diff options
Diffstat (limited to 'common/recipes-kernel/linux/linux-yocto-4.14.71/0556-drm-amd-display-fix-dcn-pipe-reset-sequence.patch')
-rw-r--r-- | common/recipes-kernel/linux/linux-yocto-4.14.71/0556-drm-amd-display-fix-dcn-pipe-reset-sequence.patch | 819 |
1 files changed, 819 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/linux-yocto-4.14.71/0556-drm-amd-display-fix-dcn-pipe-reset-sequence.patch b/common/recipes-kernel/linux/linux-yocto-4.14.71/0556-drm-amd-display-fix-dcn-pipe-reset-sequence.patch new file mode 100644 index 00000000..3ead018a --- /dev/null +++ b/common/recipes-kernel/linux/linux-yocto-4.14.71/0556-drm-amd-display-fix-dcn-pipe-reset-sequence.patch @@ -0,0 +1,819 @@ +From 14d47cae2bff887e9999c4e1824abe8692f2065b Mon Sep 17 00:00:00 2001 +From: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Date: Wed, 14 Jun 2017 18:58:04 -0400 +Subject: [PATCH 0556/4131] drm/amd/display: fix dcn pipe reset sequence + +This change fixes dcn10 front end reset sequence. Previously we +would reset front end during flip which led to issues +in certain MPO and 4k/5k scenarios. We would also never properly +power gate our front end. + +Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com> +Reviewed-by: Charlene Liu <Charlene.Liu@amd.com> +Acked-by: Harry Wentland <Harry.Wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + .../drm/amd/display/amdgpu_dm/amdgpu_dm_types.c | 2 +- + drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c | 19 +- + drivers/gpu/drm/amd/display/dc/core/dc.c | 22 +- + drivers/gpu/drm/amd/display/dc/core/dc_resource.c | 7 + + drivers/gpu/drm/amd/display/dc/dc.h | 3 - + .../amd/display/dc/dce110/dce110_hw_sequencer.c | 17 +- + .../drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c | 226 ++++++++++----------- + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c | 17 +- + drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h | 4 +- + .../amd/display/dc/dcn10/dcn10_timing_generator.c | 6 +- + .../amd/display/dc/dcn10/dcn10_timing_generator.h | 4 + + drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h | 1 + + drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h | 2 +- + 13 files changed, 155 insertions(+), 175 deletions(-) + +diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c +index abbf575..6054c2f 100644 +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_types.c +@@ -2525,7 +2525,7 @@ static void amdgpu_dm_do_flip( + surface_updates->flip_addr = &addr; + + +- dc_update_surfaces_for_stream(adev->dm.dc, surface_updates, 1, acrtc->stream); ++ dc_update_surfaces_and_stream(adev->dm.dc, surface_updates, 1, acrtc->stream, NULL); + + DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n", + __func__, +diff --git a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +index 3ec702f..00961bc 100644 +--- a/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c ++++ b/drivers/gpu/drm/amd/display/dc/calcs/dcn_calcs.c +@@ -511,12 +511,14 @@ static void split_stream_across_pipes( + struct pipe_ctx *primary_pipe, + struct pipe_ctx *secondary_pipe) + { ++ int pipe_idx = secondary_pipe->pipe_idx; ++ + if (!primary_pipe->surface) + return; + +- secondary_pipe->stream = primary_pipe->stream; +- secondary_pipe->tg = primary_pipe->tg; ++ *secondary_pipe = *primary_pipe; + ++ secondary_pipe->pipe_idx = pipe_idx; + secondary_pipe->mpcc = pool->mpcc[secondary_pipe->pipe_idx]; + secondary_pipe->mi = pool->mis[secondary_pipe->pipe_idx]; + secondary_pipe->ipp = pool->ipps[secondary_pipe->pipe_idx]; +@@ -528,8 +530,6 @@ static void split_stream_across_pipes( + } + primary_pipe->bottom_pipe = secondary_pipe; + secondary_pipe->top_pipe = primary_pipe; +- secondary_pipe->surface = primary_pipe->surface; +- secondary_pipe->pipe_dlg_param = primary_pipe->pipe_dlg_param; + + resource_build_scaling_params(primary_pipe); + resource_build_scaling_params(secondary_pipe); +@@ -1011,10 +1011,13 @@ bool dcn_validate_bandwidth( + dcn_bw_calc_rq_dlg_ttu(dc, v, hsplit_pipe); + } else if (hsplit_pipe && hsplit_pipe->surface == pipe->surface) { + /* merge previously split pipe */ +- if (pipe->bottom_pipe->bottom_pipe) +- pipe->bottom_pipe->bottom_pipe->top_pipe = pipe; +- memset(pipe->bottom_pipe, 0, sizeof(*pipe->bottom_pipe)); +- pipe->bottom_pipe = pipe->bottom_pipe->bottom_pipe; ++ pipe->bottom_pipe = hsplit_pipe->bottom_pipe; ++ if (hsplit_pipe->bottom_pipe) ++ hsplit_pipe->bottom_pipe->top_pipe = pipe; ++ hsplit_pipe->surface = NULL; ++ hsplit_pipe->stream = NULL; ++ hsplit_pipe->top_pipe = NULL; ++ hsplit_pipe->bottom_pipe = NULL; + resource_build_scaling_params(pipe); + } + /* for now important to do this after pipe split for building e2e params */ +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc.c b/drivers/gpu/drm/amd/display/dc/core/dc.c +index 18fde50..2f481ef 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc.c +@@ -963,11 +963,8 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc) + + for (i = 0; i < core_dc->res_pool->pipe_count; i++) + if (context->res_ctx.pipe_ctx[i].stream == NULL +- || context->res_ctx.pipe_ctx[i].surface == NULL) { +- context->res_ctx.pipe_ctx[i].pipe_idx = i; +- core_dc->hwss.power_down_front_end( +- core_dc, &context->res_ctx.pipe_ctx[i]); +- } ++ || context->res_ctx.pipe_ctx[i].surface == NULL) ++ core_dc->hwss.power_down_front_end(core_dc, i); + + /* 3rd param should be true, temp w/a for RV*/ + #if defined(CONFIG_DRM_AMD_DC_DCN1_0) +@@ -989,7 +986,6 @@ bool dc_commit_surfaces_to_stream( + struct dc_plane_info plane_info[MAX_SURFACES]; + struct dc_scaling_info scaling_info[MAX_SURFACES]; + int i; +- bool ret; + struct dc_stream_update *stream_update = + dm_alloc(sizeof(struct dc_stream_update)); + +@@ -1038,10 +1034,10 @@ bool dc_commit_surfaces_to_stream( + new_surface_count, + dc_stream, stream_update); + +- ret = dc_post_update_surfaces_to_stream(dc); ++ dc_post_update_surfaces_to_stream(dc); + + dm_free(stream_update); +- return ret; ++ return true; + } + + static bool is_surface_in_context( +@@ -1217,14 +1213,6 @@ enum surface_update_type dc_check_update_surfaces_for_stream( + return overall_type; + } + +-void dc_update_surfaces_for_stream(struct dc *dc, +- struct dc_surface_update *surface_updates, int surface_count, +- const struct dc_stream *dc_stream) +-{ +- dc_update_surfaces_and_stream(dc, surface_updates, surface_count, +- dc_stream, NULL); +-} +- + enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL; + + void dc_update_surfaces_and_stream(struct dc *dc, +@@ -1401,7 +1389,7 @@ void dc_update_surfaces_and_stream(struct dc *dc, + } + } + +- if (!surface_count) /* reset */ ++ if (surface_count == 0) + core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context); + + /* Lock pipes for provided surfaces, or all active if full update*/ +diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +index 9aff47e..04579d0 100644 +--- a/drivers/gpu/drm/amd/display/dc/core/dc_resource.c ++++ b/drivers/gpu/drm/amd/display/dc/core/dc_resource.c +@@ -1096,6 +1096,10 @@ bool resource_attach_surfaces_to_context( + free_pipe->surface = surface; + + if (tail_pipe) { ++ free_pipe->tg = tail_pipe->tg; ++ free_pipe->stream_enc = tail_pipe->stream_enc; ++ free_pipe->audio = tail_pipe->audio; ++ free_pipe->clock_source = tail_pipe->clock_source; + free_pipe->top_pipe = tail_pipe; + tail_pipe->bottom_pipe = free_pipe; + } +@@ -2300,6 +2304,9 @@ bool pipe_need_reprogram( + struct pipe_ctx *pipe_ctx_old, + struct pipe_ctx *pipe_ctx) + { ++ if (!pipe_ctx_old->stream) ++ return false; ++ + if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink) + return true; + +diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h +index cb70b6d..18f6858 100644 +--- a/drivers/gpu/drm/amd/display/dc/dc.h ++++ b/drivers/gpu/drm/amd/display/dc/dc.h +@@ -415,9 +415,6 @@ bool dc_commit_surfaces_to_stream( + bool dc_post_update_surfaces_to_stream( + struct dc *dc); + +-void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *updates, +- int surface_count, const struct dc_stream *stream); +- + /* Surface update type is used by dc_update_surfaces_and_stream + * The update type is determined at the very beginning of the function based + * on parameters passed in and decides how much programming (or updating) is +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 0bab85b..fd1cb7f 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 +@@ -1185,8 +1185,7 @@ static void disable_vga_and_power_gate_all_controllers( + enable_display_pipe_clock_gating(ctx, + true); + +- dc->hwss.power_down_front_end( +- dc, &dc->current_context->res_ctx.pipe_ctx[i]); ++ dc->hwss.power_down_front_end(dc, i); + } + } + +@@ -1340,7 +1339,7 @@ static void reset_single_pipe_hw_ctx( + resource_unreference_clock_source(&context->res_ctx, dc->res_pool, + &pipe_ctx->clock_source); + +- dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx); ++ dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx->pipe_idx); + + pipe_ctx->stream = NULL; + } +@@ -2538,17 +2537,17 @@ static void dce110_apply_ctx_for_surface( + } + } + +-static void dce110_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe) ++static void dce110_power_down_fe(struct core_dc *dc, int fe_idx) + { + /* Do not power down fe when stream is active on dce*/ +- if (pipe->stream) ++ if (dc->current_context->res_ctx.pipe_ctx[fe_idx].stream) + return; + + dc->hwss.enable_display_power_gating( +- dc, pipe->pipe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE); +- if (pipe->xfm) +- pipe->xfm->funcs->transform_reset(pipe->xfm); +- memset(&pipe->scl_data, 0, sizeof(struct scaler_data)); ++ dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE); ++ ++ dc->res_pool->transforms[fe_idx]->funcs->transform_reset( ++ dc->res_pool->transforms[fe_idx]); + } + + static const struct hw_sequencer_funcs dce110_funcs = { +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 edcd736..d0bddfd 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 +@@ -116,18 +116,6 @@ static const struct dcn10_hwseq_reg_offsets reg_offsets[] = { + HWSEQ_REG_SET_N(reg, 1, FD(reg##__##field), val) + + /* TODO should be moved to OTG */ +-static void lock_otg_master_update( +- struct dc_context *ctx, +- uint8_t inst) +-{ +- uint32_t inst_offset = reg_offsets[inst].otg; +- +- HWSEQ_REG_UPDATE(OTG0_OTG_GLOBAL_CONTROL0, +- OTG_MASTER_UPDATE_LOCK_SEL, inst); +- +- HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK, +- OTG_MASTER_UPDATE_LOCK, 1); +-} + + static bool unlock_master_tg_and_wait( + struct dc_context *ctx, +@@ -148,19 +136,6 @@ static bool unlock_master_tg_and_wait( + return true; + } + +-/* TODO: should be moved to OTG ? */ +-static void unlock_otg_master( +- struct dc_context *ctx, +- uint8_t inst) +-{ +- uint32_t inst_offset = reg_offsets[inst].otg; +- +- /* unlock master locker */ +- HWSEQ_REG_UPDATE(OTG0_OTG_MASTER_UPDATE_LOCK, +- OTG_MASTER_UPDATE_LOCK, 0); +-} +- +- + static void wait_no_outstanding_request( + struct dc_context *ctx, + uint8_t plane_id) +@@ -489,8 +464,7 @@ static void hubp_pg_control( + + static void power_on_plane( + struct dc_context *ctx, +- uint8_t plane_id, +- uint8_t inst) ++ int plane_id) + { + uint32_t inst_offset = 0; + +@@ -500,6 +474,8 @@ static void power_on_plane( + hubp_pg_control(ctx, plane_id, true); + HWSEQ_REG_SET(DC_IP_REQUEST_CNTL, + IP_REQUEST_EN, 0); ++ dm_logger_write(ctx->logger, LOG_DC, ++ "Un-gated front end for pipe %d\n", plane_id); + } + + /* fully check bios enabledisplaypowergating table. dal only need dce init +@@ -596,13 +572,13 @@ static void init_hw(struct core_dc *dc) + dc->res_pool->mpcc[i]; + struct mpcc_cfg mpcc_cfg; + +- lock_otg_master_update(dc->ctx, tg->inst); ++ tg->funcs->lock(tg); + mpcc_cfg.opp_id = 0xf; + mpcc_cfg.top_dpp_id = 0xf; + mpcc_cfg.bot_mpcc_id = 0xf; + mpcc_cfg.top_of_tree = true; + mpcc->funcs->set(mpcc, &mpcc_cfg); +- unlock_otg_master(dc->ctx, tg->inst); ++ tg->funcs->unlock(tg); + + tg->funcs->disable_vga(tg); + /* Blank controller using driver code instead of +@@ -822,56 +798,85 @@ static void reset_back_end_for_pipe( + return; + + pipe_ctx->stream = NULL; ++ dm_logger_write(dc->ctx->logger, LOG_DC, ++ "Reset back end for pipe %d, tg:%d\n", ++ pipe_ctx->pipe_idx, pipe_ctx->tg->inst); + } + +-static void reset_front_end_for_pipe( ++static void reset_front_end( + struct core_dc *dc, +- struct pipe_ctx *pipe_ctx, +- struct validate_context *context) ++ int fe_idx) + { + struct mpcc_cfg mpcc_cfg; ++ struct mem_input *mi = dc->res_pool->mis[fe_idx]; ++ struct transform *xfm = dc->res_pool->transforms[fe_idx]; ++ struct mpcc *mpcc = dc->res_pool->mpcc[fe_idx]; ++ struct timing_generator *tg = dc->res_pool->timing_generators[mpcc->opp_id]; + +- if (!pipe_ctx->surface) ++ /*Already reset*/ ++ if (mpcc->opp_id == 0xf) + return; + +- pipe_ctx->mi->funcs->dcc_control(pipe_ctx->mi, false, false); +- +- lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst); ++ mi->funcs->dcc_control(mi, false, false); ++ tg->funcs->lock(tg); + + mpcc_cfg.opp_id = 0xf; + mpcc_cfg.top_dpp_id = 0xf; + mpcc_cfg.bot_mpcc_id = 0xf; +- mpcc_cfg.top_of_tree = !pipe_ctx->top_pipe; +- pipe_ctx->mpcc->funcs->set(pipe_ctx->mpcc, &mpcc_cfg); +- +- pipe_ctx->top_pipe = NULL; +- pipe_ctx->bottom_pipe = NULL; ++ mpcc_cfg.top_of_tree = tg->inst == mpcc->inst; ++ mpcc->funcs->set(mpcc, &mpcc_cfg); + +- unlock_master_tg_and_wait(dc->ctx, pipe_ctx->tg->inst); ++ unlock_master_tg_and_wait(dc->ctx, tg->inst); ++ mpcc->funcs->wait_for_idle(mpcc); ++ mi->funcs->set_blank(mi, true); ++ wait_no_outstanding_request(dc->ctx, fe_idx); ++ disable_clocks(dc->ctx, fe_idx); + +- pipe_ctx->mi->funcs->set_blank(pipe_ctx->mi, true); ++ xfm->funcs->transform_reset(xfm); + +- wait_no_outstanding_request(dc->ctx, pipe_ctx->pipe_idx); ++ dm_logger_write(dc->ctx->logger, LOG_DC, ++ "Reset front end %d\n", ++ fe_idx); ++} + +- disable_clocks(dc->ctx, pipe_ctx->pipe_idx); ++static void dcn10_power_down_fe(struct core_dc *dc, int fe_idx) ++{ ++ struct dc_context *ctx = dc->ctx; ++ uint32_t inst_offset = 0; + +- pipe_ctx->xfm->funcs->transform_reset(pipe_ctx->xfm); ++ reset_front_end(dc, fe_idx); + ++ HWSEQ_REG_SET(DC_IP_REQUEST_CNTL, ++ IP_REQUEST_EN, 1); ++ dpp_pg_control(ctx, fe_idx, false); ++ hubp_pg_control(ctx, fe_idx, false); ++ HWSEQ_REG_SET(DC_IP_REQUEST_CNTL, ++ IP_REQUEST_EN, 0); + dm_logger_write(dc->ctx->logger, LOG_DC, +- "Reset front end for pipe %d\n", +- pipe_ctx->pipe_idx); +- +- pipe_ctx->surface = NULL; ++ "Power gated front end %d\n", fe_idx); + } + +-static void reset_hw_ctx(struct core_dc *dc, +- struct validate_context *context, +- void (*reset)(struct core_dc *dc, +- struct pipe_ctx *pipe_ctx, +- struct validate_context *context)) ++static void reset_hw_ctx_wrap( ++ struct core_dc *dc, ++ struct validate_context *context) + { + int i; + ++ /* Reset Front End*/ ++ for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { ++ struct pipe_ctx *pipe_ctx_old = ++ &dc->current_context->res_ctx.pipe_ctx[i]; ++ struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; ++ ++ /*if (!pipe_ctx_old->stream) ++ continue;*/ ++ ++ if (!pipe_ctx->stream || !pipe_ctx->surface) ++ dcn10_power_down_fe(dc, i); ++ else if (pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) ++ reset_front_end(dc, i); ++ } ++ /* Reset Back End*/ + for (i = dc->res_pool->pipe_count - 1; i >= 0 ; i--) { + struct pipe_ctx *pipe_ctx_old = + &dc->current_context->res_ctx.pipe_ctx[i]; +@@ -882,23 +887,13 @@ static void reset_hw_ctx(struct core_dc *dc, + + if (!pipe_ctx->stream || + pipe_need_reprogram(pipe_ctx_old, pipe_ctx)) +- reset(dc, pipe_ctx_old, dc->current_context); ++ reset_back_end_for_pipe(dc, pipe_ctx_old, dc->current_context); + } + } + +-static void reset_hw_ctx_wrap( +- struct core_dc *dc, +- struct validate_context *context) +-{ +- /* Reset Front End*/ +- reset_hw_ctx(dc, context, reset_front_end_for_pipe); +- /* Reset Back End*/ +- reset_hw_ctx(dc, context, reset_back_end_for_pipe); +-} +- + +-static bool patch_address_for_sbs_tb_stereo(struct pipe_ctx *pipe_ctx, +- PHYSICAL_ADDRESS_LOC *addr) ++static bool patch_address_for_sbs_tb_stereo( ++ struct pipe_ctx *pipe_ctx, PHYSICAL_ADDRESS_LOC *addr) + { + struct core_surface *surface = pipe_ctx->surface; + bool sec_split = pipe_ctx->top_pipe && +@@ -936,8 +931,7 @@ static void update_plane_addr(const struct core_dc *dc, struct pipe_ctx *pipe_ct + } + + static bool dcn10_set_input_transfer_func( +- struct pipe_ctx *pipe_ctx, +- const struct core_surface *surface) ++ struct pipe_ctx *pipe_ctx, const struct core_surface *surface) + { + struct input_pixel_processor *ipp = pipe_ctx->ipp; + const struct core_transfer_func *tf = NULL; +@@ -950,8 +944,8 @@ static bool dcn10_set_input_transfer_func( + tf = DC_TRANSFER_FUNC_TO_CORE(surface->public.in_transfer_func); + + if (surface->public.gamma_correction && dce_use_lut(surface)) +- ipp->funcs->ipp_program_input_lut(ipp, +- surface->public.gamma_correction); ++ ipp->funcs->ipp_program_input_lut(ipp, ++ surface->public.gamma_correction); + + if (tf == NULL) + ipp->funcs->ipp_set_degamma(ipp, IPP_DEGAMMA_MODE_BYPASS); +@@ -1333,8 +1327,6 @@ static void dcn10_pipe_control_lock( + struct pipe_ctx *pipe, + bool lock) + { +- struct dce_hwseq *hws = hws = dc->hwseq; +- + /* use TG master update lock to lock everything on the TG + * therefore only top pipe need to lock + */ +@@ -1342,9 +1334,9 @@ static void dcn10_pipe_control_lock( + return; + + if (lock) +- dcn10_lock(pipe->tg); ++ pipe->tg->funcs->lock(pipe->tg); + else +- dcn10_unlock(pipe->tg); ++ pipe->tg->funcs->unlock(pipe->tg); + } + + static bool wait_for_reset_trigger_to_occur( +@@ -1543,7 +1535,7 @@ static void dcn10_power_on_fe( + struct dc_surface *dc_surface = &pipe_ctx->surface->public; + + power_on_plane(dc->ctx, +- pipe_ctx->pipe_idx, pipe_ctx->tg->inst); ++ pipe_ctx->pipe_idx); + + /* enable DCFCLK current DCHUB */ + enable_dcfclk(dc->ctx, +@@ -1694,7 +1686,6 @@ static void update_dchubp_dpp( + struct default_adjustment ocsc = {0}; + struct tg_color black_color = {0}; + struct mpcc_cfg mpcc_cfg; +- struct pipe_ctx *top_pipe; + bool per_pixel_alpha = surface->public.per_pixel_alpha && pipe_ctx->bottom_pipe; + + /* TODO: proper fix once fpga works */ +@@ -1734,14 +1725,13 @@ static void update_dchubp_dpp( + IPP_OUTPUT_FORMAT_12_BIT_FIX); + + pipe_ctx->scl_data.lb_params.alpha_en = per_pixel_alpha; +- for (top_pipe = pipe_ctx; top_pipe != NULL; top_pipe = top_pipe->top_pipe) +- mpcc_cfg.opp_id = top_pipe->opp->inst; + mpcc_cfg.top_dpp_id = pipe_ctx->pipe_idx; + if (pipe_ctx->bottom_pipe) + mpcc_cfg.bot_mpcc_id = pipe_ctx->bottom_pipe->mpcc->inst; + else + mpcc_cfg.bot_mpcc_id = 0xf; +- mpcc_cfg.top_of_tree = !pipe_ctx->top_pipe; ++ mpcc_cfg.opp_id = pipe_ctx->tg->inst; ++ mpcc_cfg.top_of_tree = pipe_ctx->pipe_idx == pipe_ctx->tg->inst; + mpcc_cfg.per_pixel_alpha = per_pixel_alpha; + /* DCN1.0 has output CM before MPC which seems to screw with + * pre-multiplied alpha. +@@ -1749,8 +1739,6 @@ static void update_dchubp_dpp( + mpcc_cfg.pre_multiplied_alpha = is_rgb_cspace( + pipe_ctx->stream->public.output_color_space) + && per_pixel_alpha; +- if (!dc->current_context->res_ctx.pipe_ctx[pipe_ctx->pipe_idx].surface) +- pipe_ctx->mpcc->funcs->wait_for_idle(pipe_ctx->mpcc); + pipe_ctx->mpcc->funcs->set(pipe_ctx->mpcc, &mpcc_cfg); + + color_space_to_black_color( +@@ -1796,7 +1784,7 @@ static void program_all_pipe_in_tree( + /* watermark is for all pipes */ + pipe_ctx->mi->funcs->program_watermarks( + pipe_ctx->mi, &context->bw.dcn.watermarks, ref_clk_mhz); +- lock_otg_master_update(dc->ctx, pipe_ctx->tg->inst); ++ pipe_ctx->tg->funcs->lock(pipe_ctx->tg); + + pipe_ctx->tg->dlg_otg_param.vready_offset = pipe_ctx->pipe_dlg_param.vready_offset; + pipe_ctx->tg->dlg_otg_param.vstartup_start = pipe_ctx->pipe_dlg_param.vstartup_start; +@@ -1852,13 +1840,41 @@ static void dcn10_apply_ctx_for_surface( + { + int i; + ++ /* reset 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_context->res_ctx.pipe_ctx[i]; ++ ++ if ((!pipe_ctx->surface && old_pipe_ctx->surface) ++ || (!pipe_ctx->stream && old_pipe_ctx->stream)) { ++ struct mpcc_cfg mpcc_cfg; ++ ++ mpcc_cfg.opp_id = 0xf; ++ mpcc_cfg.top_dpp_id = 0xf; ++ mpcc_cfg.bot_mpcc_id = 0xf; ++ mpcc_cfg.top_of_tree = !old_pipe_ctx->top_pipe; ++ old_pipe_ctx->mpcc->funcs->set(old_pipe_ctx->mpcc, &mpcc_cfg); ++ ++ old_pipe_ctx->top_pipe = NULL; ++ old_pipe_ctx->bottom_pipe = NULL; ++ old_pipe_ctx->surface = NULL; ++ ++ dm_logger_write(dc->ctx->logger, LOG_DC, ++ "Reset mpcc for pipe %d\n", ++ old_pipe_ctx->pipe_idx); ++ } ++ }*/ ++ ++ if (!surface) ++ return; ++ + for (i = 0; i < dc->res_pool->pipe_count; i++) { + struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; + +- if (!pipe_ctx->surface || pipe_ctx->surface != surface) ++ if (pipe_ctx->surface != surface) + continue; + +- + /* looking for top pipe to program */ + if (!pipe_ctx->top_pipe) + program_all_pipe_in_tree(dc, pipe_ctx, context); +@@ -1910,27 +1926,6 @@ static void dcn10_apply_ctx_for_surface( + context->bw.dcn.watermarks.d.cstate_pstate.pstate_change_ns, + context->bw.dcn.watermarks.d.pte_meta_urgent_ns + ); +- +- for (i = 0; i < dc->res_pool->pipe_count; i++) { +- struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; +- +- if (!pipe_ctx->surface || pipe_ctx->top_pipe) +- continue; +- +- /* unlock master update lock */ +- unlock_otg_master(dc->ctx, pipe_ctx->tg->inst); +- } +- +- /* reset unused pipe */ +- 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_context->res_ctx.pipe_ctx[i]; +- +- if ((!pipe_ctx->surface && old_pipe_ctx->surface) +- || (!pipe_ctx->stream && old_pipe_ctx->stream)) +- reset_front_end_for_pipe(dc, old_pipe_ctx, dc->current_context); +- } + } + + static void dcn10_set_bandwidth( +@@ -1992,23 +1987,6 @@ static void dcn10_set_bandwidth( + dcn10_pplib_apply_display_requirements(dc, context); + } + +-static void dcn10_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe) +-{ +- struct dc_context *ctx = dc->ctx; +- uint32_t inst_offset = 0; +- +- HWSEQ_REG_SET(DC_IP_REQUEST_CNTL, +- IP_REQUEST_EN, 1); +- dpp_pg_control(ctx, pipe->pipe_idx, false); +- hubp_pg_control(ctx, pipe->pipe_idx, false); +- HWSEQ_REG_SET(DC_IP_REQUEST_CNTL, +- IP_REQUEST_EN, 0); +- +- if (pipe->xfm) +- pipe->xfm->funcs->transform_reset(pipe->xfm); +- memset(&pipe->scl_data, 0, sizeof(pipe->scl_data)); +-} +- + static void set_drr(struct pipe_ctx **pipe_ctx, + int num_pipes, int vmin, int vmax) + { +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +index b1c590d..7af04bc 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.c +@@ -65,17 +65,17 @@ void dcn10_mpcc_set_bg_color( + + static void set_output_mux(struct dcn10_mpcc *mpcc10, int opp_id, int mpcc_id) + { +- ASSERT(mpcc10->opp_id == 0xf || opp_id == mpcc10->opp_id); +- mpcc10->opp_id = opp_id; ++ ASSERT(mpcc10->base.opp_id == 0xf || opp_id == mpcc10->base.opp_id); ++ mpcc10->base.opp_id = opp_id; + REG_UPDATE(OPP_PIPE_CONTROL[opp_id], OPP_PIPE_CLOCK_EN, 1); + REG_SET(MUX[opp_id], 0, MPC_OUT_MUX, mpcc_id); + } + + static void reset_output_mux(struct dcn10_mpcc *mpcc10) + { +- REG_SET(MUX[mpcc10->opp_id], 0, MPC_OUT_MUX, 0xf); +- REG_UPDATE(OPP_PIPE_CONTROL[mpcc10->opp_id], OPP_PIPE_CLOCK_EN, 0); +- mpcc10->opp_id = 0xf; ++ REG_SET(MUX[mpcc10->base.opp_id], 0, MPC_OUT_MUX, 0xf); ++ REG_UPDATE(OPP_PIPE_CONTROL[mpcc10->base.opp_id], OPP_PIPE_CLOCK_EN, 0); ++ mpcc10->base.opp_id = 0xf; + } + + static void dcn10_mpcc_set(struct mpcc *mpcc, struct mpcc_cfg *cfg) +@@ -104,16 +104,17 @@ static void dcn10_mpcc_set(struct mpcc *mpcc, struct mpcc_cfg *cfg) + if (cfg->top_of_tree) { + if (cfg->opp_id != 0xf) + set_output_mux(mpcc10, cfg->opp_id, mpcc->inst); +- else ++ else if (mpcc->opp_id != 0xf) + reset_output_mux(mpcc10); + } ++ mpcc10->base.opp_id = cfg->opp_id; + } + + static void dcn10_mpcc_wait_idle(struct mpcc *mpcc) + { + struct dcn10_mpcc *mpcc10 = TO_DCN10_MPCC(mpcc); + +- REG_WAIT(MPCC_STATUS, MPCC_IDLE, 1, 1000, 1000); ++ REG_WAIT(MPCC_STATUS, MPCC_BUSY, 0, 1000, 1000); + } + + +@@ -139,5 +140,5 @@ void dcn10_mpcc_construct(struct dcn10_mpcc *mpcc10, + mpcc10->mpcc_shift = mpcc_shift; + mpcc10->mpcc_mask = mpcc_mask; + +- mpcc10->opp_id = inst; ++ mpcc10->base.opp_id = inst; + } +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h +index 0f9f1b9..fff2674 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_mpc.h +@@ -68,6 +68,7 @@ struct dcn_mpcc_registers { + SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_MULTIPLIED_MODE, mask_sh),\ + SF(MPCC0_MPCC_CONTROL, MPCC_BLND_ACTIVE_OVERLAP_ONLY, mask_sh),\ + SF(MPCC0_MPCC_STATUS, MPCC_IDLE, mask_sh),\ ++ SF(MPCC0_MPCC_STATUS, MPCC_BUSY, mask_sh),\ + SF(MPCC0_MPCC_OPP_ID, MPCC_OPP_ID, mask_sh),\ + SF(MPCC0_MPCC_BG_G_Y, MPCC_BG_G_Y, mask_sh),\ + SF(MPCC0_MPCC_BG_R_CR, MPCC_BG_R_CR, mask_sh),\ +@@ -83,6 +84,7 @@ struct dcn_mpcc_registers { + type MPCC_ALPHA_MULTIPLIED_MODE;\ + type MPCC_BLND_ACTIVE_OVERLAP_ONLY;\ + type MPCC_IDLE;\ ++ type MPCC_BUSY;\ + type MPCC_OPP_ID;\ + type MPCC_BG_G_Y;\ + type MPCC_BG_R_CR;\ +@@ -103,8 +105,6 @@ struct dcn10_mpcc { + const struct dcn_mpcc_registers *mpcc_regs; + const struct dcn_mpcc_shift *mpcc_shift; + const struct dcn_mpcc_mask *mpcc_mask; +- +- int opp_id; + }; + + void dcn10_mpcc_construct(struct dcn10_mpcc *mpcc10, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c +index 58fb29f..802ace2 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.c +@@ -575,6 +575,8 @@ void dcn10_lock(struct timing_generator *tg) + { + struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg); + ++ REG_SET(OTG_GLOBAL_CONTROL0, 0, ++ OTG_MASTER_UPDATE_LOCK_SEL, tg->inst); + REG_SET(OTG_MASTER_UPDATE_LOCK, 0, + OTG_MASTER_UPDATE_LOCK, 1); + } +@@ -587,9 +589,9 @@ void dcn10_unlock(struct timing_generator *tg) + OTG_MASTER_UPDATE_LOCK, 0); + + /* why are we waiting here? */ +- REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, ++ /*REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL, + OTG_UPDATE_PENDING, 0, +- 20000, 200000); ++ 20000, 200000);*/ + } + + static void dcn10_get_position(struct timing_generator *tg, +diff --git a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h +index c880fa5..3b2a20a 100644 +--- a/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h ++++ b/drivers/gpu/drm/amd/display/dc/dcn10/dcn10_timing_generator.h +@@ -37,6 +37,7 @@ + SRI(OTG_VREADY_PARAM, OTG, inst),\ + SRI(OTG_BLANK_CONTROL, OTG, inst),\ + SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\ ++ SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\ + SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\ + SRI(OTG_H_TOTAL, OTG, inst),\ + SRI(OTG_H_BLANK_START_END, OTG, inst),\ +@@ -83,6 +84,7 @@ struct dcn_tg_registers { + uint32_t OTG_VREADY_PARAM; + uint32_t OTG_BLANK_CONTROL; + uint32_t OTG_MASTER_UPDATE_LOCK; ++ uint32_t OTG_GLOBAL_CONTROL0; + uint32_t OTG_DOUBLE_BUFFER_CONTROL; + uint32_t OTG_H_TOTAL; + uint32_t OTG_H_BLANK_START_END; +@@ -134,6 +136,7 @@ struct dcn_tg_registers { + SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DE_MODE, mask_sh),\ + SF(OTG0_OTG_BLANK_CONTROL, OTG_CURRENT_BLANK_STATE, mask_sh),\ + SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\ ++ SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\ + SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\ + SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\ +@@ -224,6 +227,7 @@ struct dcn_tg_registers { + type OTG_CURRENT_BLANK_STATE;\ + type OTG_MASTER_UPDATE_LOCK;\ + type OTG_UPDATE_PENDING;\ ++ type OTG_MASTER_UPDATE_LOCK_SEL;\ + type OTG_BLANK_DATA_DOUBLE_BUFFER_EN;\ + type OTG_H_TOTAL;\ + type OTG_H_BLANK_START;\ +diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +index 51bc8ef..55c9c30 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw/mpc.h +@@ -40,6 +40,7 @@ struct mpcc { + const struct mpcc_funcs *funcs; + struct dc_context *ctx; + int inst; ++ int opp_id; + }; + + struct mpcc_funcs { +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 5288481..642ae5e 100644 +--- a/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h ++++ b/drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h +@@ -105,7 +105,7 @@ struct hw_sequencer_funcs { + struct dc_bios *dcb, + enum pipe_gating_control power_gating); + +- void (*power_down_front_end)(struct core_dc *dc, struct pipe_ctx *pipe); ++ void (*power_down_front_end)(struct core_dc *dc, int fe_idx); + + void (*power_on_front_end)(struct core_dc *dc, + struct pipe_ctx *pipe, +-- +2.7.4 + |