]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Add left edge pixel for YCbCr422/420 + ODM pipe split
authorWenjing Liu <wenjing.liu@amd.com>
Thu, 25 Apr 2024 16:13:24 +0000 (12:13 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 13 May 2024 19:46:55 +0000 (15:46 -0400)
[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>
20 files changed:
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_opp.h
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_opp.c
drivers/gpu/drm/amd/display/dc/hwss/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn314/dcn314_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn35/dcn35_hwseq.c
drivers/gpu/drm/amd/display/dc/hwss/dcn401/dcn401_hwseq.c
drivers/gpu/drm/amd/display/dc/inc/hw/opp.h
drivers/gpu/drm/amd/display/dc/inc/hw/timing_generator.h
drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn20/dcn20_optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn30/dcn30_optc.h
drivers/gpu/drm/amd/display/dc/optc/dcn31/dcn31_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn314/dcn314_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn32/dcn32_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn35/dcn35_optc.c
drivers/gpu/drm/amd/display/dc/optc/dcn401/dcn401_optc.c

index fd03d7129ffa20832227a3601390410b0f673933..fd624b1fee25a1ba2edf35c15e09e8639e7c09b6 100644 (file)
@@ -2110,12 +2110,19 @@ struct rect resource_get_odm_slice_src_rect(struct pipe_ctx *pipe_ctx)
        struct rect odm_slice_dst;
        struct rect odm_slice_src;
        struct pipe_ctx *opp_head = resource_get_opp_head(pipe_ctx);
+       struct output_pixel_processor *opp = opp_head->stream_res.opp;
        uint32_t left_edge_extra_pixel_count;
 
        odm_slice_dst = resource_get_odm_slice_dst_rect(opp_head);
        odm_slice_src = odm_slice_dst;
 
-       left_edge_extra_pixel_count = 0;
+       if (opp->funcs->opp_get_left_edge_extra_pixel_count)
+               left_edge_extra_pixel_count =
+                               opp->funcs->opp_get_left_edge_extra_pixel_count(
+                                               opp, pipe_ctx->stream->timing.pixel_encoding,
+                                               resource_is_pipe_type(opp_head, OTG_MASTER));
+       else
+               left_edge_extra_pixel_count = 0;
 
        odm_slice_src.x -= left_edge_extra_pixel_count;
        odm_slice_src.width += left_edge_extra_pixel_count;
index fbf1b6370eb23af3820fa092393229296a49a843..f5fe0cac7cb064c2fc42a169fe375d05a3d57d14 100644 (file)
@@ -23,6 +23,7 @@
  *
  */
 
+#include "core_types.h"
 #include "dm_services.h"
 #include "dcn20_opp.h"
 #include "reg_helper.h"
@@ -350,19 +351,32 @@ bool opp2_dpg_is_pending(struct output_pixel_processor *opp)
        return (dpg_en == 1 && double_buffer_pending == 1);
 }
 
-void opp2_program_left_edge_extra_pixel (
+void opp2_program_left_edge_extra_pixel(
                struct output_pixel_processor *opp,
-               bool count)
+               enum dc_pixel_encoding pixel_encoding,
+               bool is_primary)
 {
        struct dcn20_opp *oppn20 = TO_DCN20_OPP(opp);
+       uint32_t count = opp2_get_left_edge_extra_pixel_count(opp, pixel_encoding, is_primary);
 
-       /* Specifies the number of extra left edge pixels that are supplied to
+       /*
+        * Specifies the number of extra left edge pixels that are supplied to
         * the 422 horizontal chroma sub-sample filter.
-        * Note that when left edge pixel is not "0", fmt pixel encoding can be in either 420 or 422 mode
-        * */
+        */
        REG_UPDATE(FMT_422_CONTROL, FMT_LEFT_EDGE_EXTRA_PIXEL_COUNT, count);
 }
 
+uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp,
+               enum dc_pixel_encoding pixel_encoding, bool is_primary)
+{
+       if ((pixel_encoding == PIXEL_ENCODING_YCBCR422 || pixel_encoding == PIXEL_ENCODING_YCBCR420) &&
+                       !opp->ctx->dc->debug.force_chroma_subsampling_1tap &&
+                       !is_primary)
+               return 1;
+       else
+               return 0;
+}
+
 /*****************************************/
 /* Constructor, Destructor               */
 /*****************************************/
