Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/amd/display: fixed the DSC power off sequence during Driver PnP

[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>

authored by

Yi-Ling Chen and committed by
Alex Deucher
8fa6f4c5 3f232a0f

+62 -5
+37
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
··· 1362 1362 1363 1363 tg->funcs->tg_init(tg); 1364 1364 } 1365 + 1366 + /* Power gate DSCs */ 1367 + if (hws->funcs.dsc_pg_control != NULL) { 1368 + uint32_t num_opps = 0; 1369 + uint32_t opp_id_src0 = OPP_ID_INVALID; 1370 + uint32_t opp_id_src1 = OPP_ID_INVALID; 1371 + 1372 + // Step 1: To find out which OPTC is running & OPTC DSC is ON 1373 + for (i = 0; i < dc->res_pool->res_cap->num_timing_generator; i++) { 1374 + uint32_t optc_dsc_state = 0; 1375 + struct timing_generator *tg = dc->res_pool->timing_generators[i]; 1376 + 1377 + if (tg->funcs->is_tg_enabled(tg)) { 1378 + if (tg->funcs->get_dsc_status) 1379 + tg->funcs->get_dsc_status(tg, &optc_dsc_state); 1380 + // Only one OPTC with DSC is ON, so if we got one result, we would exit this block. 1381 + // non-zero value is DSC enabled 1382 + if (optc_dsc_state != 0) { 1383 + tg->funcs->get_optc_source(tg, &num_opps, &opp_id_src0, &opp_id_src1); 1384 + break; 1385 + } 1386 + } 1387 + } 1388 + 1389 + // Step 2: To power down DSC but skip DSC of running OPTC 1390 + for (i = 0; i < dc->res_pool->res_cap->num_dsc; i++) { 1391 + struct dcn_dsc_state s = {0}; 1392 + 1393 + dc->res_pool->dscs[i]->funcs->dsc_read_state(dc->res_pool->dscs[i], &s); 1394 + 1395 + if ((s.dsc_opp_source == opp_id_src0 || s.dsc_opp_source == opp_id_src1) && 1396 + s.dsc_clock_en && s.dsc_fw_en) 1397 + continue; 1398 + 1399 + hws->funcs.dsc_pg_control(hws, dc->res_pool->dscs[i]->inst, false); 1400 + } 1401 + } 1365 1402 } 1366 1403 1367 1404 void dcn10_init_hw(struct dc *dc)
+2
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_dsc.c
··· 162 162 REG_GET(DSCC_PPS_CONFIG2, PIC_WIDTH, &s->dsc_pic_width); 163 163 REG_GET(DSCC_PPS_CONFIG2, PIC_HEIGHT, &s->dsc_pic_height); 164 164 REG_GET(DSCC_PPS_CONFIG7, SLICE_BPG_OFFSET, &s->dsc_slice_bpg_offset); 165 + REG_GET_2(DSCRM_DSC_FORWARD_CONFIG, DSCRM_DSC_FORWARD_EN, &s->dsc_fw_en, 166 + DSCRM_DSC_OPP_PIPE_SOURCE, &s->dsc_opp_source); 165 167 } 166 168 167 169
+14
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.c
··· 190 190 OPTC_DSC_SLICE_WIDTH, dsc_slice_width); 191 191 } 192 192 193 + /* Get DSC-related configuration. 194 + * dsc_mode: 0 disables DSC, other values enable DSC in specified format 195 + */ 196 + void optc2_get_dsc_status(struct timing_generator *optc, 197 + uint32_t *dsc_mode) 198 + { 199 + struct optc *optc1 = DCN10TG_FROM_TG(optc); 200 + 201 + REG_GET(OPTC_DATA_FORMAT_CONTROL, 202 + OPTC_DSC_MODE, dsc_mode); 203 + } 204 + 205 + 193 206 /*TEMP: Need to figure out inheritance model here.*/ 194 207 bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) 195 208 { ··· 592 579 .get_crc = optc1_get_crc, 593 580 .configure_crc = optc2_configure_crc, 594 581 .set_dsc_config = optc2_set_dsc_config, 582 + .get_dsc_status = optc2_get_dsc_status, 595 583 .set_dwb_source = optc2_set_dwb_source, 596 584 .set_odm_bypass = optc2_set_odm_bypass, 597 585 .set_odm_combine = optc2_set_odm_combine,
+3
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_optc.h
··· 98 98 uint32_t dsc_bytes_per_pixel, 99 99 uint32_t dsc_slice_width); 100 100 101 + void optc2_get_dsc_status(struct timing_generator *optc, 102 + uint32_t *dsc_mode); 103 + 101 104 void optc2_set_odm_bypass(struct timing_generator *optc, 102 105 const struct dc_crtc_timing *dc_crtc_timing); 103 106
+1
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_optc.c
··· 332 332 .get_crc = optc1_get_crc, 333 333 .configure_crc = optc2_configure_crc, 334 334 .set_dsc_config = optc3_set_dsc_config, 335 + .get_dsc_status = optc2_get_dsc_status, 335 336 .set_dwb_source = NULL, 336 337 .set_odm_bypass = optc3_set_odm_bypass, 337 338 .set_odm_combine = optc3_set_odm_combine,
-5
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hwseq.c
··· 192 192 link->link_status.link_active = true; 193 193 } 194 194 195 - /* Power gate DSCs */ 196 - for (i = 0; i < res_pool->res_cap->num_dsc; i++) 197 - if (hws->funcs.dsc_pg_control != NULL) 198 - hws->funcs.dsc_pg_control(hws, res_pool->dscs[i]->inst, false); 199 - 200 195 /* Enables outbox notifications for usb4 dpia */ 201 196 if (dc->res_pool->usb4_dpia_count) 202 197 dmub_enable_outbox_notification(dc);
+1
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_optc.c
··· 256 256 .get_crc = optc1_get_crc, 257 257 .configure_crc = optc2_configure_crc, 258 258 .set_dsc_config = optc3_set_dsc_config, 259 + .get_dsc_status = optc2_get_dsc_status, 259 260 .set_dwb_source = NULL, 260 261 .set_odm_bypass = optc3_set_odm_bypass, 261 262 .set_odm_combine = optc31_set_odm_combine,
+2
drivers/gpu/drm/amd/display/dc/inc/hw/dsc.h
··· 61 61 uint32_t dsc_pic_height; 62 62 uint32_t dsc_slice_bpg_offset; 63 63 uint32_t dsc_chunk_size; 64 + uint32_t dsc_fw_en; 65 + uint32_t dsc_opp_source; 64 66 }; 65 67 66 68
+2
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
··· 290 290 enum optc_dsc_mode dsc_mode, 291 291 uint32_t dsc_bytes_per_pixel, 292 292 uint32_t dsc_slice_width); 293 + void (*get_dsc_status)(struct timing_generator *optc, 294 + uint32_t *dsc_mode); 293 295 void (*set_odm_bypass)(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing); 294 296 void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt, 295 297 struct dc_crtc_timing *timing);