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

drm/amd/display: Add left edge pixel for YCbCr422/420 + ODM pipe split

[WHY]
Currently 3-tap chroma subsampling is used for YCbCr422/420. When ODM
pipesplit is used, pixels on the left edge of ODM slices need one extra
pixel from the right edge of the previous slice to calculate the correct
chroma value.

Without this change, the chroma value is slightly different than
expected. This is usually imperceptible visually, but it impacts test
pattern CRCs for compliance test automation.

[HOW]
Update logic to use the register for adding extra left edge pixel for
YCbCr422/420 ODM cases.

Reviewed-by: George Shen <george.shen@amd.com>
Acked-by: Alex Hung <alex.hung@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>

authored by

Wenjing Liu and committed by
Alex Deucher
f9d48a88 d5192c15

+140 -106
+8 -1
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
··· 2110 2110 struct rect odm_slice_dst; 2111 2111 struct rect odm_slice_src; 2112 2112 struct pipe_ctx *opp_head = resource_get_opp_head(pipe_ctx); 2113 + struct output_pixel_processor *opp = opp_head->stream_res.opp; 2113 2114 uint32_t left_edge_extra_pixel_count; 2114 2115 2115 2116 odm_slice_dst = resource_get_odm_slice_dst_rect(opp_head); 2116 2117 odm_slice_src = odm_slice_dst; 2117 2118 2118 - left_edge_extra_pixel_count = 0; 2119 + if (opp->funcs->opp_get_left_edge_extra_pixel_count) 2120 + left_edge_extra_pixel_count = 2121 + opp->funcs->opp_get_left_edge_extra_pixel_count( 2122 + opp, pipe_ctx->stream->timing.pixel_encoding, 2123 + resource_is_pipe_type(opp_head, OTG_MASTER)); 2124 + else 2125 + left_edge_extra_pixel_count = 0; 2119 2126 2120 2127 odm_slice_src.x -= left_edge_extra_pixel_count; 2121 2128 odm_slice_src.width += left_edge_extra_pixel_count;
+20 -5
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c
··· 23 23 * 24 24 */ 25 25 26 + #include "core_types.h" 26 27 #include "dm_services.h" 27 28 #include "dcn20_opp.h" 28 29 #include "reg_helper.h" ··· 351 350 return (dpg_en == 1 && double_buffer_pending == 1); 352 351 } 353 352 354 - void opp2_program_left_edge_extra_pixel ( 353 + void opp2_program_left_edge_extra_pixel( 355 354 struct output_pixel_processor *opp, 356 - bool count) 355 + enum dc_pixel_encoding pixel_encoding, 356 + bool is_primary) 357 357 { 358 358 struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp); 359 + uint32_t count = opp2_get_left_edge_extra_pixel_count(opp, pixel_encoding, is_primary); 359 360 360 - /* Specifies the number of extra left edge pixels that are supplied to 361 + /* 362 + * Specifies the number of extra left edge pixels that are supplied to 361 363 * the 422 horizontal chroma sub-sample filter. 362 - * Note that when left edge pixel is not "0", fmt pixel encoding can be in either 420 or 422 mode 363 - * */ 364 + */ 364 365 REG_UPDATE(FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, count); 366 + } 367 + 368 + uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp, 369 + enum dc_pixel_encoding pixel_encoding, bool is_primary) 370 + { 371 + if ((pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420) && 372 + !opp->ctx->dc->debug.force_chroma_subsampling_1tap && 373 + !is_primary) 374 + return 1; 375 + else 376 + return 0; 365 377 } 366 378 367 379 /*****************************************/ ··· 394 380 .opp_dpg_set_blank_color = opp2_dpg_set_blank_color, 395 381 .opp_destroy = opp1_destroy, 396 382 .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel, 383 + .opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count, 397 384 }; 398 385 399 386 void dcn20_opp_construct(struct dcn20_opp *oppn20,
+3 -1
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h
··· 167 167 168 168 void opp2_program_left_edge_extra_pixel ( 169 169 struct output_pixel_processor *opp, 170 - bool count); 170 + enum dc_pixel_encoding pixel_encoding, bool is_primary); 171 171 172 + uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp, 173 + enum dc_pixel_encoding pixel_encoding, bool is_primary); 172 174 #endif
+1
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_opp.c
··· 54 54 .opp_dpg_set_blank_color = opp2_dpg_set_blank_color, 55 55 .opp_destroy = opp1_destroy, 56 56 .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel, 57 + .opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count, 57 58 }; 58 59 59 60 void dcn201_opp_construct(struct dcn201_opp *oppn201,
+31 -36
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
··· 820 820 struct dc_stream_state *stream = pipe_ctx->stream; 821 821 struct drr_params params = {0}; 822 822 unsigned int event_triggers = 0; 823 - struct pipe_ctx *odm_pipe; 824 823 int opp_cnt = 1; 825 - int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; 824 + int opp_inst[MAX_PIPES] = {0}; 826 825 bool interlace = stream->timing.flags.INTERLACE; 827 826 int i; 828 827 struct mpc_dwb_flow_control flow_control; ··· 831 832 bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container); 832 833 unsigned int k1_div = PIXEL_RATE_DIV_NA; 833 834 unsigned int k2_div = PIXEL_RATE_DIV_NA; 835 + int odm_slice_width; 836 + int last_odm_slice_width; 837 + struct pipe_ctx *opp_heads[MAX_PIPES]; 834 838 835 839 if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) { 836 840 hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div); ··· 852 850 853 851 /* TODO check if timing_changed, disable stream if timing changed */ 854 852 855 - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { 856 - opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; 857 - opp_cnt++; 858 - } 853 + opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads); 854 + for (i = 0; i < opp_cnt; i++) 855 + opp_inst[opp_cnt] = opp_heads[i]->stream_res.opp->inst; 859 856 857 + odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 858 + last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 860 859 if (opp_cnt > 1) 861 860 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 862 861 pipe_ctx->stream_res.tg, 863 - opp_inst, opp_cnt, 864 - &pipe_ctx->stream->timing); 862 + opp_inst, opp_cnt, odm_slice_width, 863 + last_odm_slice_width); 865 864 866 865 /* HW program guide assume display already disable 867 866 * by unplug sequence. OTG assume stop. ··· 930 927 } 931 928 } 932 929 933 - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) 934 - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( 935 - odm_pipe->stream_res.opp, 930 + for (i = 0; i < opp_cnt; i++) { 931 + opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control( 932 + opp_heads[i]->stream_res.opp, 936 933 true); 937 - 938 - pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 939 - pipe_ctx->stream_res.opp, 940 - true); 934 + opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 935 + opp_heads[i]->stream_res.opp, 936 + stream->timing.pixel_encoding, 937 + resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 938 + } 941 939 942 940 hws->funcs.blank_pixel_data(dc, pipe_ctx, true); 943 941 ··· 1179 1175 struct pipe_ctx *odm_pipe; 1180 1176 int opp_cnt = 1; 1181 1177 int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; 1178 + int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 1179 + int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 1182 1180 1183 1181 for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { 1184 1182 opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst; ··· 1191 1185 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 1192 1186 pipe_ctx->stream_res.tg, 1193 1187 opp_inst, opp_cnt, 1194 - &pipe_ctx->stream->timing); 1188 + odm_slice_width, last_odm_slice_width); 1195 1189 else 1196 1190 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 1197 1191 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); ··· 1209 1203 enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; 1210 1204 enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED; 1211 1205 struct pipe_ctx *odm_pipe; 1212 - int odm_cnt = 1; 1213 - int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right; 1214 - int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top; 1215 - int odm_slice_width, last_odm_slice_width, offset = 0; 1216 - bool is_two_pixels_per_container = 1217 - pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing); 1206 + struct rect odm_slice_src; 1218 1207 1219 1208 if (stream->link->test_pattern_enabled) 1220 1209 return; 1221 1210 1222 1211 /* get opp dpg blank color */ 1223 1212 color_space_to_black_color(dc, color_space, &black_color); 1224 - 1225 - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) 1226 - odm_cnt++; 1227 - odm_slice_width = h_active / odm_cnt; 1228 - if ((odm_slice_width % 2) && is_two_pixels_per_container) 1229 - odm_slice_width++; 1230 - last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1); 1231 1213 1232 1214 if (blank) { 1233 1215 dc->hwss.set_abm_immediate_disable(pipe_ctx); ··· 1231 1237 odm_pipe = pipe_ctx; 1232 1238 1233 1239 while (odm_pipe->next_odm_pipe) { 1240 + odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe); 1234 1241 dc->hwss.set_disp_pattern_generator(dc, 1235 1242 odm_pipe, 1236 1243 test_pattern, 1237 1244 test_pattern_color_space, 1238 1245 stream->timing.display_color_depth, 1239 1246 &black_color, 1240 - odm_slice_width, 1241 - v_active, 1242 - offset); 1243 - offset += odm_slice_width; 1247 + odm_slice_src.width, 1248 + odm_slice_src.height, 1249 + odm_slice_src.x); 1244 1250 odm_pipe = odm_pipe->next_odm_pipe; 1245 1251 } 1246 1252 1253 + odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe); 1247 1254 dc->hwss.set_disp_pattern_generator(dc, 1248 1255 odm_pipe, 1249 1256 test_pattern, 1250 1257 test_pattern_color_space, 1251 1258 stream->timing.display_color_depth, 1252 1259 &black_color, 1253 - last_odm_slice_width, 1254 - v_active, 1255 - offset); 1260 + odm_slice_src.width, 1261 + odm_slice_src.height, 1262 + odm_slice_src.x); 1256 1263 1257 1264 if (!blank) 1258 1265 if (stream_res->abm) {
+3 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c
··· 160 160 struct pipe_ctx *odm_pipe; 161 161 int opp_cnt = 0; 162 162 int opp_inst[MAX_PIPES] = {0}; 163 + int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 164 + int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 163 165 164 166 opp_cnt = get_odm_config(pipe_ctx, opp_inst); 165 167 ··· 169 167 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 170 168 pipe_ctx->stream_res.tg, 171 169 opp_inst, opp_cnt, 172 - &pipe_ctx->stream->timing); 170 + odm_slice_width, last_odm_slice_width); 173 171 else 174 172 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 175 173 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+7 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
··· 1078 1078 struct pipe_ctx *odm_pipe; 1079 1079 int opp_cnt = 0; 1080 1080 int opp_inst[MAX_PIPES] = {0}; 1081 + int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 1082 + int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 1081 1083 1082 1084 opp_cnt = get_odm_config(pipe_ctx, opp_inst); 1083 1085 ··· 1087 1085 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 1088 1086 pipe_ctx->stream_res.tg, 1089 1087 opp_inst, opp_cnt, 1090 - &pipe_ctx->stream->timing); 1088 + odm_slice_width, last_odm_slice_width); 1091 1089 else 1092 1090 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 1093 1091 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); ··· 1096 1094 odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( 1097 1095 odm_pipe->stream_res.opp, 1098 1096 true); 1097 + odm_pipe->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 1098 + odm_pipe->stream_res.opp, 1099 + pipe_ctx->stream->timing.pixel_encoding, 1100 + resource_is_pipe_type(odm_pipe, OTG_MASTER)); 1099 1101 } 1100 1102 1101 1103 if (pipe_ctx->stream_res.dsc) {
+3 -1
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
··· 451 451 struct pipe_ctx *odm_pipe; 452 452 int opp_cnt = 0; 453 453 int opp_inst[MAX_PIPES] = {0}; 454 + int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 455 + int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 454 456 455 457 opp_cnt = get_odm_config(pipe_ctx, opp_inst); 456 458 ··· 460 458 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 461 459 pipe_ctx->stream_res.tg, 462 460 opp_inst, opp_cnt, 463 - &pipe_ctx->stream->timing); 461 + odm_slice_width, last_odm_slice_width); 464 462 else 465 463 pipe_ctx->stream_res.tg->funcs->set_odm_bypass( 466 464 pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
+33 -15
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
··· 744 744 unsigned int *tmds_div, 745 745 int *opp_inst, 746 746 int *opp_cnt, 747 + struct pipe_ctx *opp_heads[MAX_PIPES], 747 748 bool *manual_mode, 748 749 struct drr_params *params, 749 750 unsigned int *event_triggers) 750 751 { 751 752 struct dc_stream_state *stream = pipe_ctx->stream; 752 - struct pipe_ctx *odm_pipe; 753 + int i; 753 754 754 755 if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal)) 755 756 dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div); 756 757 757 - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) { 758 - opp_inst[*opp_cnt] = odm_pipe->stream_res.opp->inst; 759 - (*opp_cnt)++; 760 - } 758 + *opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads); 759 + for (i = 0; i < *opp_cnt; i++) 760 + opp_inst[i] = opp_heads[i]->stream_res.opp->inst; 761 761 762 762 if (dc_is_tmds_signal(stream->signal)) { 763 763 stream->link->phy_state.symclk_ref_cnts.otg = 1; ··· 786 786 struct dc_stream_state *stream = pipe_ctx->stream; 787 787 struct drr_params params = {0}; 788 788 unsigned int event_triggers = 0; 789 - struct pipe_ctx *odm_pipe; 790 789 int opp_cnt = 1; 791 - int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst }; 790 + int opp_inst[MAX_PIPES] = {0}; 791 + struct pipe_ctx *opp_heads[MAX_PIPES]; 792 792 bool manual_mode; 793 793 unsigned int tmds_div = PIXEL_RATE_DIV_NA; 794 794 unsigned int unused_div = PIXEL_RATE_DIV_NA; 795 + int odm_slice_width; 796 + int last_odm_slice_width; 797 + int i; 795 798 796 799 if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER)) 797 800 return DC_OK; 798 801 799 802 enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst, 800 - &opp_cnt, &manual_mode, &params, &event_triggers); 803 + &opp_cnt, opp_heads, &manual_mode, &params, &event_triggers); 801 804 802 805 if (dc->res_pool->dccg->funcs->set_pixel_rate_div) { 803 806 dc->res_pool->dccg->funcs->set_pixel_rate_div( ··· 810 807 811 808 /* TODO check if timing_changed, disable stream if timing changed */ 812 809 813 - if (opp_cnt > 1) 810 + if (opp_cnt > 1) { 811 + odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false); 812 + last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true); 814 813 pipe_ctx->stream_res.tg->funcs->set_odm_combine( 815 814 pipe_ctx->stream_res.tg, 816 815 opp_inst, opp_cnt, 817 - &pipe_ctx->stream->timing); 816 + odm_slice_width, last_odm_slice_width); 817 + } 818 818 819 819 /* HW program guide assume display already disable 820 820 * by unplug sequence. OTG assume stop. ··· 846 840 pipe_ctx->stream->signal, 847 841 true); 848 842 849 - for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) 850 - odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control( 851 - odm_pipe->stream_res.opp, 843 + for (i = 0; i < opp_cnt; i++) { 844 + opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control( 845 + opp_heads[i]->stream_res.opp, 852 846 true); 847 + opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 848 + opp_heads[i]->stream_res.opp, 849 + stream->timing.pixel_encoding, 850 + resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 851 + } 853 852 854 853 pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control( 855 854 pipe_ctx->stream_res.opp, ··· 1604 1593 struct pipe_ctx *opp_heads[MAX_PIPES]; 1605 1594 int opp_inst[MAX_PIPES] = {0}; 1606 1595 int opp_head_count; 1596 + int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false); 1597 + int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true); 1607 1598 int i; 1608 1599 1609 1600 opp_head_count = resource_get_opp_heads_for_otg_master( ··· 1617 1604 otg_master->stream_res.tg->funcs->set_odm_combine( 1618 1605 otg_master->stream_res.tg, 1619 1606 opp_inst, opp_head_count, 1620 - &otg_master->stream->timing); 1607 + odm_slice_width, last_odm_slice_width); 1621 1608 else 1622 1609 otg_master->stream_res.tg->funcs->set_odm_bypass( 1623 1610 otg_master->stream_res.tg, 1624 1611 &otg_master->stream->timing); 1625 1612 1626 - for (i = 0; i < opp_head_count; i++) 1613 + for (i = 0; i < opp_head_count; i++) { 1627 1614 opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control( 1628 1615 opp_heads[i]->stream_res.opp, 1629 1616 true); 1617 + opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel( 1618 + opp_heads[i]->stream_res.opp, 1619 + opp_heads[i]->stream->timing.pixel_encoding, 1620 + resource_is_pipe_type(opp_heads[i], OTG_MASTER)); 1621 + } 1630 1622 1631 1623 update_dsc_for_odm_change(dc, context, otg_master); 1632 1624
+6 -1
drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
··· 346 346 347 347 void (*opp_program_left_edge_extra_pixel)( 348 348 struct output_pixel_processor *opp, 349 - bool count); 349 + enum dc_pixel_encoding pixel_encoding, 350 + bool is_primary); 350 351 352 + uint32_t (*opp_get_left_edge_extra_pixel_count)( 353 + struct output_pixel_processor *opp, 354 + enum dc_pixel_encoding pixel_encoding, 355 + bool is_primary); 351 356 }; 352 357 353 358 #endif
+1 -1
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
··· 313 313 * OPP(s) and turn on/off ODM memory. 314 314 */ 315 315 void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt, 316 - struct dc_crtc_timing *timing); 316 + int segment_width, int last_segment_width); 317 317 void (*get_odm_combine_segments)(struct timing_generator *tg, int *odm_segments); 318 318 void (*set_h_timing_div_manual_mode)(struct timing_generator *optc, bool manual_mode); 319 319 void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params);
+2 -4
drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c
··· 179 179 } 180 180 181 181 void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 182 - struct dc_crtc_timing *timing) 182 + int segment_width, int last_segment_width) 183 183 { 184 184 struct optc *optc1 = DCN10TG_FROM_TG(optc); 185 - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) 186 - / opp_cnt; 187 185 uint32_t memory_mask; 188 186 189 187 ASSERT(opp_cnt == 2); ··· 211 213 OPTC_SEG1_SRC_SEL, opp_id[1]); 212 214 213 215 REG_UPDATE(OPTC_WIDTH_CONTROL, 214 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 216 + OPTC_SEGMENT_WIDTH, segment_width); 215 217 216 218 REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1); 217 219 optc1->opp_count = opp_cnt;
+1 -1
drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h
··· 105 105 const struct dc_crtc_timing *dc_crtc_timing); 106 106 107 107 void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 108 - struct dc_crtc_timing *timing); 108 + int segment_width, int last_segment_width); 109 109 110 110 void optc2_get_optc_source(struct timing_generator *optc, 111 111 uint32_t *num_of_src_opp,
+2 -4
drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
··· 216 216 } 217 217 218 218 void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 219 - struct dc_crtc_timing *timing) 219 + int segment_width, int last_segment_width) 220 220 { 221 221 struct optc *optc1 = DCN10TG_FROM_TG(optc); 222 - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) 223 - / opp_cnt; 224 222 uint32_t memory_mask = 0; 225 223 226 224 /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic ··· 265 267 } 266 268 267 269 REG_UPDATE(OPTC_WIDTH_CONTROL, 268 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 270 + OPTC_SEGMENT_WIDTH, segment_width); 269 271 270 272 REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); 271 273 optc1->opp_count = opp_cnt;
+1 -1
drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
··· 352 352 void optc3_set_odm_bypass(struct timing_generator *optc, 353 353 const struct dc_crtc_timing *dc_crtc_timing); 354 354 void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 355 - struct dc_crtc_timing *timing); 355 + int segment_width, int last_segment_width); 356 356 void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc); 357 357 void optc3_tg_init(struct timing_generator *optc); 358 358 void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max);
+3 -5
drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
··· 41 41 optc1->tg_shift->field_name, optc1->tg_mask->field_name 42 42 43 43 static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 44 - struct dc_crtc_timing *timing) 44 + int segment_width, int last_segment_width) 45 45 { 46 46 struct optc *optc1 = DCN10TG_FROM_TG(optc); 47 - int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right) 48 - / opp_cnt; 49 47 uint32_t memory_mask = 0; 50 - int mem_count_per_opp = (mpcc_hactive + 2559) / 2560; 48 + int mem_count_per_opp = (segment_width + 2559) / 2560; 51 49 52 50 /* Assume less than 6 pipes */ 53 51 if (opp_cnt == 4) { ··· 83 85 } 84 86 85 87 REG_UPDATE(OPTC_WIDTH_CONTROL, 86 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 88 + OPTC_SEGMENT_WIDTH, segment_width); 87 89 88 90 REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); 89 91 optc1->opp_count = opp_cnt;
+3 -4
drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
··· 48 48 */ 49 49 50 50 static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 51 - struct dc_crtc_timing *timing) 51 + int segment_width, int last_segment_width) 52 52 { 53 53 struct optc *optc1 = DCN10TG_FROM_TG(optc); 54 54 uint32_t memory_mask = 0; 55 - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; 56 - int mpcc_hactive = h_active / opp_cnt; 55 + int h_active = segment_width * opp_cnt; 57 56 /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ 58 57 int odm_mem_count = (h_active + 2047) / 2048; 59 58 ··· 95 96 } 96 97 97 98 REG_UPDATE(OPTC_WIDTH_CONTROL, 98 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 99 + OPTC_SEGMENT_WIDTH, segment_width); 99 100 100 101 REG_UPDATE(OTG_H_TIMING_CNTL, 101 102 OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
+3 -4
drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
··· 43 43 optc1->tg_shift->field_name, optc1->tg_mask->field_name 44 44 45 45 static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 46 - struct dc_crtc_timing *timing) 46 + int segment_width, int last_segment_width) 47 47 { 48 48 struct optc *optc1 = DCN10TG_FROM_TG(optc); 49 49 uint32_t memory_mask = 0; 50 - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; 51 - int mpcc_hactive = h_active / opp_cnt; 50 + int h_active = segment_width * opp_cnt; 52 51 /* Each memory instance is 2048x(32x2) bits to support half line of 4096 */ 53 52 int odm_mem_count = (h_active + 2047) / 2048; 54 53 ··· 90 91 } 91 92 92 93 REG_UPDATE(OPTC_WIDTH_CONTROL, 93 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 94 + OPTC_SEGMENT_WIDTH, segment_width); 94 95 95 96 REG_UPDATE(OTG_H_TIMING_CNTL, 96 97 OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
+3 -4
drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
··· 55 55 * Return: void. 56 56 */ 57 57 static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt, 58 - struct dc_crtc_timing *timing) 58 + int segment_width, int last_segment_width) 59 59 { 60 60 struct optc *optc1 = DCN10TG_FROM_TG(optc); 61 61 uint32_t memory_mask = 0; 62 - int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right; 63 - int mpcc_hactive = h_active / opp_cnt; 62 + int h_active = segment_width * opp_cnt; 64 63 /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */ 65 64 int odm_mem_count = (h_active + 2047) / 2048; 66 65 ··· 102 103 } 103 104 104 105 REG_UPDATE(OPTC_WIDTH_CONTROL, 105 - OPTC_SEGMENT_WIDTH, mpcc_hactive); 106 + OPTC_SEGMENT_WIDTH, segment_width); 106 107 107 108 REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, opp_cnt - 1); 108 109 optc1->opp_count = opp_cnt;
+6 -16
drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c
··· 102 102 } 103 103 104 104 static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id, 105 - int opp_cnt, struct dc_crtc_timing *timing) 105 + int opp_cnt, int segment_width, int last_segment_width) 106 106 { 107 107 struct optc *optc1 = DCN10TG_FROM_TG(optc); 108 - uint32_t h_active = timing->h_addressable + 109 - timing->h_border_left + timing->h_border_right; 108 + uint32_t h_active = segment_width * (opp_cnt - 1) + last_segment_width; 110 109 uint32_t odm_mem_bit_map = decide_odm_mem_bit_map( 111 110 opp_id, opp_cnt, h_active); 112 - uint32_t odm_segment_width; 113 - uint32_t odm_segment_width_last; 114 - bool is_two_pixels_per_container = optc->funcs->is_two_pixels_per_container(timing); 115 - 116 - odm_segment_width = h_active / opp_cnt; 117 - if ((odm_segment_width % 2) && is_two_pixels_per_container) 118 - odm_segment_width++; 119 - odm_segment_width_last = 120 - h_active - odm_segment_width * (opp_cnt - 1); 121 111 122 112 REG_SET(OPTC_MEMORY_CONFIG, 0, 123 113 OPTC_MEM_SEL, odm_mem_bit_map); ··· 119 129 OPTC_SEG0_SRC_SEL, opp_id[0], 120 130 OPTC_SEG1_SRC_SEL, opp_id[1]); 121 131 REG_UPDATE(OPTC_WIDTH_CONTROL, 122 - OPTC_SEGMENT_WIDTH, odm_segment_width); 132 + OPTC_SEGMENT_WIDTH, segment_width); 123 133 124 134 REG_UPDATE(OTG_H_TIMING_CNTL, 125 135 OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY2); ··· 131 141 OPTC_SEG1_SRC_SEL, opp_id[1], 132 142 OPTC_SEG2_SRC_SEL, opp_id[2]); 133 143 REG_UPDATE(OPTC_WIDTH_CONTROL, 134 - OPTC_SEGMENT_WIDTH, odm_segment_width); 144 + OPTC_SEGMENT_WIDTH, segment_width); 135 145 REG_UPDATE(OPTC_WIDTH_CONTROL2, 136 146 OPTC_SEGMENT_WIDTH_LAST, 137 - odm_segment_width_last); 147 + last_segment_width); 138 148 /* In ODM combine 3:1 mode ODM packs 4 pixels per data transfer 139 149 * so OTG_H_TIMING_DIV_MODE should be configured to 140 150 * H_TIMING_DIV_BY4 even though ODM combines 3 OPP inputs, it ··· 151 161 OPTC_SEG2_SRC_SEL, opp_id[2], 152 162 OPTC_SEG3_SRC_SEL, opp_id[3]); 153 163 REG_UPDATE(OPTC_WIDTH_CONTROL, 154 - OPTC_SEGMENT_WIDTH, odm_segment_width); 164 + OPTC_SEGMENT_WIDTH, segment_width); 155 165 REG_UPDATE(OTG_H_TIMING_CNTL, 156 166 OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY4); 157 167 break;