@@ -380,6 +394,7 @@ static struct opp_funcs dcn20_opp_funcs = {
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
+               .opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count,
 };
 
 void dcn20_opp_construct(struct dcn20_opp *oppn20,
index 8f186abd558db45a09dc92776e0b627fb1e0958b..34936e6c49f3fb7ceeeb9090b5bbd9c6ac49cdfe 100644 (file)
@@ -167,6 +167,8 @@ void opp2_dpg_set_blank_color(
 
 void opp2_program_left_edge_extra_pixel (
                struct output_pixel_processor *opp,
-               bool count);
+               enum dc_pixel_encoding pixel_encoding, bool is_primary);
 
+uint32_t opp2_get_left_edge_extra_pixel_count(struct output_pixel_processor *opp,
+               enum dc_pixel_encoding pixel_encoding, bool is_primary);
 #endif
index 6a71ba3dfc6327969d8f973913fee9c80d6aa387..e83367a9b6b38b1585eb9808a2e616de92924cf2 100644 (file)
@@ -54,6 +54,7 @@ static struct opp_funcs dcn201_opp_funcs = {
                .opp_dpg_set_blank_color = opp2_dpg_set_blank_color,
                .opp_destroy = opp1_destroy,
                .opp_program_left_edge_extra_pixel = opp2_program_left_edge_extra_pixel,
+               .opp_get_left_edge_extra_pixel_count = opp2_get_left_edge_extra_pixel_count,
 };
 
 void dcn201_opp_construct(struct dcn201_opp *oppn201,
index 5623a48cf3fd98601c80fdf210d010e7b9ef2293..d085c9ff9d382a8cce60816fc5201b439c06b8c5 100644 (file)
@@ -820,9 +820,8 @@ enum dc_status dcn20_enable_stream_timing(
        struct dc_stream_state *stream = pipe_ctx->stream;
        struct drr_params params = {0};
        unsigned int event_triggers = 0;
-       struct pipe_ctx *odm_pipe;
        int opp_cnt = 1;
-       int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
+       int opp_inst[MAX_PIPES] = {0};
        bool interlace = stream->timing.flags.INTERLACE;
        int i;
        struct mpc_dwb_flow_control flow_control;
@@ -832,6 +831,9 @@ enum dc_status dcn20_enable_stream_timing(
        bool rate_control_2x_pclk = (interlace || is_two_pixels_per_container);
        unsigned int k1_div = PIXEL_RATE_DIV_NA;
        unsigned int k2_div = PIXEL_RATE_DIV_NA;
+       int odm_slice_width;
+       int last_odm_slice_width;
+       struct pipe_ctx *opp_heads[MAX_PIPES];
 
        if (hws->funcs.calculate_dccg_k1_k2_values && dc->res_pool->dccg->funcs->set_pixel_rate_div) {
                hws->funcs.calculate_dccg_k1_k2_values(pipe_ctx, &k1_div, &k2_div);
@@ -850,16 +852,17 @@ enum dc_status dcn20_enable_stream_timing(
 
        /* TODO check if timing_changed, disable stream if timing changed */
 
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-               opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
-               opp_cnt++;
-       }
+       opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
+       for (i = 0; i < opp_cnt; i++)
+               opp_inst[opp_cnt] = opp_heads[i]->stream_res.opp->inst;
 
+       odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+       last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
        if (opp_cnt > 1)
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
-                               opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               opp_inst, opp_cnt, odm_slice_width,
+                               last_odm_slice_width);
 
        /* HW program guide assume display already disable
         * by unplug sequence. OTG assume stop.
@@ -927,14 +930,15 @@ enum dc_status dcn20_enable_stream_timing(
                }
        }
 
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-               odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
-                               odm_pipe->stream_res.opp,
+       for (i = 0; i < opp_cnt; i++) {
+               opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
+                               opp_heads[i]->stream_res.opp,
                                true);
-
-       pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
-                       pipe_ctx->stream_res.opp,
-                       true);
+               opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
+                               opp_heads[i]->stream_res.opp,
+                               stream->timing.pixel_encoding,
+                               resource_is_pipe_type(opp_heads[i], OTG_MASTER));
+       }
 
        hws->funcs.blank_pixel_data(dc, pipe_ctx, true);
 
@@ -1175,6 +1179,8 @@ void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 1;
        int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
+       int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+       int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
 
        for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
                opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
@@ -1185,7 +1191,7 @@ void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
                                opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
        else
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
@@ -1203,12 +1209,7 @@ void dcn20_blank_pixel_data(
        enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
        enum controller_dp_color_space test_pattern_color_space = CONTROLLER_DP_COLOR_SPACE_UDEFINED;
        struct pipe_ctx *odm_pipe;
-       int odm_cnt = 1;
-       int h_active = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
-       int v_active = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
-       int odm_slice_width, last_odm_slice_width, offset = 0;
-       bool is_two_pixels_per_container =
-                       pipe_ctx->stream_res.tg->funcs->is_two_pixels_per_container(&stream->timing);
+       struct rect odm_slice_src;
 
        if (stream->link->test_pattern_enabled)
                return;
@@ -1216,13 +1217,6 @@ void dcn20_blank_pixel_data(
        /* get opp dpg blank color */
        color_space_to_black_color(dc, color_space, &black_color);
 
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-               odm_cnt++;
-       odm_slice_width = h_active / odm_cnt;
-       if ((odm_slice_width % 2) && is_two_pixels_per_container)
-               odm_slice_width++;
-       last_odm_slice_width = h_active - odm_slice_width * (odm_cnt - 1);
-
        if (blank) {
                dc->hwss.set_abm_immediate_disable(pipe_ctx);
 
@@ -1237,28 +1231,29 @@ void dcn20_blank_pixel_data(
        odm_pipe = pipe_ctx;
 
        while (odm_pipe->next_odm_pipe) {
+               odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
                dc->hwss.set_disp_pattern_generator(dc,
                                odm_pipe,
                                test_pattern,
                                test_pattern_color_space,
                                stream->timing.display_color_depth,
                                &black_color,
-                               odm_slice_width,
-                               v_active,
-                               offset);
-               offset += odm_slice_width;
+                               odm_slice_src.width,
+                               odm_slice_src.height,
+                               odm_slice_src.x);
                odm_pipe = odm_pipe->next_odm_pipe;
        }
 
+       odm_slice_src = resource_get_odm_slice_src_rect(odm_pipe);
        dc->hwss.set_disp_pattern_generator(dc,
                        odm_pipe,
                        test_pattern,
                        test_pattern_color_space,
                        stream->timing.display_color_depth,
                        &black_color,
-                       last_odm_slice_width,
-                       v_active,
-                       offset);
+                       odm_slice_src.width,
+                       odm_slice_src.height,
+                       odm_slice_src.x);
 
        if (!blank)
                if (stream_res->abm) {
index 0b12a69e2df0fa253de583884a9e01531a729612..1d853241ca32292b17352106ec3602c59ef200e8 100644 (file)
@@ -160,6 +160,8 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 0;
        int opp_inst[MAX_PIPES] = {0};
+       int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+       int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
@@ -167,7 +169,7 @@ void dcn314_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
                                opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
        else
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
index df0fceb11ae186b67a5c81c1fd395602e57d1361..7aaef3709baa7f5719ee3fa4d68fd51d07fc08e4 100644 (file)
@@ -1078,6 +1078,8 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 0;
        int opp_inst[MAX_PIPES] = {0};
+       int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+       int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
@@ -1085,7 +1087,7 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
                                opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
        else
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
@@ -1094,6 +1096,10 @@ void dcn32_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
                                odm_pipe->stream_res.opp,
                                true);
+               odm_pipe->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
+                               odm_pipe->stream_res.opp,
+                               pipe_ctx->stream->timing.pixel_encoding,
+                               resource_is_pipe_type(odm_pipe, OTG_MASTER));
        }
 
        if (pipe_ctx->stream_res.dsc) {
index bddcd23a27279165aed2217927e18e088da36541..6d40e93b5497a85c29a1accd9e0723687b698c3e 100644 (file)
@@ -451,6 +451,8 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
        struct pipe_ctx *odm_pipe;
        int opp_cnt = 0;
        int opp_inst[MAX_PIPES] = {0};
+       int odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+       int last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
 
        opp_cnt = get_odm_config(pipe_ctx, opp_inst);
 
@@ -458,7 +460,7 @@ void dcn35_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
                                opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
        else
                pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
                                pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
index 5b87186598e6aa22322aafd85ed97969fd0bc032..c01cf2a2f786a95c71d007cb4507895fe277bc05 100644 (file)
@@ -744,20 +744,20 @@ static void enable_stream_timing_calc(
                unsigned int *tmds_div,
                int *opp_inst,
                int *opp_cnt,
+               struct pipe_ctx *opp_heads[MAX_PIPES],
                bool *manual_mode,
                struct drr_params *params,
                unsigned int *event_triggers)
 {
        struct dc_stream_state *stream = pipe_ctx->stream;
-       struct pipe_ctx *odm_pipe;
+       int i;
 
        if (dc_is_tmds_signal(stream->signal) || dc_is_virtual_signal(stream->signal))
                dcn401_calculate_dccg_tmds_div_value(pipe_ctx, tmds_div);
 
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
-               opp_inst[*opp_cnt] = odm_pipe->stream_res.opp->inst;
-               (*opp_cnt)++;
-       }
+       *opp_cnt = resource_get_opp_heads_for_otg_master(pipe_ctx, &context->res_ctx, opp_heads);
+       for (i = 0; i < *opp_cnt; i++)
+               opp_inst[i] = opp_heads[i]->stream_res.opp->inst;
 
        if (dc_is_tmds_signal(stream->signal)) {
                stream->link->phy_state.symclk_ref_cnts.otg = 1;
@@ -786,18 +786,21 @@ enum dc_status dcn401_enable_stream_timing(
        struct dc_stream_state *stream = pipe_ctx->stream;
        struct drr_params params = {0};
        unsigned int event_triggers = 0;
-       struct pipe_ctx *odm_pipe;
        int opp_cnt = 1;
-       int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
+       int opp_inst[MAX_PIPES] = {0};
+       struct pipe_ctx *opp_heads[MAX_PIPES];
        bool manual_mode;
        unsigned int tmds_div = PIXEL_RATE_DIV_NA;
        unsigned int unused_div = PIXEL_RATE_DIV_NA;
+       int odm_slice_width;
+       int last_odm_slice_width;
+       int i;
 
        if (!resource_is_pipe_type(pipe_ctx, OTG_MASTER))
                return DC_OK;
 
        enable_stream_timing_calc(pipe_ctx, context, dc, &tmds_div, opp_inst,
-                       &opp_cnt, &manual_mode, &params, &event_triggers);
+                       &opp_cnt, opp_heads, &manual_mode, &params, &event_triggers);
 
        if (dc->res_pool->dccg->funcs->set_pixel_rate_div) {
                dc->res_pool->dccg->funcs->set_pixel_rate_div(
@@ -807,11 +810,14 @@ enum dc_status dcn401_enable_stream_timing(
 
        /* TODO check if timing_changed, disable stream if timing changed */
 
-       if (opp_cnt > 1)
+       if (opp_cnt > 1) {
+               odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, false);
+               last_odm_slice_width = resource_get_odm_slice_dst_width(pipe_ctx, true);
                pipe_ctx->stream_res.tg->funcs->set_odm_combine(
                                pipe_ctx->stream_res.tg,
                                opp_inst, opp_cnt,
-                               &pipe_ctx->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
+       }
 
        /* HW program guide assume display already disable
         * by unplug sequence. OTG assume stop.
@@ -840,10 +846,15 @@ enum dc_status dcn401_enable_stream_timing(
                        pipe_ctx->stream->signal,
                        true);
 
-       for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
-               odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
-                               odm_pipe->stream_res.opp,
+       for (i = 0; i < opp_cnt; i++) {
+               opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
+                               opp_heads[i]->stream_res.opp,
                                true);
+               opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
+                               opp_heads[i]->stream_res.opp,
+                               stream->timing.pixel_encoding,
+                               resource_is_pipe_type(opp_heads[i], OTG_MASTER));
+       }
 
        pipe_ctx->stream_res.opp->funcs->opp_pipe_clock_control(
                        pipe_ctx->stream_res.opp,
@@ -1593,6 +1604,8 @@ void dcn401_update_odm(struct dc *dc, struct dc_state *context,
        struct pipe_ctx *opp_heads[MAX_PIPES];
        int opp_inst[MAX_PIPES] = {0};
        int opp_head_count;
+       int odm_slice_width = resource_get_odm_slice_dst_width(otg_master, false);
+       int last_odm_slice_width = resource_get_odm_slice_dst_width(otg_master, true);
        int i;
 
        opp_head_count = resource_get_opp_heads_for_otg_master(
@@ -1604,16 +1617,21 @@ void dcn401_update_odm(struct dc *dc, struct dc_state *context,
                otg_master->stream_res.tg->funcs->set_odm_combine(
                                otg_master->stream_res.tg,
                                opp_inst, opp_head_count,
-                               &otg_master->stream->timing);
+                               odm_slice_width, last_odm_slice_width);
        else
                otg_master->stream_res.tg->funcs->set_odm_bypass(
                                otg_master->stream_res.tg,
                                &otg_master->stream->timing);
 
-       for (i = 0; i < opp_head_count; i++)
+       for (i = 0; i < opp_head_count; i++) {
                opp_heads[i]->stream_res.opp->funcs->opp_pipe_clock_control(
                                opp_heads[i]->stream_res.opp,
                                true);
+               opp_heads[i]->stream_res.opp->funcs->opp_program_left_edge_extra_pixel(
+                               opp_heads[i]->stream_res.opp,
+                               opp_heads[i]->stream->timing.pixel_encoding,
+                               resource_is_pipe_type(opp_heads[i], OTG_MASTER));
+       }
 
        update_dsc_for_odm_change(dc, context, otg_master);
 
index d89c92370d5b3a773f524ccfdeeb3d0d5691af63..127fb1a5165495637042051fdbdef11691880ad0 100644 (file)
@@ -346,8 +346,13 @@ struct opp_funcs {
 
        void (*opp_program_left_edge_extra_pixel)(
                        struct output_pixel_processor *opp,
-                       bool count);
+                       enum dc_pixel_encoding pixel_encoding,
+                       bool is_primary);
 
+       uint32_t (*opp_get_left_edge_extra_pixel_count)(
+                       struct output_pixel_processor *opp,
+                       enum dc_pixel_encoding pixel_encoding,
+                       bool is_primary);
 };
 
 #endif
index a347425c1da22d796a8023d693dda04b1686195d..cd4826f329c15e1938d31eb9edbb296d9c9cb116 100644 (file)
@@ -313,7 +313,7 @@ struct timing_generator_funcs {
         * OPP(s) and turn on/off ODM memory.
         */
        void (*set_odm_combine)(struct timing_generator *optc, int *opp_id, int opp_cnt,
-                       struct dc_crtc_timing *timing);
+                       int segment_width, int last_segment_width);
        void (*get_odm_combine_segments)(struct timing_generator *tg, int *odm_segments);
        void (*set_h_timing_div_manual_mode)(struct timing_generator *optc, bool manual_mode);
        void (*set_gsl)(struct timing_generator *optc, const struct gsl_params *params);
index 314a0cee08ae79354afe1d0b6de11558262e7742..43417cff2c9bcf0290576abcf289c810b83aad26 100644 (file)
@@ -179,11 +179,9 @@ void optc2_set_odm_bypass(struct timing_generator *optc,
 }
 
 void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
-                       / opp_cnt;
        uint32_t memory_mask;
 
        ASSERT(opp_cnt == 2);
@@ -213,7 +211,7 @@ void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c
                        OPTC_SEG1_SRC_SEL, opp_id[1]);
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_BY2, 1);
        optc1->opp_count = opp_cnt;
index 1f8bc7fce9fc62fa1efa2867b12a8e96582edec3..364034b190281bad90c706bfac71cc11bb2bb8b3 100644 (file)
@@ -105,7 +105,7 @@ void optc2_set_odm_bypass(struct timing_generator *optc,
                const struct dc_crtc_timing *dc_crtc_timing);
 
 void optc2_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing);
+               int segment_width, int last_segment_width);
 
 void optc2_get_optc_source(struct timing_generator *optc,
                uint32_t *num_of_src_opp,
index c805fd2a48a11fdf843b2f965930290cb98efec9..abcd03d7866843b9eaae5de71eb0bea6f2428975 100644 (file)
@@ -216,11 +216,9 @@ void optc3_set_odm_bypass(struct timing_generator *optc,
 }
 
 void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
-                       / opp_cnt;
        uint32_t memory_mask = 0;
 
        /* TODO: In pseudocode but does not affect maximus, delete comment if we dont need on asic
@@ -267,7 +265,7 @@ void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_c
        }
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
        optc1->opp_count = opp_cnt;
index d3a056c12b0dc794edf33f136e980bb9853d3b36..bda974d432ea6af56f27a6e4d71742137a7a5080 100644 (file)
@@ -352,7 +352,7 @@ void optc3_set_timing_db_mode(struct timing_generator *optc, bool enable);
 void optc3_set_odm_bypass(struct timing_generator *optc,
                const struct dc_crtc_timing *dc_crtc_timing);
 void optc3_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing);
+               int segment_width, int last_segment_width);
 void optc3_wait_drr_doublebuffer_pending_clear(struct timing_generator *optc);
 void optc3_tg_init(struct timing_generator *optc);
 void optc3_set_vtotal_min_max(struct timing_generator *optc, int vtotal_min, int vtotal_max);
index 84d2ba31e2cae1dbcb74df428485c65b2764de67..de83761edce85d7a492142bedcb663cc67b84f6c 100644 (file)
        optc1->tg_shift->field_name, optc1->tg_mask->field_name
 
 static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       int mpcc_hactive = (timing->h_addressable + timing->h_border_left + timing->h_border_right)
-                       / opp_cnt;
        uint32_t memory_mask = 0;
-       int mem_count_per_opp = (mpcc_hactive + 2559) / 2560;
+       int mem_count_per_opp = (segment_width + 2559) / 2560;
 
        /* Assume less than 6 pipes */
        if (opp_cnt == 4) {
@@ -85,7 +83,7 @@ static void optc31_set_odm_combine(struct timing_generator *optc, int *opp_id, i
        }
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_SET(OTG_H_TIMING_CNTL, 0, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
        optc1->opp_count = opp_cnt;
index 9022fb2ffca4ea03729100926bfd52c03647d364..633d62addd4d27b2527cb9a40c734ad9dfe3be93 100644 (file)
  */
 
 static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
        uint32_t memory_mask = 0;
-       int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
-       int mpcc_hactive = h_active / opp_cnt;
+       int h_active = segment_width * opp_cnt;
        /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */
        int odm_mem_count = (h_active + 2047) / 2048;
 
@@ -96,7 +95,7 @@ static void optc314_set_odm_combine(struct timing_generator *optc, int *opp_id,
        }
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_UPDATE(OTG_H_TIMING_CNTL,
                        OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
index c18d580279a88decd2094e5ed48d7f95115dcef1..6c837409df4298da8e764456fb6cadb90100eceb 100644 (file)
        optc1->tg_shift->field_name, optc1->tg_mask->field_name
 
 static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
        uint32_t memory_mask = 0;
-       int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
-       int mpcc_hactive = h_active / opp_cnt;
+       int h_active = segment_width * opp_cnt;
        /* Each memory instance is 2048x(32x2) bits to support half line of 4096 */
        int odm_mem_count = (h_active + 2047) / 2048;
 
@@ -91,7 +90,7 @@ static void optc32_set_odm_combine(struct timing_generator *optc, int *opp_id, i
        }
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_UPDATE(OTG_H_TIMING_CNTL,
                        OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
index cf8da22492dc4d9de32a2b4608c1a41dde0ae3c6..7c9faa507ec250dbd39729574ee6988f336bfd2c 100644 (file)
  * Return: void.
  */
 static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, int opp_cnt,
-               struct dc_crtc_timing *timing)
+               int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
        uint32_t memory_mask = 0;
-       int h_active = timing->h_addressable + timing->h_border_left + timing->h_border_right;
-       int mpcc_hactive = h_active / opp_cnt;
+       int h_active = segment_width * opp_cnt;
        /* Each memory instance is 2048x(314x2) bits to support half line of 4096 */
        int odm_mem_count = (h_active + 2047) / 2048;
 
@@ -103,7 +102,7 @@ static void optc35_set_odm_combine(struct timing_generator *optc, int *opp_id, i
        }
 
        REG_UPDATE(OPTC_WIDTH_CONTROL,
-                       OPTC_SEGMENT_WIDTH, mpcc_hactive);
+                       OPTC_SEGMENT_WIDTH, segment_width);
 
        REG_UPDATE(OTG_H_TIMING_CNTL, OTG_H_TIMING_DIV_MODE, opp_cnt - 1);
        optc1->opp_count = opp_cnt;
index 099658bcd77f0ec390fac68f618741532aaea98b..8ab788b6e6c1dd7128eb33c3ec41a143d82547e5 100644 (file)
@@ -102,22 +102,12 @@ static uint32_t decide_odm_mem_bit_map(int *opp_id, int opp_cnt, int h_active)
 }
 
 static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
-               int opp_cnt, struct dc_crtc_timing *timing)
+               int opp_cnt, int segment_width, int last_segment_width)
 {
        struct optc *optc1 = DCN10TG_FROM_TG(optc);
-       uint32_t h_active = timing->h_addressable +
-                       timing->h_border_left + timing->h_border_right;
+       uint32_t h_active = segment_width * (opp_cnt - 1) + last_segment_width;
        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);
@@ -129,7 +119,7 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
                                OPTC_SEG0_SRC_SEL, opp_id[0],
                                OPTC_SEG1_SRC_SEL, opp_id[1]);
                REG_UPDATE(OPTC_WIDTH_CONTROL,
-                                       OPTC_SEGMENT_WIDTH, odm_segment_width);
+                                       OPTC_SEGMENT_WIDTH, segment_width);
 
                REG_UPDATE(OTG_H_TIMING_CNTL,
                                OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY2);
