drm/amd/display: Turn on phantom OTG before disabling phantom pipe
authorAlvin Lee <Alvin.Lee2@amd.com>
Thu, 8 Dec 2022 01:19:49 +0000 (20:19 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 3 Jan 2023 21:57:44 +0000 (16:57 -0500)
[Description]
- Proper phantom pipe disable sequence was missing in
  commit_planes_for_stream
- If disabling phantom pipe, turn on phantom OTG first, and turn
  off the phantom OTG after the plane is disabled
- Also update sequence for enabling / disabling phantom streams
  (apply_ctx_to_hw). When enabling phantom pipes, enable before
  doing front end programming for phantom pipes. If disabling
  phantom pipes, disable after front end programming (i.e. after
  phantom plane disable)
- TODO: Still need to properly handle transition case when a phantom
  pipe is transitioned directly into a real pipe (need to fully disable
  the phantom pipe first)

Acked-by: Aurabindo Pillai <aurabindo.pillai@amd.com>
Signed-off-by: Alvin Lee <Alvin.Lee2@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.h
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_init.c
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer.h

index e265faff4c3d0104d8691c70370caead25669c98..f41933845d2a17504c0c91a671fcc138cb0d66e8 100644 (file)
@@ -3326,6 +3326,7 @@ static void commit_planes_for_stream(struct dc *dc,
        struct pipe_ctx *top_pipe_to_program = NULL;
        bool should_lock_all_pipes = (update_type != UPDATE_TYPE_FAST);
        bool subvp_prev_use = false;
+       bool subvp_curr_use = false;
 
        // Once we apply the new subvp context to hardware it won't be in the
        // dc->current_state anymore, so we have to cache it before we apply
@@ -3382,6 +3383,15 @@ static void commit_planes_for_stream(struct dc *dc,
                        break;
        }
 
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+                       subvp_curr_use = true;
+                       break;
+               }
+       }
+
        if (stream->test_pattern.type != DP_TEST_PATTERN_VIDEO_MODE) {
                struct pipe_ctx *mpcc_pipe;
                struct pipe_ctx *odm_pipe;
@@ -3653,42 +3663,22 @@ static void commit_planes_for_stream(struct dc *dc,
                                        top_pipe_to_program->stream_res.tg);
                }
 
-       /* For phantom pipe OTG enable, it has to be done after any previous pipe
-        * that was in use has already been programmed at gotten its double buffer
-        * update for "disable".
-        */
-       if (update_type != UPDATE_TYPE_FAST) {
-               for (i = 0; i < dc->res_pool->pipe_count; i++) {
-                       struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
-                       struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-
-                       /* If an active, non-phantom pipe is being transitioned into a phantom
-                        * pipe, wait for the double buffer update to complete first before we do
-                        * ANY phantom pipe programming.
-                        */
-                       if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
-                                       old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
-                               old_pipe->stream_res.tg->funcs->wait_for_state(
-                                               old_pipe->stream_res.tg,
-                                               CRTC_STATE_VBLANK);
-                               old_pipe->stream_res.tg->funcs->wait_for_state(
-                                               old_pipe->stream_res.tg,
-                                               CRTC_STATE_VACTIVE);
-                       }
+       if (subvp_curr_use) {
+               /* If enabling subvp or transitioning from subvp->subvp, enable the
+                * phantom streams before we program front end for the phantom pipes.
+                */
+               if (update_type != UPDATE_TYPE_FAST) {
+                       if (dc->hwss.enable_phantom_streams)
+                               dc->hwss.enable_phantom_streams(dc, context);
                }
-               for (i = 0; i < dc->res_pool->pipe_count; i++) {
-                       struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
+       }
 
-                       if ((new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) ||
-                                       subvp_prev_use) {
-                               // If old context or new context has phantom pipes, apply
-                               // the phantom timings now. We can't change the phantom
-                               // pipe configuration safely without driver acquiring
-                               // the DMCUB lock first.
-                               dc->hwss.apply_ctx_to_hw(dc, context);
-                               break;
-                       }
-               }
+       if (subvp_prev_use && !subvp_curr_use) {
+               /* If disabling subvp, disable phantom streams after front end
+                * programming has completed (we turn on phantom OTG in order
+                * to complete the plane disable for phantom pipes).
+                */
+               dc->hwss.apply_ctx_to_hw(dc, context);
        }
 
        if (update_type != UPDATE_TYPE_FAST)
index 6291a241158ad6df6b9639e68feaac6791564a11..366ba05cf8ef014cb2f0b5b5e543f970e3f2e9a5 100644 (file)
@@ -582,6 +582,9 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
        if (pipe_ctx->stream_res.gsl_group != 0)
                dcn20_setup_gsl_group_as_lock(dc, pipe_ctx, false);
 
+       if (hubp->funcs->hubp_update_mall_sel)
+               hubp->funcs->hubp_update_mall_sel(hubp, 0, false);
+
        dc->hwss.set_flip_control_gsl(pipe_ctx, false);
 
        hubp->funcs->hubp_clk_cntl(hubp, false);
@@ -605,6 +608,9 @@ 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)
 {
+       bool is_phantom = pipe_ctx->plane_state && pipe_ctx->plane_state->is_phantom;
+       struct timing_generator *tg = is_phantom ? pipe_ctx->stream_res.tg : NULL;
+
        DC_LOGGER_INIT(dc->ctx->logger);
 
        if (!pipe_ctx->plane_res.hubp || pipe_ctx->plane_res.hubp->power_gated)
@@ -612,6 +618,12 @@ void dcn20_disable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx)
 
        dcn20_plane_atomic_disable(dc, pipe_ctx);
 
