drm/amd/display: fixed the DSC power off sequence during Driver PnP
authorYi-Ling Chen <Yi-Ling.Chen2@amd.com>
Fri, 5 Nov 2021 07:43:25 +0000 (15:43 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 22 Nov 2021 19:45:02 +0000 (14:45 -0500)
[WHY]
After unloading driver, driver would not disable DSC function.
At next loading driver, driver would power all DSC engines off.
When driver powered the active DSC off, the screen would be gray
until reprograming DSC relatived register correcntly.

[HOW]
1. Remove DSC Power down code into init_pipes()
2. Depend on  the OTG mapping information and DSC status to skip
power off for the working DSC.

Reviewed-by: Anthony Koo <Anthony.Koo@amd.com>
Acked-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Yi-Ling Chen <Yi-Ling.Chen2@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_dsc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h

index 135e2b5..c50427b 100644 (file)
@@ -1362,6 +1362,43 @@ void dcn10_init_pipes(struct dc *dc, struct dc_state *context)
 
                tg->funcs->tg_init(tg);
        }
+
+       /* Power gate DSCs */
+       if (hws->funcs.dsc_pg_control != NULL) {
+               uint32_t num_opps = 0;
+               uint32_t opp_id_src0 = OPP_ID_INVALID;
+               uint32_t opp_id_src1 = OPP_ID_INVALID;
+
+               // Step 1: To find out which OPTC is running & OPTC DSC is ON
+               for (i = 0; i < dc->res_pool->res_cap->num_timing_generator; i++) {
+                       uint32_t optc_dsc_state = 0;
+                       struct timing_generator *tg = dc->res_pool->timing_generators[i];
+
+                       if (tg->funcs->is_tg_enabled(tg)) {
+                               if (tg->funcs->get_dsc_status)
+                                       tg->funcs->get_dsc_status(tg, &optc_dsc_state);
+                               // Only one OPTC with DSC is ON, so if we got one result, we would exit this block.
+                               // non-zero value is DSC enabled
+                               if (optc_dsc_state != 0) {
+                                       tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1);
+                                       break;
+                               }
+                       }
+               }
+
+               // Step 2: To power down DSC but skip DSC  of running OPTC
+               for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) {
+                       struct dcn_dsc_state s  = {0};
+
+                       dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s);
+
+                       if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) &&
+                               s.dsc_clock_en && s.dsc_fw_en)
+                               continue;
+
+                       hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false);
+               }
+       }
 }
 
 void dcn10_init_hw(struct dc *dc)
index 79b640e..ef5c4c0 100644 (file)
@@ -162,6 +162,8 @@ static void dsc2_read_state(struct display_stream_compressor *dsc, struct dcn_ds
        REG_GET(DSCC_PPS_CONFIG2, PIC_WIDTH, &s->dsc_pic_width);
        REG_GET(DSCC_PPS_CONFIG2, PIC_HEIGHT, &s->dsc_pic_height);
        REG_GET(DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, &s->dsc_slice_bpg_offset);
+       REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &s->dsc_fw_en,
+               DSCRM_DSC_OPP_PIPE_SOURCE, &s->dsc_opp_source);
 }
 
 
index c90b851..8c34751 100644 (file)
@@ -190,6 +190,19 @@ void optc2_set_dsc_config(struct timing_generator *optc,
                OPTC_DSC_SLICE_WIDTH, dsc_slice_width);
 }
 
+/* Get DSC-related configuration.
+ *   dsc_mode: 0 disables DSC, other values enable DSC in specified format
+ */
+void optc2_get_dsc_status(struct timing_generator *optc,
+                                       uint32_t *dsc_mode)
+{
+       struct optc *optc1 = DCN10TG_FROM_TG(optc);
+
+       REG_GET(OPTC_DATA_FORMAT_CONTROL,
+               OPTC_DSC_MODE, dsc_mode);
+}
+
+
 /*TEMP: Need to figure out inheritance model here.*/
 bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing)
 {
@@ -579,6 +592,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
                .get_crc = optc1_get_crc,
                .configure_crc = optc2_configure_crc,
                .set_dsc_config = optc2_set_dsc_config,
+               .get_dsc_status = optc2_get_dsc_status,
                .set_dwb_source = optc2_set_dwb_source,
                .set_odm_bypass = optc2_set_odm_bypass,
                .set_odm_combine = optc2_set_odm_combine,
index be19a68..f7968b9 100644 (file)
@@ -98,6 +98,9 @@ void optc2_set_dsc_config(struct timing_generator *optc,
                                        uint32_t dsc_bytes_per_pixel,
                                        uint32_t dsc_slice_width);
 
+void optc2_get_dsc_status(struct timing_generator *optc,
+                                       uint32_t *dsc_mode);
+
 void optc2_set_odm_bypass(struct timing_generator *optc,
                const struct dc_crtc_timing *dc_crtc_timing);
 
index 5d9e641..f5e8916 100644 (file)
@@ -332,6 +332,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = {
                .get_crc = optc1_get_crc,
                .configure_crc = optc2_configure_crc,
                .set_dsc_config = optc3_set_dsc_config,
+               .get_dsc_status = optc2_get_dsc_status,
                .set_dwb_source = NULL,
                .set_odm_bypass = optc3_set_odm_bypass,
                .set_odm_combine = optc3_set_odm_combine,
index bdaeb6e..a668fef 100644 (file)
@@ -192,11 +192,6 @@ void dcn31_init_hw(struct dc *dc)
                        link->link_status.link_active = true;
        }
 
-       /* Power gate DSCs */
-       for (i = 0; i < res_pool->res_cap->num_dsc; i++)
-               if (hws->funcs.dsc_pg_control != NULL)
-                       hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false);
-
        /* Enables outbox notifications for usb4 dpia */
        if (dc->res_pool->usb4_dpia_count)
                dmub_enable_outbox_notification(dc);
index a4b1d98..e8562fa 100644 (file)
@@ -256,6 +256,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = {
                .get_crc = optc1_get_crc,
                .configure_crc = optc2_configure_crc,
                .set_dsc_config = optc3_set_dsc_config,
+               .get_dsc_status = optc2_get_dsc_status,
                .set_dwb_source = NULL,
                .set_odm_bypass = optc3_set_odm_bypass,
                .set_odm_combine = optc31_set_odm_combine,
index 0c83e79..346f0ba 100644 (file)
@@ -61,6 +61,8 @@ struct dcn_dsc_state {
        uint32_t dsc_pic_height;
        uint32_t dsc_slice_bpg_offset;
        uint32_t dsc_chunk_size;
+       uint32_t dsc_fw_en;
+       uint32_t dsc_opp_source;
 };
 
 
index 7390baf..c29320b 100644 (file)
@@ -290,6 +290,8 @@ struct timing_generator_funcs {
                               enum optc_dsc_mode dsc_mode,
                               uint32_t dsc_bytes_per_pixel,
                               uint32_t dsc_slice_width);
+       void (*get_dsc_status)(struct timing_generator *optc,
+                                       uint32_t *dsc_mode);
        void (*set_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing);
        void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt,
                        struct dc_crtc_timing *timing);