]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
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 135e2b58cc7339a790fb529960e1022f6dd4ebea..c50427bfab77221b0253983207459d4c67e0ea4f 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 79b640e202eb4752dccbb2f59d526200a7736d63..ef5c4c0f4d6c242c5e6c60708f8d7c9875563108 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 c90b8516dcc128d95a3ba67ddfc2c80858863d93..8c34751b0e582c81b01f9be72fadd6251bd45cbe 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 be19a6885fbfd23fa135973b921d9b4c2b898dbf..f7968b9ca16eb41fcce68fff662fd59a6e271905 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 5d9e6413d67a2e3b46ff936f00e4d23be8fab586..f5e8916601d3d65a7c3828a9aa5f1a695dd60b52 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 bdaeb6ebdacb0f9a28e693ae293b91c15d047161..a668feff30b89776910a2a38c2ec19688a82b86e 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 a4b1d98f00077dde0a8ea86baac10d7bb2441715..e8562fa11366a481133ba9073bf3cee2954ef547 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 0c83e79d3ce371df84d33e2448a51d4002e0f02a..346f0ba73e864397f69e7ce933d98a863b31fa07 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 7390baf916b58451a3e490a4ef402286e327204a..c29320b3855da4da5ed5403e48fa0bfa32cced0e 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);