diff options
author | Wenjing Liu <wenjing.liu@amd.com> | 2024-04-17 15:23:08 -0400 |
---|---|---|
committer | Alex Deucher <alexander.deucher@amd.com> | 2024-04-30 09:57:04 -0400 |
commit | e6a901a00822659181c93c86d8bbc2a17779fddc (patch) | |
tree | fe207fcbc0e4f94ec6405d9bec097f82bfbaa2f9 /drivers/gpu/drm/amd/display/dc/optc | |
parent | a8baec4623aedf36d50767627f6eae5ebf07c6fb (diff) |
drm/amd/display: use even ODM slice width for two pixels per container
[why]
When optc uses two pixel per container, each ODM slice width must be an
even number.
[how]
If ODM slice width is odd number increase it by 1.
Reviewed-by: Dillon Varone <dillon.varone@amd.com>
Acked-by: Wayne Lin <wayne.lin@amd.com>
Signed-off-by: Wenjing Liu <wenjing.liu@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/amd/display/dc/optc')
12 files changed, 46 insertions, 48 deletions
diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c index 5574bc628053..03140e7372d9 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn10/dcn10_optc.c @@ -297,7 +297,7 @@ void optc1_program_timing( * of stereo handled in explicit call */ - if (optc1_is_two_pixels_per_containter(&patched_crtc_timing) || optc1->opp_count == 2) + if (optc->funcs->is_two_pixels_per_container(&patched_crtc_timing) || optc1->opp_count == 2) h_div = H_TIMING_DIV_BY2; if (REG(OPTC_DATA_FORMAT_CONTROL) && optc1->tg_mask->OPTC_DATA_FORMAT != 0) { @@ -1548,6 +1548,27 @@ bool optc1_get_crc(struct timing_generator *optc, return true; } +/* "Container" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: + * + * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as + * container rate. + * + * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be + * halved to maintain the correct pixel rate. + * + * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied + * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. + * + */ +bool optc1_is_two_pixels_per_container(const struct dc_crtc_timing *timing) +{ + bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; + + two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 + && !timing->dsc_cfg.ycbcr422_simple); + return two_pix; +} + static const struct timing_generator_funcs dcn10_tg_funcs = { .validate_timing = optc1_validate_timing, .program_timing = optc1_program_timing, @@ -1594,6 +1615,7 @@ static const struct timing_generator_funcs dcn10_tg_funcs = { .program_manual_trigger = optc1_program_manual_trigger, .setup_manual_trigger = optc1_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn10_timing_generator_init(struct optc *optc1) @@ -1609,25 +1631,3 @@ void dcn10_timing_generator_init(struct optc *optc1) optc1->min_h_sync_width = 4; optc1->min_v_sync_width = 1; } - -/* "Containter" vs. "pixel" is a concept within HW blocks, mostly those closer to the back-end. It works like this: - * - * - In most of the formats (RGB or YCbCr 4:4:4, 4:2:2 uncompressed and DSC 4:2:2 Simple) pixel rate is the same as - * containter rate. - * - * - In 4:2:0 (DSC or uncompressed) there are two pixels per container, hence the target container rate has to be - * halved to maintain the correct pixel rate. - * - * - Unlike 4:2:2 uncompressed, DSC 4:2:2 Native also has two pixels per container (this happens when DSC is applied - * to it) and has to be treated the same as 4:2:0, i.e. target containter rate has to be halved in this case as well. - * - */ -bool optc1_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) -{ - bool two_pix = timing->pixel_encoding == PIXEL_ENCODING_YCBCR420; - - two_pix = two_pix || (timing->flags.DSC && timing->pixel_encoding == PIXEL_ENCODING_YCBCR422 - && !timing->dsc_cfg.ycbcr422_simple); - return two_pix; -} - diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c index d6f095b4555d..314a0cee08ae 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c @@ -158,13 +158,6 @@ void optc2_get_dsc_status(struct timing_generator *optc, 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) -{ - return optc1_is_two_pixels_per_containter(timing); -} - void optc2_set_odm_bypass(struct timing_generator *optc, const struct dc_crtc_timing *dc_crtc_timing) { @@ -177,7 +170,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc, OPTC_SEG1_SRC_SEL, 0xf); REG_WRITE(OTG_H_TIMING_CNTL, 0); - h_div_2 = optc2_is_two_pixels_per_containter(dc_crtc_timing); + h_div_2 = optc->funcs->is_two_pixels_per_container(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_BY2, h_div_2); REG_SET(OPTC_MEMORY_CONFIG, 0, @@ -560,6 +553,7 @@ static struct timing_generator_funcs dcn20_tg_funcs = { .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .align_vblanks = optc2_align_vblanks, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn20_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h index c2e03ced392e..1f8bc7fce9fc 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h @@ -118,7 +118,6 @@ void optc2_lock_doublebuffer_disable(struct timing_generator *optc); void optc2_lock_doublebuffer_enable(struct timing_generator *optc); void optc2_setup_manual_trigger(struct timing_generator *optc); void optc2_program_manual_trigger(struct timing_generator *optc); -bool optc2_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); bool optc2_configure_crc(struct timing_generator *optc, const struct crc_params *params); #endif /* __DC_OPTC_DCN20_H__ */ diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c index 70fcbec03fb6..49c2efdfa403 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.c @@ -38,12 +38,6 @@ #define FN(reg_name, field_name) \ optc1->tg_shift->field_name, optc1->tg_mask->field_name -/*TEMP: Need to figure out inheritance model here.*/ -bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing) -{ - return optc1_is_two_pixels_per_containter(timing); -} - static void optc201_triplebuffer_lock(struct timing_generator *optc) { struct optc *optc1 = DCN10TG_FROM_TG(optc); @@ -185,6 +179,7 @@ static struct timing_generator_funcs dcn201_tg_funcs = { .program_manual_trigger = optc2_program_manual_trigger, .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn201_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h index e9545b73513a..a9b281abfd44 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn201/dcn201_optc.h @@ -68,7 +68,4 @@ SF(DWB_SOURCE_SELECT, OPTC_DWB1_SOURCE_SELECT, mask_sh) void dcn201_timing_generator_init(struct optc *optc); - -bool optc201_is_two_pixels_per_containter(const struct dc_crtc_timing *timing); - #endif diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c index b97bdb868a0e..c805fd2a48a1 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c @@ -206,7 +206,7 @@ void optc3_set_odm_bypass(struct timing_generator *optc, OPTC_SEG3_SRC_SEL, 0xf ); - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, h_div); @@ -376,6 +376,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn30_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c index b3cfcb887905..1a22ae89fb55 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn301/dcn301_optc.c @@ -168,6 +168,7 @@ static struct timing_generator_funcs dcn30_tg_funcs = { .setup_manual_trigger = optc301_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .wait_drr_doublebuffer_pending_clear = optc3_wait_drr_doublebuffer_pending_clear, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn301_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c index 63a677c8ee27..84d2ba31e2ca 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c @@ -292,6 +292,7 @@ static struct timing_generator_funcs dcn31_tg_funcs = { .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, .init_odm = optc3_init_odm, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn31_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c index 0086cafb0f7a..9022fb2ffca4 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c @@ -175,7 +175,7 @@ static void optc314_set_odm_bypass(struct timing_generator *optc, OPTC_SEG3_SRC_SEL, 0xf ); - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, h_div); @@ -255,6 +255,7 @@ static struct timing_generator_funcs dcn314_tg_funcs = { .set_odm_bypass = optc314_set_odm_bypass, .set_odm_combine = optc314_set_odm_combine, .set_h_timing_div_manual_mode = optc314_set_h_timing_div_manual_mode, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn314_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c index 52eab8fccb7f..c18d580279a8 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c @@ -239,7 +239,7 @@ void optc32_set_odm_bypass(struct timing_generator *optc, OPTC_SEG3_SRC_SEL, 0xf ); - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, h_div); @@ -361,6 +361,7 @@ static struct timing_generator_funcs dcn32_tg_funcs = { .program_manual_trigger = optc2_program_manual_trigger, .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn32_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c index d393be30dff8..cf8da22492dc 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c @@ -438,6 +438,7 @@ static struct timing_generator_funcs dcn35_tg_funcs = { .get_hw_timing = optc1_get_hw_timing, .init_odm = optc3_init_odm, .set_long_vtotal = optc35_set_long_vtotal, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn35_timing_generator_init(struct optc *optc1) diff --git a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c index 5d65d8376f50..fd030e5b9de6 100644 --- a/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c +++ b/drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c @@ -107,11 +107,17 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id, struct optc *optc1 = DCN10TG_FROM_TG(optc); uint32_t h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; - uint32_t odm_segment_width = h_active / opp_cnt; - uint32_t odm_segment_width_last = - h_active - odm_segment_width * (opp_cnt - 1); uint32_t odm_mem_bit_map = decide_odm_mem_bit_map( opp_id, opp_cnt, h_active); + uint32_t odm_segment_width; + uint32_t odm_segment_width_last; + bool is_two_pixels_per_container = optc->funcs->is_two_pixels_per_container(timing); + + odm_segment_width = h_active / opp_cnt; + if ((odm_segment_width % 2) && is_two_pixels_per_container) + odm_segment_width++; + odm_segment_width_last = + h_active - odm_segment_width * (opp_cnt - 1); REG_SET(OPTC_MEMORY_CONFIG, 0, OPTC_MEM_SEL, odm_mem_bit_map); @@ -277,7 +283,7 @@ static void optc401_set_odm_bypass(struct timing_generator *optc, OPTC_SEG3_SRC_SEL, 0xf ); - h_div = optc1_is_two_pixels_per_containter(dc_crtc_timing); + h_div = optc->funcs->is_two_pixels_per_container(dc_crtc_timing); REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, h_div); @@ -461,6 +467,7 @@ static struct timing_generator_funcs dcn401_tg_funcs = { .program_manual_trigger = optc2_program_manual_trigger, .setup_manual_trigger = optc2_setup_manual_trigger, .get_hw_timing = optc1_get_hw_timing, + .is_two_pixels_per_container = optc1_is_two_pixels_per_container, }; void dcn401_timing_generator_init(struct optc *optc1) |