+       /* Turn back off the phantom OTG after the phantom plane is fully disabled
+        */
+       if (is_phantom)
+               if (tg && tg->funcs->disable_phantom_crtc)
+                       tg->funcs->disable_phantom_crtc(tg);
+
        DC_LOG_DC("Power down front end %d\n",
                                        pipe_ctx->pipe_idx);
 }
@@ -1803,6 +1815,18 @@ void dcn20_program_front_end_for_ctx(
                dcn20_detect_pipe_changes(&dc->current_state->res_ctx.pipe_ctx[i],
                                &context->res_ctx.pipe_ctx[i]);
 
+       /* When disabling phantom pipes, turn on phantom OTG first (so we can get double
+        * buffer updates properly)
+        */
+       for (i = 0; i < dc->res_pool->pipe_count; i++)
+               if (context->res_ctx.pipe_ctx[i].update_flags.bits.disable
+                               && dc->current_state->res_ctx.pipe_ctx[i].stream->mall_stream_config.type == SUBVP_PHANTOM) {
+                       struct timing_generator *tg = dc->current_state->res_ctx.pipe_ctx[i].stream_res.tg;
+
+                       if (tg->funcs->enable_crtc)
+                               tg->funcs->enable_crtc(tg);
+               }
+
        /* 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
index 2f0ebe1f6c45ba58e541bb4298631271328ed1a0..c10d8a60380a489985c0862f56eb5ee21829767d 100644 (file)
@@ -1451,3 +1451,39 @@ void dcn32_update_dsc_pg(struct dc *dc,
                }
        }
 }
+
+void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context)
+{
+       unsigned int i;
+
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
+               struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
+
+               /* If an active, non-phantom pipe is being transitioned into a phantom
+                * pipe, wait for the double buffer update to complete first before we do
+                * ANY phantom pipe programming.
+                */
+               if (pipe->stream && pipe->stream->mall_stream_config.type == SUBVP_PHANTOM &&
+                               old_pipe->stream && old_pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
+                       old_pipe->stream_res.tg->funcs->wait_for_state(
+                                       old_pipe->stream_res.tg,
+                                       CRTC_STATE_VBLANK);
+                       old_pipe->stream_res.tg->funcs->wait_for_state(
+                                       old_pipe->stream_res.tg,
+                                       CRTC_STATE_VACTIVE);
+               }
+       }
+       for (i = 0; i < dc->res_pool->pipe_count; i++) {
+               struct pipe_ctx *new_pipe = &context->res_ctx.pipe_ctx[i];
+
+               if (new_pipe->stream && new_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
+                       // If old context or new context has phantom pipes, apply
+                       // the phantom timings now. We can't change the phantom
+                       // pipe configuration safely without driver acquiring
+                       // the DMCUB lock first.
+                       dc->hwss.apply_ctx_to_hw(dc, context);
+                       break;
+               }
+       }
+}
index 7de36529cf99c616f8c6f946145d2011f4c92df7..e9e9534f36680a3d062dd3802f11781eca9c9354 100644 (file)
@@ -102,4 +102,6 @@ void dcn32_update_dsc_pg(struct dc *dc,
                struct dc_state *context,
                bool safe_to_disable);
 
+void dcn32_enable_phantom_streams(struct dc *dc, struct dc_state *context);
+
 #endif /* __DC_HWSS_DCN32_H__ */
index dc4649458567428e1c478f10092038fca55dae04..330d7cbc73988133ccd30c0563d6ef4b1f0a598a 100644 (file)
@@ -106,6 +106,7 @@ static const struct hw_sequencer_funcs dcn32_funcs = {
        .set_disp_pattern_generator = dcn30_set_disp_pattern_generator,
        .get_dcc_en_bits = dcn10_get_dcc_en_bits,
        .commit_subvp_config = dcn32_commit_subvp_config,
+       .enable_phantom_streams = dcn32_enable_phantom_streams,
        .subvp_pipe_control_lock = dcn32_subvp_pipe_control_lock,
        .update_visual_confirm_color = dcn20_update_visual_confirm_color,
        .update_phantom_vp_position = dcn32_update_phantom_vp_position,
index c43523f9ff6d0be9404f2e58553d97673e36ebe2..88ac723d10aa72340fbff0c0903cf28fa1de713e 100644 (file)
@@ -266,6 +266,7 @@ struct hw_sequencer_funcs {
        void (*apply_update_flags_for_phantom)(struct pipe_ctx *phantom_pipe);
 
        void (*commit_subvp_config)(struct dc *dc, struct dc_state *context);
+       void (*enable_phantom_streams)(struct dc *dc, struct dc_state *context);
        void (*subvp_pipe_control_lock)(struct dc *dc,
                        struct dc_state *context,
                        bool lock,