@@ -141,10 +131,10 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
                                OPTC_SEG1_SRC_SEL, opp_id[1],
                                OPTC_SEG2_SRC_SEL, opp_id[2]);
                REG_UPDATE(OPTC_WIDTH_CONTROL,
-                               OPTC_SEGMENT_WIDTH, odm_segment_width);
+                               OPTC_SEGMENT_WIDTH, segment_width);
                REG_UPDATE(OPTC_WIDTH_CONTROL2,
                                OPTC_SEGMENT_WIDTH_LAST,
-                               odm_segment_width_last);
+                               last_segment_width);
                /* In ODM combine 3:1 mode ODM packs 4 pixels per data transfer
                 * so OTG_H_TIMING_DIV_MODE should be configured to
                 * H_TIMING_DIV_BY4 even though ODM combines 3 OPP inputs, it
@@ -161,7 +151,7 @@ static void optc401_set_odm_combine(struct timing_generator *optc, int *opp_id,
                                OPTC_SEG2_SRC_SEL, opp_id[2],
                                OPTC_SEG3_SRC_SEL, opp_id[3]);
                REG_UPDATE(OPTC_WIDTH_CONTROL,
-                                       OPTC_SEGMENT_WIDTH, odm_segment_width);
+                                       OPTC_SEGMENT_WIDTH, segment_width);
                REG_UPDATE(OTG_H_TIMING_CNTL,
                                OTG_H_TIMING_DIV_MODE, H_TIMING_DIV_BY4);
                break;