drm/amd/display: Fix 4to1 MPC black screen with DPP RCO
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Mon, 13 Mar 2023 17:23:45 +0000 (13:23 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 31 Mar 2023 15:18:54 +0000 (11:18 -0400)
[Why]
DPP Root clock optimization when combined with 4to1 MPC combine results
in the screen turning black.

This is because the DPPCLK is stopped during the middle of an
optimize_bandwidth sequence during commit_minimal_transition without
going through plane power down/power up.

[How]
The intent of a 0Hz DPP clock through update_clocks is to disable the
DTO. This differs from the behavior of stopping the DPPCLK entirely
(utilizing a 0Hz clock on some ASIC) so it's better to move this logic
to reside next to plane power up/power down where we gate the HUBP/DPP
DOMAIN.

The new  sequence should be:
Power down: PG enabled -> RCO on
Power up: RCO off -> PG disabled

Rename power_on_plane to power_on_plane_resources to reflect the
actual operation that's occurring.

Cc: stable@vger.kernel.org
Cc: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Jun Lei <Jun.Lei@amd.com>
Acked-by: Qingqing Zhuo <qingqing.zhuo@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@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/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_dccg.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_dccg.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_hwseq.h
drivers/gpu/drm/amd/display/dc/dcn314/dcn314_init.c
drivers/gpu/drm/amd/display/dc/inc/hw/dccg.h
drivers/gpu/drm/amd/display/dc/inc/hw_sequencer_private.h

index 46ca88741cb8ea5a681a3d201608739406ca2a53..1c3b6f25a7825167741039e4bcbddf3e01f53eb0 100644 (file)
@@ -726,11 +726,15 @@ void dcn10_hubp_pg_control(
        }
 }
 
-static void power_on_plane(
+static void power_on_plane_resources(
        struct dce_hwseq *hws,
        int plane_id)
 {
        DC_LOGGER_INIT(hws->ctx->logger);
+
+       if (hws->funcs.dpp_root_clock_control)
+               hws->funcs.dpp_root_clock_control(hws, plane_id, true);
+
        if (REG(DC_IP_REQUEST_CNTL)) {
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 1);
@@ -1237,11 +1241,15 @@ void dcn10_plane_atomic_power_down(struct dc *dc,
                        hws->funcs.hubp_pg_control(hws, 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", hubp->inst);
        }
+
+       if (hws->funcs.dpp_root_clock_control)
+               hws->funcs.dpp_root_clock_control(hws, dpp->inst, false);
 }
 
 /* disable HW used by plane.
@@ -2462,7 +2470,7 @@ static void dcn10_enable_plane(
 
        undo_DEGVIDCN10_253_wa(dc);
 
-       power_on_plane(dc->hwseq,
+       power_on_plane_resources(dc->hwseq,
                pipe_ctx->plane_res.hubp->inst);
 
        /* enable DCFCLK current DCHUB */
index 69ea1f4ea749f970306682d6217c0a366289be11..9ca162ea0d07fedcfadf33e91f571eea471318fd 100644 (file)
@@ -1130,11 +1130,15 @@ void dcn20_blank_pixel_data(
 }
 
 
-static void dcn20_power_on_plane(
+static void dcn20_power_on_plane_resources(
        struct dce_hwseq *hws,
        struct pipe_ctx *pipe_ctx)
 {
        DC_LOGGER_INIT(hws->ctx->logger);
+
+       if (hws->funcs.dpp_root_clock_control)
+               hws->funcs.dpp_root_clock_control(hws, pipe_ctx->plane_res.dpp->inst, true);
+
        if (REG(DC_IP_REQUEST_CNTL)) {
                REG_SET(DC_IP_REQUEST_CNTL, 0,
                                IP_REQUEST_EN, 1);
@@ -1158,7 +1162,7 @@ static void dcn20_enable_plane(struct dc *dc, struct pipe_ctx *pipe_ctx,
        //if (dc->debug.sanity_checks) {
        //      dcn10_verify_allow_pstate_change_high(dc);
        //}
-       dcn20_power_on_plane(dc->hwseq, pipe_ctx);
+       dcn20_power_on_plane_resources(dc->hwseq, pipe_ctx);
 
        /* enable DCFCLK current DCHUB */
        pipe_ctx->plane_res.hubp->funcs->hubp_clk_cntl(pipe_ctx->plane_res.hubp, true);
index 7f34418e63081810335c40ee0bdeabcb1f648989..7d2b982506fd7ba9e820002cbee2a74e23adc461 100644 (file)
@@ -66,17 +66,8 @@ void dccg31_update_dpp_dto(struct dccg *dccg, int dpp_inst, int req_dppclk)
                REG_UPDATE(DPPCLK_DTO_CTRL,
                                DPPCLK_DTO_ENABLE[dpp_inst], 1);
        } else {
-               //DTO must be enabled to generate a 0Hz clock output
-               if (dccg->ctx->dc->debug.root_clock_optimization.bits.dpp) {
-                       REG_UPDATE(DPPCLK_DTO_CTRL,
-                                       DPPCLK_DTO_ENABLE[dpp_inst], 1);
-                       REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
-                                       DPPCLK0_DTO_PHASE, 0,
-                                       DPPCLK0_DTO_MODULO, 1);
-               } else {
-                       REG_UPDATE(DPPCLK_DTO_CTRL,
-                                       DPPCLK_DTO_ENABLE[dpp_inst], 0);
-               }
+               REG_UPDATE(DPPCLK_DTO_CTRL,
+                               DPPCLK_DTO_ENABLE[dpp_inst], 0);
        }
        dccg->pipe_dppclk_khz[dpp_inst] = req_dppclk;
 }
index 0b769ee714058a0066a8d1ea37da3b117515d2b0..081ce168f621137e0564cdbd2ca3267d8a005e8c 100644 (file)
@@ -289,8 +289,31 @@ static void dccg314_set_valid_pixel_rate(
        dccg314_set_dtbclk_dto(dccg, &dto_params);
 }
 
+static void dccg314_dpp_root_clock_control(
+               struct dccg *dccg,
+               unsigned int dpp_inst,
+               bool clock_on)
+{
+       struct dcn_dccg *dccg_dcn = TO_DCN_DCCG(dccg);
+
+       if (clock_on) {
+               /* turn off the DTO and leave phase/modulo at max */
+               REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 0);
+               REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
+                         DPPCLK0_DTO_PHASE, 0xFF,
+                         DPPCLK0_DTO_MODULO, 0xFF);
+       } else {
+               /* turn on the DTO to generate a 0hz clock */
+               REG_UPDATE(DPPCLK_DTO_CTRL, DPPCLK_DTO_ENABLE[dpp_inst], 1);
+               REG_SET_2(DPPCLK_DTO_PARAM[dpp_inst], 0,
+                         DPPCLK0_DTO_PHASE, 0,
+                         DPPCLK0_DTO_MODULO, 1);
+       }
+}
+
 static const struct dccg_funcs dccg314_funcs = {
        .update_dpp_dto = dccg31_update_dpp_dto,
+       .dpp_root_clock_control = dccg314_dpp_root_clock_control,
        .get_dccg_ref_freq = dccg31_get_dccg_ref_freq,
        .dccg_init = dccg31_init,
        .set_dpstreamclk = dccg314_set_dpstreamclk,
index bcc03426fc3e684ee6d099923ef18350bdb0fa80..40c488b26901b3cecbe2c08b28f62dbe9724860f 100644 (file)
@@ -390,6 +390,16 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx)
                                pix_per_cycle);
 }
 
+void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on)
+{
+       if (!hws->ctx->dc->debug.root_clock_optimization.bits.dpp)
+               return;
+
+       if (hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control)
+               hws->ctx->dc->res_pool->dccg->funcs->dpp_root_clock_control(
+                       hws->ctx->dc->res_pool->dccg, dpp_inst, clock_on);
+}
+
 void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on)
 {
        struct dc_context *ctx = hws->ctx;
index c419d3dbdfee6d6e04d953d3681b6d0c177cd2dc..c786d5e6a428ed983f95b09ee798efea95ff9cfa 100644 (file)
@@ -43,4 +43,6 @@ void dcn314_set_pixels_per_cycle(struct pipe_ctx *pipe_ctx);
 
 void dcn314_hubp_pg_control(struct dce_hwseq *hws, unsigned int hubp_inst, bool power_on);
 
+void dcn314_dpp_root_clock_control(struct dce_hwseq *hws, unsigned int dpp_inst, bool clock_on);
+
 #endif /* __DC_HWSS_DCN314_H__ */
index 343f4d9dd5e3412cb440c52ad7d48362f652b076..5267e901a35c130ad4b050db6be1b4d19a323323 100644 (file)
@@ -137,6 +137,7 @@ static const struct hwseq_private_funcs dcn314_private_funcs = {
        .plane_atomic_disable = dcn20_plane_atomic_disable,
        .plane_atomic_power_down = dcn10_plane_atomic_power_down,
        .enable_power_gating_plane = dcn314_enable_power_gating_plane,
+       .dpp_root_clock_control = dcn314_dpp_root_clock_control,
        .hubp_pg_control = dcn314_hubp_pg_control,
        .program_all_writeback_pipes_in_tree = dcn30_program_all_writeback_pipes_in_tree,
        .update_odm = dcn314_update_odm,
index ce006762f2571e9b2dd8ae84eaec854ab5fa639c..ad6acd1b34e1dd33eedc072b7db807ff3a40ffd3 100644 (file)
@@ -148,18 +148,21 @@ struct dccg_funcs {
                struct dccg *dccg,
                int inst);
 
-void (*set_pixel_rate_div)(
-        struct dccg *dccg,
-        uint32_t otg_inst,
-        enum pixel_rate_div k1,
-        enum pixel_rate_div k2);
-
-void (*set_valid_pixel_rate)(
-        struct dccg *dccg,
-       int ref_dtbclk_khz,
-        int otg_inst,
-        int pixclk_khz);
+       void (*set_pixel_rate_div)(struct dccg *dccg,
+                       uint32_t otg_inst,
+                       enum pixel_rate_div k1,
+                       enum pixel_rate_div k2);
 
+       void (*set_valid_pixel_rate)(
+                       struct dccg *dccg,
+                       int ref_dtbclk_khz,
+                       int otg_inst,
+                       int pixclk_khz);
+
+       void (*dpp_root_clock_control)(
+                       struct dccg *dccg,
+                       unsigned int dpp_inst,
+                       bool clock_on);
 };
 
 #endif //__DAL_DCCG_H__
index 45d37c584551352e691a4e8931514b8cba2e63b7..5f63b67975cf45ff738a650dcfd9993702f82803 100644 (file)
@@ -115,6 +115,10 @@ struct hwseq_private_funcs {
        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_root_clock_control)(
+                       struct dce_hwseq *hws,
+                       unsigned int dpp_inst,
+                       bool clock_on);
        void (*dpp_pg_control)(struct dce_hwseq *hws,
                        unsigned int dpp_inst,
                        bool power_on);