drm/amd/display: implement pipe type definition and adding accessors
authorWenjing Liu <wenjing.liu@amd.com>
Fri, 28 Jul 2023 17:42:37 +0000 (13:42 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Aug 2023 22:08:28 +0000 (18:08 -0400)
[why]
There is a lack of encapsulation of pipe connection representation in pipe context.
This has caused many challenging bugs and coding errors with repeated
logic to identify the same pipe type.

[how]
Formally define pipe types and provide getters to identify a pipe type and
find a pipe based on specific requirements. Update existing logic in non dcn
specific files and dcn32 and future versions to use the new accessors.

Reviewed-by: Jun Lei <jun.lei@amd.com>
Acked-by: Stylon Wang <stylon.wang@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>
19 files changed:
drivers/gpu/drm/amd/display/dc/core/dc.c
drivers/gpu/drm/amd/display/dc/core/dc_resource.c
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
drivers/gpu/drm/amd/display/dc/dce100/dce100_resource.c
drivers/gpu/drm/amd/display/dc/dce110/dce110_resource.c
drivers/gpu/drm/amd/display/dc/dce112/dce112_resource.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_resource.c
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_resource.c
drivers/gpu/drm/amd/display/dc/dcn201/dcn201_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource.c
drivers/gpu/drm/amd/display/dc/dcn32/dcn32_resource_helpers.c
drivers/gpu/drm/amd/display/dc/dml/calcs/dce_calcs.c
drivers/gpu/drm/amd/display/dc/dml/calcs/dcn_calcs.c
drivers/gpu/drm/amd/display/dc/dml/dcn20/dcn20_fpu.c
drivers/gpu/drm/amd/display/dc/dml/dcn32/dcn32_fpu.c
drivers/gpu/drm/amd/display/dc/inc/resource.h
drivers/gpu/drm/amd/display/dc/link/accessories/link_dp_cts.c
drivers/gpu/drm/amd/display/dc/link/link_dpms.c

index 508d5ea89b8b53623455123884b5f9a4e7d4f1ff..566d7045b2dea80a6670b4af8cb253c1e455f1ca 100644 (file)
@@ -586,18 +586,15 @@ dc_stream_forward_crc_window(struct dc_stream_state *stream,
 bool dc_stream_configure_crc(struct dc *dc, struct dc_stream_state *stream,
                             struct crc_params *crc_window, bool enable, bool continuous)
 {
-       int i;
        struct pipe_ctx *pipe;
        struct crc_params param;
        struct timing_generator *tg;
 
-       for (i = 0; i < MAX_PIPES; i++) {
-               pipe = &dc->current_state->res_ctx.pipe_ctx[i];
-               if (pipe->stream == stream && !pipe->top_pipe && !pipe->prev_odm_pipe)
-                       break;
-       }
+       pipe = resource_get_otg_master_for_stream(
+                       &dc->current_state->res_ctx, stream);
+
        /* Stream not found */
-       if (i == MAX_PIPES)
+       if (pipe == NULL)
                return false;
 
        /* By default, capture the full frame */
@@ -1064,7 +1061,7 @@ static void apply_ctx_interdependent_lock(struct dc *dc,
 
                        // Copied conditions that were previously in dce110_apply_ctx_for_surface
                        if (stream == pipe_ctx->stream) {
-                               if (!pipe_ctx->top_pipe &&
+                               if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) &&
                                        (pipe_ctx->plane_state || old_pipe_ctx->plane_state))
                                        dc->hwss.pipe_control_lock(dc, pipe_ctx, lock);
                        }
@@ -3164,7 +3161,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
        for (j = 0; j < dc->res_pool->pipe_count; j++) {
                struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
 
-               if (!pipe_ctx->top_pipe &&  !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {
+               if (resource_is_pipe_type(pipe_ctx, OTG_MASTER) && pipe_ctx->stream == stream) {
 
                        if (stream_update->periodic_interrupt && dc->hwss.setup_periodic_interrupt)
                                dc->hwss.setup_periodic_interrupt(dc, pipe_ctx);
@@ -3446,16 +3443,9 @@ static void commit_planes_for_stream_fast(struct dc *dc,
        struct pipe_ctx *top_pipe_to_program = NULL;
        dc_z10_restore(dc);
 
-       for (j = 0; j < dc->res_pool->pipe_count; j++) {
-               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
-
-               if (!pipe_ctx->top_pipe &&
-                       !pipe_ctx->prev_odm_pipe &&
-                       pipe_ctx->stream &&
-                       pipe_ctx->stream == stream) {
-                       top_pipe_to_program = pipe_ctx;
-               }
-       }
+       top_pipe_to_program = resource_get_otg_master_for_stream(
+                       &context->res_ctx,
+                       stream);
 
        if (dc->debug.visual_confirm) {
                for (i = 0; i < dc->res_pool->pipe_count; i++) {
@@ -3560,16 +3550,9 @@ static void commit_planes_for_stream(struct dc *dc,
                context_clock_trace(dc, context);
        }
 
-       for (j = 0; j < dc->res_pool->pipe_count; j++) {
-               struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
-
-               if (!pipe_ctx->top_pipe &&
-                       !pipe_ctx->prev_odm_pipe &&
-                       pipe_ctx->stream &&
-                       pipe_ctx->stream == stream) {
-                       top_pipe_to_program = pipe_ctx;
-               }
-       }
+       top_pipe_to_program = resource_get_otg_master_for_stream(
+                               &context->res_ctx,
+                               stream);
 
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *old_pipe = &dc->current_state->res_ctx.pipe_ctx[i];
index 853e5b99dd625bd6f28d21d4678c25be52f9e53d..f7b51aca602006411358c61723d76e051334f290 100644 (file)
@@ -732,10 +732,10 @@ static inline void get_vp_scan_direction(
                *flip_horz_scan_dir = !*flip_horz_scan_dir;
 }
 
-int get_num_mpc_splits(struct pipe_ctx *pipe)
+int resource_get_num_mpc_splits(const struct pipe_ctx *pipe)
 {
        int mpc_split_count = 0;
-       struct pipe_ctx *other_pipe = pipe->bottom_pipe;
+       const struct pipe_ctx *other_pipe = pipe->bottom_pipe;
 
        while (other_pipe && other_pipe->plane_state == pipe->plane_state) {
                mpc_split_count++;
@@ -750,40 +750,30 @@ int get_num_mpc_splits(struct pipe_ctx *pipe)
        return mpc_split_count;
 }
 
-int get_num_odm_splits(struct pipe_ctx *pipe)
+int resource_get_num_odm_splits(const struct pipe_ctx *pipe)
 {
        int odm_split_count = 0;
-       struct pipe_ctx *next_pipe = NULL;
 
-       while (pipe->top_pipe)
-               pipe = pipe->top_pipe;
+       pipe = resource_get_otg_master(pipe);
 
-       next_pipe = pipe->next_odm_pipe;
-       while (next_pipe) {
+       while (pipe->next_odm_pipe) {
                odm_split_count++;
-               next_pipe = next_pipe->next_odm_pipe;
-       }
-       pipe = pipe->prev_odm_pipe;
-       while (pipe) {
-               odm_split_count++;
-               pipe = pipe->prev_odm_pipe;
+               pipe = pipe->next_odm_pipe;
        }
        return odm_split_count;
 }
 
 static int get_odm_split_index(struct pipe_ctx *pipe_ctx)
 {
-       struct pipe_ctx *split_pipe = NULL;
        int index = 0;
 
-       while (pipe_ctx->top_pipe)
-               pipe_ctx = pipe_ctx->top_pipe;
-
-       split_pipe = pipe_ctx->prev_odm_pipe;
+       pipe_ctx = resource_get_opp_head(pipe_ctx);
+       if (!pipe_ctx)
+               return 0;
 
-       while (split_pipe) {
+       while (pipe_ctx->prev_odm_pipe) {
                index++;
-               split_pipe = split_pipe->prev_odm_pipe;
+               pipe_ctx = pipe_ctx->prev_odm_pipe;
        }
 
        return index;
@@ -854,7 +844,7 @@ static struct rect shift_rec(const struct rect *rec_in, int x, int y)
 static struct rect calculate_odm_slice_in_timing_active(struct pipe_ctx *pipe_ctx)
 {
        const struct dc_stream_state *stream = pipe_ctx->stream;
-       int odm_slice_count = get_num_odm_splits(pipe_ctx) + 1;
+       int odm_slice_count = resource_get_num_odm_splits(pipe_ctx) + 1;
        int odm_slice_idx = get_odm_split_index(pipe_ctx);
        bool is_last_odm_slice = (odm_slice_idx + 1) == odm_slice_count;
        int h_active = stream->timing.h_addressable +
@@ -972,7 +962,7 @@ static struct rect calculate_mpc_slice_in_timing_active(
                struct rect *plane_clip_rec)
 {
        const struct dc_stream_state *stream = pipe_ctx->stream;
-       int mpc_slice_count = get_num_mpc_splits(pipe_ctx) + 1;
+       int mpc_slice_count = resource_get_num_mpc_splits(pipe_ctx) + 1;
        int mpc_slice_idx = get_mpc_split_index(pipe_ctx);
        int epimo = mpc_slice_count - plane_clip_rec->width % mpc_slice_count - 1;
        struct rect mpc_rec;
@@ -1565,7 +1555,7 @@ enum dc_status resource_build_scaling_params_for_context(
        return DC_OK;
 }
 
-struct pipe_ctx *find_free_secondary_pipe_legacy(
+struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
                struct resource_context *res_ctx,
                const struct resource_pool *pool,
                const struct pipe_ctx *primary_pipe)
@@ -1631,7 +1621,7 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
                const struct pipe_ctx *cur_opp_head)
 {
        const struct pipe_ctx *cur_sec_dpp = cur_opp_head->bottom_pipe;
-       struct pipe_ctx *new_sec_dpp;
+       struct pipe_ctx *new_pipe;
        int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
 
        while (cur_sec_dpp) {
@@ -1639,9 +1629,8 @@ int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
                 * this is to avoid MPO pipe switching to different opp blending
                 * tree
                 */
-               new_sec_dpp = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
-               if (new_sec_dpp->plane_state == NULL &&
-                               new_sec_dpp->stream == NULL) {
+               new_pipe = &new_res_ctx->pipe_ctx[cur_sec_dpp->pipe_idx];
+               if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
                        free_pipe_idx = cur_sec_dpp->pipe_idx;
                        break;
                }
@@ -1657,17 +1646,15 @@ int recource_find_free_pipe_not_used_in_cur_res_ctx(
                const struct resource_pool *pool)
 {
        int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
-       const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp;
+       const struct pipe_ctx *new_pipe, *cur_pipe;
        int i;
 
        for (i = 0; i < pool->pipe_count; i++) {
-               cur_sec_dpp = &cur_res_ctx->pipe_ctx[i];
-               new_sec_dpp = &new_res_ctx->pipe_ctx[i];
+               cur_pipe = &cur_res_ctx->pipe_ctx[i];
+               new_pipe = &new_res_ctx->pipe_ctx[i];
 
-               if (cur_sec_dpp->plane_state == NULL &&
-                               cur_sec_dpp->stream == NULL &&
-                               new_sec_dpp->plane_state == NULL &&
-                               new_sec_dpp->stream == NULL) {
+               if (resource_is_pipe_type(cur_pipe, FREE_PIPE) &&
+                               resource_is_pipe_type(new_pipe, FREE_PIPE)) {
                        free_pipe_idx = i;
                        break;
                }
@@ -1682,18 +1669,17 @@ int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
                const struct resource_pool *pool)
 {
        int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
-       const struct pipe_ctx *new_sec_dpp, *cur_sec_dpp;
+       const struct pipe_ctx *new_pipe, *cur_pipe;
        int i;
 
        for (i = 0; i < pool->pipe_count; i++) {
-               cur_sec_dpp = &cur_res_ctx->pipe_ctx[i];
-               new_sec_dpp = &new_res_ctx->pipe_ctx[i];
-
-               if (cur_sec_dpp->plane_state &&
-                               cur_sec_dpp->top_pipe &&
-                               cur_sec_dpp->top_pipe->plane_state == cur_sec_dpp->plane_state &&
-                               new_sec_dpp->plane_state == NULL &&
-                               new_sec_dpp->stream == NULL) {
+               cur_pipe = &cur_res_ctx->pipe_ctx[i];
+               new_pipe = &new_res_ctx->pipe_ctx[i];
+
+               if (resource_is_pipe_type(cur_pipe, DPP_PIPE) &&
+                               !resource_is_pipe_type(cur_pipe, OPP_HEAD) &&
+                               resource_is_for_mpcc_combine(cur_pipe) &&
+                               resource_is_pipe_type(new_pipe, FREE_PIPE)) {
                        free_pipe_idx = i;
                        break;
                }
@@ -1706,14 +1692,13 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
                const struct resource_pool *pool)
 {
        int free_pipe_idx = FREE_PIPE_INDEX_NOT_FOUND;
-       const struct pipe_ctx *new_sec_dpp;
+       const struct pipe_ctx *new_pipe;
        int i;
 
        for (i = 0; i < pool->pipe_count; i++) {
-               new_sec_dpp = &new_res_ctx->pipe_ctx[i];
+               new_pipe = &new_res_ctx->pipe_ctx[i];
 
-               if (new_sec_dpp->plane_state == NULL &&
-                               new_sec_dpp->stream == NULL) {
+               if (resource_is_pipe_type(new_pipe, FREE_PIPE)) {
                        free_pipe_idx = i;
                        break;
                }
@@ -1722,51 +1707,83 @@ int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
        return free_pipe_idx;
 }
 
-/* TODO: Unify the pipe naming convention:
- *
- * OPP head pipe - the head pipe of an MPC blending tree with a functional OPP
- * feeding to an OTG. OPP head pipe is by convention the top most pipe. i.e.
- * pipe's top_pipe is NULL.
- *
- * OTG master pipe - the master pipe of its OPP head pipes with a functional
- * OTG. It merges all its OPP head pipes pixel data from their MPCs in ODM block
- * and output to backend DIG. OTG master pipe is by convention the top most pipe
- * of the first odm slice. i.e. pipe's top_pipe is NULL and pipe's prev_odm_pipe
- * is NULL.
- *
- * Secondary OPP head pipe - an OPP head pipe which is not an OTG master pipe.
- * Its output feeds to another OTG master pipe. i.e pipe's top_pipe is NULL and
- * pipe's prev_odm_pipe is not NULL.
- *
- * Secondary DPP pipe - the pipe with a functional DPP outputting to another OPP
- * head pipe's MPC. Its output is a secondary layer in the OPP head's MPC
- * blending tree. Secondary DPP pipe is by convention a non top most pipe. i.e
- * pipe's top_pipe should be not NULL.
- *
- * The function below is actually getting the OTG master pipe associated with
- * the stream. Name it as getting head pipe is confusing.
- */
-struct pipe_ctx *resource_get_head_pipe_for_stream(
+bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type)
+{
+#ifdef DBG
+       if (pipe_ctx->stream == NULL) {
+               /* a free pipe with dangling states */
+               ASSERT(!pipe_ctx->plane_state);
+               ASSERT(!pipe_ctx->prev_odm_pipe);
+               ASSERT(!pipe_ctx->next_odm_pipe);
+               ASSERT(!pipe_ctx->top_pipe);
+               ASSERT(!pipe_ctx->bottom_pipe);
+       } else if (pipe_ctx->top_pipe) {
+               /* a secondary DPP pipe must be signed to a plane */
+               ASSERT(pipe_ctx->plane_state)
+       }
+       /* Add more checks here to prevent corrupted pipe ctx. It is very hard
+        * to debug this issue afterwards because we can't pinpoint the code
+        * location causing inconsistent pipe context states.
+        */
+#endif
+       switch (type) {
+       case OTG_MASTER:
+               return !pipe_ctx->prev_odm_pipe &&
+                               !pipe_ctx->top_pipe &&
+                               pipe_ctx->stream;
+       case OPP_HEAD:
+               return !pipe_ctx->top_pipe && pipe_ctx->stream;
+       case DPP_PIPE:
+               return pipe_ctx->plane_state && pipe_ctx->stream;
+       case FREE_PIPE:
+               return !pipe_ctx->plane_state && !pipe_ctx->stream;
+       default:
+               return false;
+       }
+}
+
+bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx)
+{
+       return resource_get_num_mpc_splits(pipe_ctx) > 0;
+}
+
+struct pipe_ctx *resource_get_otg_master_for_stream(
                struct resource_context *res_ctx,
                struct dc_stream_state *stream)
 {
        int i;
 
        for (i = 0; i < MAX_PIPES; i++) {
-               if (res_ctx->pipe_ctx[i].stream == stream
-                               && !res_ctx->pipe_ctx[i].top_pipe
-                               && !res_ctx->pipe_ctx[i].prev_odm_pipe)
+               if (res_ctx->pipe_ctx[i].stream == stream &&
+                               resource_is_pipe_type(&res_ctx->pipe_ctx[i], OTG_MASTER))
                        return &res_ctx->pipe_ctx[i];
        }
        return NULL;
 }
 
+struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx)
+{
+       struct pipe_ctx *otg_master = resource_get_opp_head(pipe_ctx);
+
+       while (otg_master->prev_odm_pipe)
+               otg_master = otg_master->prev_odm_pipe;
+       return otg_master;
+}
+
+struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx)
+{
+       struct pipe_ctx *opp_head = (struct pipe_ctx *) pipe_ctx;
+
+       ASSERT(!resource_is_pipe_type(opp_head, FREE_PIPE));
+       while (opp_head->top_pipe)
+               opp_head = opp_head->top_pipe;
+       return opp_head;
+}
+
 static struct pipe_ctx *get_tail_pipe(
                struct pipe_ctx *head_pipe)
 {
-       struct pipe_ctx *tail_pipe;
-
-       tail_pipe = head_pipe->bottom_pipe;
+       struct pipe_ctx *tail_pipe = head_pipe->bottom_pipe;
 
        while (tail_pipe) {
                head_pipe = tail_pipe;
@@ -1908,7 +1925,7 @@ bool dc_add_plane_to_context(
                goto out;
        }
 
-       otg_master_pipe = resource_get_head_pipe_for_stream(
+       otg_master_pipe = resource_get_otg_master_for_stream(
                        &context->res_ctx, stream);
        if (otg_master_pipe->plane_state == NULL)
                added = add_plane_to_opp_head_pipes(otg_master_pipe,
@@ -2429,7 +2446,7 @@ enum dc_status dc_remove_stream_from_ctx(
 {
        int i;
        struct dc_context *dc_ctx = dc->ctx;
-       struct pipe_ctx *del_pipe = resource_get_head_pipe_for_stream(&new_ctx->res_ctx, stream);
+       struct pipe_ctx *del_pipe = resource_get_otg_master_for_stream(&new_ctx->res_ctx, stream);
        struct pipe_ctx *odm_pipe;
 
        if (!del_pipe) {
@@ -3683,7 +3700,7 @@ enum dc_status resource_map_clock_resources(
 {
        /* acquire new resources */
        const struct resource_pool *pool = dc->res_pool;
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
                                &context->res_ctx, stream);
 
        if (!pipe_ctx)
@@ -4073,10 +4090,7 @@ void reset_syncd_pipes_from_disabled_pipes(struct dc *dc,
                pipe_ctx_old =  &dc->current_state->res_ctx.pipe_ctx[i];
                pipe_ctx = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe_ctx_old->stream)
-                       continue;
-
-               if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe_ctx_old, OTG_MASTER))
                        continue;
 
                if (!pipe_ctx->stream ||
index 530b85a50b0388cf82fde6ce4851148ff8561d0a..4c5ef3ef8dbdd78bf93a9871e9ee95f70477efe7 100644 (file)
@@ -31,6 +31,7 @@
 #include "core_types.h"
 #include "../basics/conversion.h"
 #include "cursor_reg_cache.h"
+#include "resource.h"
 
 #define CTX dc_dmub_srv->ctx
 #define DC_LOGGER CTX->logger
@@ -356,7 +357,7 @@ bool dc_dmub_srv_p_state_delegate(struct dc *dc, bool should_manage_pstate, stru
        for (i = 0, k = 0; context && i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe->top_pipe && !pipe->prev_odm_pipe && pipe->stream && pipe->stream->fpo_in_use) {
+               if (resource_is_pipe_type(pipe, OTG_MASTER) && pipe->stream->fpo_in_use) {
                        struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
                        uint8_t min_refresh_in_hz = (pipe->stream->timing.min_refresh_in_uhz + 999999) / 1000000;
 
@@ -531,7 +532,8 @@ static void populate_subvp_cmd_vblank_pipe_info(struct dc *dc,
 
                // We check for master pipe, but it shouldn't matter since we only need
                // the pipe for timing info (stream should be same for any pipe splits)
-               if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
+                               !resource_is_pipe_type(pipe, DPP_PIPE))
                        continue;
 
                // Find the SubVP pipe
@@ -728,12 +730,10 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe->stream)
-                       continue;
-
                /* For SubVP pipe count, only count the top most (ODM / MPC) pipe
                 */
-               if (pipe->plane_state && !pipe->top_pipe && !pipe->prev_odm_pipe &&
+               if (resource_is_pipe_type(pipe, OTG_MASTER) &&
+                               resource_is_pipe_type(pipe, DPP_PIPE) &&
                                pipe->stream->mall_stream_config.type == SUBVP_MAIN)
                        subvp_pipes[subvp_count++] = pipe;
        }
@@ -750,12 +750,14 @@ void dc_dmub_setup_subvp_dmub_command(struct dc *dc,
                         * Any ODM or MPC splits being used in SubVP will be handled internally in
                         * populate_subvp_cmd_pipe_info
                         */
-                       if (pipe->plane_state && pipe->stream->mall_stream_config.paired_stream &&
-                                       !pipe->top_pipe && !pipe->prev_odm_pipe &&
+                       if (resource_is_pipe_type(pipe, OTG_MASTER) &&
+                                       resource_is_pipe_type(pipe, DPP_PIPE) &&
+                                       pipe->stream->mall_stream_config.paired_stream &&
                                        pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
                                populate_subvp_cmd_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
-                       } else if (pipe->plane_state && pipe->stream->mall_stream_config.type == SUBVP_NONE &&
-                                   !pipe->top_pipe && !pipe->prev_odm_pipe) {
+                       } else if (resource_is_pipe_type(pipe, OTG_MASTER) &&
+                                       resource_is_pipe_type(pipe, DPP_PIPE) &&
+                                       pipe->stream->mall_stream_config.type == SUBVP_NONE) {
                                // Don't need to check for ActiveDRAMClockChangeMargin < 0, not valid in cases where
                                // we run through DML without calculating "natural" P-state support
                                populate_subvp_cmd_vblank_pipe_info(dc, context, &cmd, pipe, cmd_pipe_index++);
index 42e9b6a529f6f881b3107b419eaf9fa00e89c30e..899b25b0bad8f6efaa5ac3b80beb6883e6662be1 100644 (file)
@@ -824,7 +824,7 @@ static enum dc_status build_mapped_resource(
                struct dc_state *context,
                struct dc_stream_state *stream)
 {
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
 
        if (!pipe_ctx)
                return DC_ERROR_UNEXPECTED;
index c0214da714d49dd946cf39d23061d8c37ee357e8..1289b94188771010cf387d4d8c0c032db637e83a 100644 (file)
@@ -942,7 +942,7 @@ static enum dc_status build_mapped_resource(
                struct dc_state *context,
                struct dc_stream_state *stream)
 {
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
 
        if (!pipe_ctx)
                return DC_ERROR_UNEXPECTED;
index e115ff91aaaaefe5b9dbd094acc8bfccb7bd079e..2b20180f1a3248669b4f77ec627467700d04f3a3 100644 (file)
@@ -873,7 +873,7 @@ static enum dc_status build_mapped_resource(
                struct dc_state *context,
                struct dc_stream_state *stream)
 {
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
 
        if (!pipe_ctx)
                return DC_ERROR_UNEXPECTED;
@@ -964,7 +964,7 @@ enum dc_status resource_map_phy_clock_resources(
 {
 
        /* acquire new resources */
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(
                        &context->res_ctx, stream);
 
        if (!pipe_ctx)
index 82e5af4d5d154fb6bd6ce2945b605917f3224f36..9f9145742f149d5fe123619e0332a0403660d1c6 100644 (file)
@@ -1055,7 +1055,7 @@ static enum dc_status build_mapped_resource(
                struct dc_state *context,
                struct dc_stream_state *stream)
 {
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
 
        if (!pipe_ctx)
                return DC_ERROR_UNEXPECTED;
@@ -1090,8 +1090,8 @@ static struct pipe_ctx *dcn10_acquire_free_pipe_for_layer(
                const struct pipe_ctx *opp_head_pipe)
 {
        struct resource_context *res_ctx = &new_ctx->res_ctx;
-       struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
-       struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
+       struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
+       struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
 
        if (!head_pipe) {
                ASSERT(0);
index efa600e4619485f7a3ebdfaae7e7d7d248921b61..66b74bb5d936fc365bd84552ad17982a63889659 100644 (file)
@@ -1294,7 +1294,7 @@ static enum dc_status build_pipe_hw_param(struct pipe_ctx *pipe_ctx)
 enum dc_status dcn20_build_mapped_resource(const struct dc *dc, struct dc_state *context, struct dc_stream_state *stream)
 {
        enum dc_status status = DC_OK;
-       struct pipe_ctx *pipe_ctx = resource_get_head_pipe_for_stream(&context->res_ctx, stream);
+       struct pipe_ctx *pipe_ctx = resource_get_otg_master_for_stream(&context->res_ctx, stream);
 
        if (!pipe_ctx)
                return DC_ERROR_UNEXPECTED;
@@ -1948,7 +1948,7 @@ int dcn20_validate_apply_pipe_split_flags(
                        v->ODMCombineEnablePerState[vlevel][pipe_plane];
 
                if (v->ODMCombineEnabled[pipe_plane] == dm_odm_combine_mode_disabled) {
-                       if (get_num_mpc_splits(pipe) == 1) {
+                       if (resource_get_num_mpc_splits(pipe) == 1) {
                                /*If need split for mpc but 2 way split already*/
                                if (split[i] == 4)
                                        split[i] = 2; /* 2 -> 4 MPC */
@@ -1956,7 +1956,7 @@ int dcn20_validate_apply_pipe_split_flags(
                                        split[i] = 0; /* 2 -> 2 MPC */
                                else if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state)
                                        merge[i] = true; /* 2 -> 1 MPC */
-                       } else if (get_num_mpc_splits(pipe) == 3) {
+                       } else if (resource_get_num_mpc_splits(pipe) == 3) {
                                /*If need split for mpc but 4 way split already*/
                                if (split[i] == 2 && ((pipe->top_pipe && !pipe->top_pipe->top_pipe)
                                                || !pipe->bottom_pipe)) {
@@ -1965,7 +1965,7 @@ int dcn20_validate_apply_pipe_split_flags(
                                                pipe->top_pipe->plane_state == pipe->plane_state)
                                        merge[i] = true; /* 4 -> 1 MPC */
                                split[i] = 0;
-                       } else if (get_num_odm_splits(pipe)) {
+                       } else if (resource_get_num_odm_splits(pipe)) {
                                /* ODM -> MPC transition */
                                if (pipe->prev_odm_pipe) {
                                        split[i] = 0;
@@ -1973,7 +1973,7 @@ int dcn20_validate_apply_pipe_split_flags(
                                }
                        }
                } else {
-                       if (get_num_odm_splits(pipe) == 1) {
+                       if (resource_get_num_odm_splits(pipe) == 1) {
                                /*If need split for odm but 2 way split already*/
                                if (split[i] == 4)
                                        split[i] = 2; /* 2 -> 4 ODM */
@@ -1983,7 +1983,7 @@ int dcn20_validate_apply_pipe_split_flags(
                                        ASSERT(0); /* NOT expected yet */
                                        merge[i] = true; /* exit ODM */
                                }
-                       } else if (get_num_odm_splits(pipe) == 3) {
+                       } else if (resource_get_num_odm_splits(pipe) == 3) {
                                /*If need split for odm but 4 way split already*/
                                if (split[i] == 2 && ((pipe->prev_odm_pipe && !pipe->prev_odm_pipe->prev_odm_pipe)
                                                || !pipe->next_odm_pipe)) {
@@ -1993,7 +1993,7 @@ int dcn20_validate_apply_pipe_split_flags(
                                        merge[i] = true; /* exit ODM */
                                }
                                split[i] = 0;
-                       } else if (get_num_mpc_splits(pipe)) {
+                       } else if (resource_get_num_mpc_splits(pipe)) {
                                /* MPC -> ODM transition */
                                ASSERT(0); /* NOT expected yet */
                                if (pipe->top_pipe && pipe->top_pipe->plane_state == pipe->plane_state) {
@@ -2154,8 +2154,8 @@ struct pipe_ctx *dcn20_acquire_free_pipe_for_layer(
                const struct pipe_ctx *opp_head)
 {
        struct resource_context *res_ctx = &new_ctx->res_ctx;
-       struct pipe_ctx *otg_master = resource_get_head_pipe_for_stream(res_ctx, opp_head->stream);
-       struct pipe_ctx *sec_dpp_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, otg_master);
+       struct pipe_ctx *otg_master = resource_get_otg_master_for_stream(res_ctx, opp_head->stream);
+       struct pipe_ctx *sec_dpp_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, otg_master);
 
        ASSERT(otg_master);
 
index 4fce3485d0f5d0ea77b62124db30dda2ecf778d9..2dc4d2c1410b816091dbc551b2523c4395f86416 100644 (file)
@@ -999,8 +999,8 @@ static struct pipe_ctx *dcn201_acquire_free_pipe_for_layer(
                const struct pipe_ctx *opp_head_pipe)
 {
        struct resource_context *res_ctx = &new_ctx->res_ctx;
-       struct pipe_ctx *head_pipe = resource_get_head_pipe_for_stream(res_ctx, opp_head_pipe->stream);
-       struct pipe_ctx *idle_pipe = find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
+       struct pipe_ctx *head_pipe = resource_get_otg_master_for_stream(res_ctx, opp_head_pipe->stream);
+       struct pipe_ctx *idle_pipe = resource_find_free_secondary_pipe_legacy(res_ctx, pool, head_pipe);
 
        if (!head_pipe)
                ASSERT(0);
index a87afb796f470a23256cb19f8071af139e31c997..680e7fa8d18abce9e28b29bd867990c4c22c6392 100644 (file)
@@ -567,7 +567,7 @@ bool dcn32_set_output_transfer_func(struct dc *dc,
        bool ret = false;
 
        /* program OGAM or 3DLUT only for the top pipe*/
-       if (pipe_ctx->top_pipe == NULL) {
+       if (resource_is_pipe_type(pipe_ctx, OPP_HEAD)) {
                /*program shaper and 3dlut in MPC*/
                ret = dcn32_set_mpc_shaper_3dlut(pipe_ctx, stream);
                if (ret == false && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
@@ -1202,10 +1202,10 @@ void dcn32_resync_fifo_dccg_dio(struct dce_hwseq *hws, struct dc *dc, struct dc_
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                pipe = &dc->current_state->res_ctx.pipe_ctx[i];
 
-               if (pipe->top_pipe || pipe->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe, OTG_MASTER))
                        continue;
 
-               if (pipe->stream && (pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
+               if ((pipe->stream->dpms_off || dc_is_virtual_signal(pipe->stream->signal))
                        && pipe->stream->mall_stream_config.type != SUBVP_PHANTOM) {
                        pipe->stream_res.tg->funcs->disable_crtc(pipe->stream_res.tg);
                        reset_sync_context_for_pipe(dc, context, i);
@@ -1299,7 +1299,7 @@ static void apply_symclk_on_tx_off_wa(struct dc_link *link)
        if (link->phy_state.symclk_ref_cnts.otg > 0) {
                for (i = 0; i < MAX_PIPES; i++) {
                        pipe_ctx = &dc->current_state->res_ctx.pipe_ctx[i];
-                       if (pipe_ctx->stream && pipe_ctx->stream->link == link && pipe_ctx->top_pipe == NULL) {
+                       if (resource_is_pipe_type(pipe_ctx, OPP_HEAD) && pipe_ctx->stream->link == link) {
                                pipe_ctx->clock_source->funcs->program_pix_clk(
                                                pipe_ctx->clock_source,
                                                &pipe_ctx->stream_res.pix_clk_params,
@@ -1382,7 +1382,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
 {
        phantom_pipe->update_flags.raw = 0;
        if (phantom_pipe->stream && phantom_pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
-               if (phantom_pipe->stream && phantom_pipe->plane_state) {
+               if (resource_is_pipe_type(phantom_pipe, DPP_PIPE)) {
                        phantom_pipe->update_flags.bits.enable = 1;
                        phantom_pipe->update_flags.bits.mpcc = 1;
                        phantom_pipe->update_flags.bits.dppclk = 1;
@@ -1392,7 +1392,7 @@ void dcn32_apply_update_flags_for_phantom(struct pipe_ctx *phantom_pipe)
                        phantom_pipe->update_flags.bits.scaler = 1;
                        phantom_pipe->update_flags.bits.viewport = 1;
                        phantom_pipe->update_flags.bits.det_size = 1;
-                       if (!phantom_pipe->top_pipe && !phantom_pipe->prev_odm_pipe) {
+                       if (resource_is_pipe_type(phantom_pipe, OTG_MASTER)) {
                                phantom_pipe->update_flags.bits.odm = 1;
                                phantom_pipe->update_flags.bits.global_sync = 1;
                        }
index cadbe1dcfbfeb235a142fa46d617044409942326..935cd23e6a01ab80efd07196e466337a852b4373 100644 (file)
@@ -1709,8 +1709,8 @@ void dcn32_retain_phantom_pipes(struct dc *dc, struct dc_state *context)
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe->top_pipe && !pipe->prev_odm_pipe &&
-                               pipe->plane_state && pipe->stream &&
+               if (resource_is_pipe_type(pipe, OTG_MASTER) &&
+                               resource_is_pipe_type(pipe, DPP_PIPE) &&
                                pipe->stream->mall_stream_config.type == SUBVP_PHANTOM) {
                        phantom_plane = pipe->plane_state;
                        phantom_stream = pipe->stream;
index db9c55a09d9f4f62c75d5130fa1416fc985288ca..3ad2b48954e02924cce24d3680d6cdeece8ea3e0 100644 (file)
@@ -646,10 +646,8 @@ bool dcn32_subvp_drr_admissable(struct dc *dc, struct dc_state *context)
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe->stream)
-                       continue;
-
-               if (pipe->plane_state && !pipe->top_pipe) {
+               if (resource_is_pipe_type(pipe, OPP_HEAD) &&
+                               resource_is_pipe_type(pipe, DPP_PIPE)) {
                        if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
                                subvp_count++;
 
@@ -706,10 +704,8 @@ bool dcn32_subvp_vblank_admissable(struct dc *dc, struct dc_state *context, int
        for (i = 0; i < dc->res_pool->pipe_count; i++) {
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
-               if (!pipe->stream)
-                       continue;
-
-               if (pipe->plane_state && !pipe->top_pipe) {
+               if (resource_is_pipe_type(pipe, OPP_HEAD) &&
+                               resource_is_pipe_type(pipe, DPP_PIPE)) {
                        if (pipe->stream->mall_stream_config.type == SUBVP_MAIN) {
                                subvp_count++;
 
index 0100a6053ab6b2d10ded15b84633ff21d17da8e6..f2dfa96f9ef5d9e4805fdbf592cac078efa391a5 100644 (file)
@@ -3015,7 +3015,7 @@ static bool all_displays_in_sync(const struct pipe_ctx pipe[],
        int i, num_active_pipes = 0;
 
        for (i = 0; i < pipe_count; i++) {
-               if (!pipe[i].stream || pipe[i].top_pipe)
+               if (!resource_is_pipe_type(&pipe[i], OPP_HEAD))
                        continue;
 
                active_pipes[num_active_pipes++] = &pipe[i];
index 794d6517e51105275b2b96c7f7a0537597384757..50b0434354f8f5778ab825864fe46b1f25505ccd 100644 (file)
@@ -1258,7 +1258,7 @@ bool dcn_validate_bandwidth(
                                                hsplit_pipe->pipe_dlg_param.vblank_end = pipe->pipe_dlg_param.vblank_end;
                                        } else {
                                                /* pipe not split previously needs split */
-                                               hsplit_pipe = find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe);
+                                               hsplit_pipe = resource_find_free_secondary_pipe_legacy(&context->res_ctx, pool, pipe);
                                                ASSERT(hsplit_pipe);
                                                split_stream_across_pipes(&context->res_ctx, pool, pipe, hsplit_pipe);
                                        }
index 8ae5ddbd1b271b6148a30a3870a28d26f8b3f87b..8afda5ecc0cd3f28f07d9d821822d7943a547c31 100644 (file)
@@ -1305,7 +1305,7 @@ int dcn20_populate_dml_pipes_from_context(struct dc *dc,
                pipes[pipe_cnt].dout.is_virtual = 0;
                pipes[pipe_cnt].pipe.dest.vtotal_min = res_ctx->pipe_ctx[i].stream->adjust.v_total_min;
                pipes[pipe_cnt].pipe.dest.vtotal_max = res_ctx->pipe_ctx[i].stream->adjust.v_total_max;
-               switch (get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
+               switch (resource_get_num_odm_splits(&res_ctx->pipe_ctx[i])) {
                case 1:
                        pipes[pipe_cnt].pipe.dest.odm_combine = dm_odm_combine_mode_2to1;
                        break;
index 6d60ae0133ee0f1bc5fcce59d2b6b271ac21cdbd..711d4085b33b8f781890cfdd92fdeff782de60a9 100644 (file)
@@ -756,7 +756,7 @@ static bool dcn32_enough_pipes_for_subvp(struct dc *dc, struct dc_state *context
                struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
 
                // Find the minimum pipe split count for non SubVP pipes
-               if (pipe->stream && !pipe->top_pipe &&
+               if (resource_is_pipe_type(pipe, OPP_HEAD) &&
                    pipe->stream->mall_stream_config.type == SUBVP_NONE) {
                        split_cnt = 0;
                        while (pipe) {
@@ -886,7 +886,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
 
                // We check for master pipe, but it shouldn't matter since we only need
                // the pipe for timing info (stream should be same for any pipe splits)
-               if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
+                               !resource_is_pipe_type(pipe, DPP_PIPE))
                        continue;
 
                // Find the SubVP pipe
@@ -899,7 +900,8 @@ static bool subvp_drr_schedulable(struct dc *dc, struct dc_state *context)
                drr_pipe = &context->res_ctx.pipe_ctx[i];
 
                // We check for master pipe only
-               if (!drr_pipe->stream || !drr_pipe->plane_state || drr_pipe->top_pipe || drr_pipe->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
+                               !resource_is_pipe_type(pipe, DPP_PIPE))
                        continue;
 
                if (drr_pipe->stream->mall_stream_config.type == SUBVP_NONE && drr_pipe->stream->ignore_msa_timing_param &&
@@ -980,7 +982,8 @@ static bool subvp_vblank_schedulable(struct dc *dc, struct dc_state *context)
 
                // We check for master pipe, but it shouldn't matter since we only need
                // the pipe for timing info (stream should be same for any pipe splits)
-               if (!pipe->stream || !pipe->plane_state || pipe->top_pipe || pipe->prev_odm_pipe)
+               if (!resource_is_pipe_type(pipe, OTG_MASTER) ||
+                               !resource_is_pipe_type(pipe, DPP_PIPE))
                        continue;
 
                if (!found && pipe->stream->mall_stream_config.type == SUBVP_NONE) {
index 8dabbbc2a7b902eed2446d9697de4de8efc0bd5d..e546b9c506c116600648ae0b5bfd0e79730ae4f7 100644 (file)
@@ -37,7 +37,6 @@
 #define IS_PIPE_SYNCD_VALID(pipe) ((((pipe)->pipe_idx_syncd) & 0x80)?1:0)
 #define GET_PIPE_SYNCD_FROM_PIPE(pipe) ((pipe)->pipe_idx_syncd & 0x7F)
 #define SET_PIPE_SYNCD_TO_PIPE(pipe, pipe_syncd) ((pipe)->pipe_idx_syncd = (0x80 | pipe_syncd))
-#define FREE_PIPE_INDEX_NOT_FOUND -1
 
 enum dce_version resource_parse_asic_id(
                struct hw_asic_id asic_id);
@@ -143,10 +142,6 @@ struct clock_source *dc_resource_find_first_free_pll(
                struct resource_context *res_ctx,
                const struct resource_pool *pool);
 
-struct pipe_ctx *resource_get_head_pipe_for_stream(
-               struct resource_context *res_ctx,
-               struct dc_stream_state *stream);
-
 bool resource_attach_surfaces_to_context(
                struct dc_plane_state *const *plane_state,
                int surface_count,
@@ -154,29 +149,232 @@ bool resource_attach_surfaces_to_context(
                struct dc_state *context,
                const struct resource_pool *pool);
 
-struct pipe_ctx *find_free_secondary_pipe_legacy(
-               struct resource_context *res_ctx,
-               const struct resource_pool *pool,
-               const struct pipe_ctx *primary_pipe);
+#define FREE_PIPE_INDEX_NOT_FOUND -1
 
+/*
+ * pipe types are identified based on MUXes in DCN front end that are capable
+ * of taking input from one DCN pipeline to another DCN pipeline. The name is
+ * in a form of XXXX_YYYY, where XXXX is the DCN front end hardware block the
+ * pipeline ends with and YYYY is the rendering role that the pipe is in.
+ *
+ * For instance OTG_MASTER is a pipe ending with OTG hardware block in its
+ * pipeline and it is in a role of a master pipe for timing generation.
+ *
+ * For quick reference a diagram of each pipe type's areas of responsibility
+ * for outputting timings on the screen is shown below:
+ *
+ *       Timing Active for Stream 0
+ *        __________________________________________________
+ *       |OTG master 0 (OPP head 0)|OPP head 2 (DPP pipe 2) |
+ *       |             (DPP pipe 0)|                        |
+ *       | Top Plane 0             |                        |
+ *       |           ______________|____                    |
+ *       |          |DPP pipe 1    |DPP |                   |
+ *       |          |              |pipe|                   |
+ *       |          |  Bottom      |3   |                   |
+ *       |          |  Plane 1     |    |                   |
+ *       |          |              |    |                   |
+ *       |          |______________|____|                   |
+ *       |                         |                        |
+ *       |                         |                        |
+ *       | ODM slice 0             | ODM slice 1            |
+ *       |_________________________|________________________|
+ *
+ *       Timing Active for Stream 1
+ *        __________________________________________________
+ *       |OTG master 4 (OPP head 4)                         |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |               Blank Pixel Data                   |
+ *       |              (generated by DPG4)                 |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |                                                  |
+ *       |__________________________________________________|
+ *
+ *       Inter-pipe Relation
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |  plane 0      | slice 0   |             |
+ *       |   0    | -------------MPC---------ODM----------- |
+ *       |        |  plane 1    | |         | |             |
+ *       |   1    | ------------- |         | |             |
+ *       |        |  plane 0      | slice 1 | |             |
+ *       |   2    | -------------MPC--------- |             |
+ *       |        |  plane 1    | |           |             |
+ *       |   3    | ------------- |           |             |
+ *       |        |               | blank     |             |
+ *       |   4    |               | ----------------------- |
+ *       |        |               |           |             |
+ *       |   5    |  (FREE)       |           |             |
+ *       |________|_______________|___________|_____________|
+ */
+enum pipe_type {
+       /* free pipe - free pipe is an uninitialized pipe without a stream
+        * associated with it. It is a free DCN pipe resource. It can be
+        * acquired as any type of pipe.
+        */
+       FREE_PIPE,
+
+       /* OTG master pipe - the master pipe of its OPP head pipes with a
+        * functional OTG. It merges all its OPP head pipes pixel data in ODM
+        * block and output to backend DIG. OTG master pipe is responsible for
+        * generating entire crtc timing to backend DIG. An OTG master pipe may
+        * or may not have a plane. If it has a plane it blends it as the left
+        * most MPC slice of the top most layer. If it doesn't have a plane it
+        * can output pixel data from its OPP head pipes' test pattern
+        * generators (DPG) such as solid black pixel data to blank the screen.
+        */
+       OTG_MASTER,
+
+       /* OPP head pipe - the head pipe of an MPC blending tree with a
+        * functional OPP outputting to an OTG. OPP head pipe is responsible for
+        * processing output pixels in its own ODM slice. It may or may not have
+        * a plane. If it has a plane it blends it as the top most layer within
+        * its own ODM slice. If it doesn't have a plane it can output pixel
+        * data from its DPG such as solid black pixel data to blank the pixel
+        * data in its own ODM slice. OTG master pipe is also an OPP head pipe
+        * but with more responsibility.
+        */
+       OPP_HEAD,
+
+       /* DPP pipe - the pipe with a functional DPP outputting to an OPP head
+        * pipe's MPC. DPP pipe is responsible for processing pixel data from
+        * its own MPC slice of a plane. It must be connected to an OPP head
+        * pipe and it must have a plane associated with it.
+        */
+       DPP_PIPE,
+};
+
+/*
+ * Determine if the input pipe ctx is of a pipe type.
+ * return - true if pipe ctx is of the input type.
+ */
+bool resource_is_pipe_type(const struct pipe_ctx *pipe_ctx, enum pipe_type type);
+
+/*
+ * Determine if the input pipe ctx is used for rendering a plane with MPCC
+ * combine. MPCC combine is a hardware feature to combine multiple DPP pipes
+ * into a single plane. It is typically used for bypassing pipe bandwidth
+ * limitation for rendering a very large plane or saving power by reducing UCLK
+ * and DPPCLK speeds.
+ *
+ * For instance in the Inter-pipe Relation diagram shown below, both PIPE 0 and
+ * 1 are for MPCC combine for plane 0
+ *
+ *       Inter-pipe Relation
+ *        __________________________________________________
+ *       |PIPE IDX|   DPP PIPES   | OPP HEADS | OTG MASTER  |
+ *       |        |  plane 0      |           |             |
+ *       |   0    | -------------MPC----------------------- |
+ *       |        |  plane 0    | |           |             |
+ *       |   1    | ------------- |           |             |
+ *       |________|_______________|___________|_____________|
+ *
+ * return - true if pipe ctx is used for mpcc combine.
+ */
+bool resource_is_for_mpcc_combine(const struct pipe_ctx *pipe_ctx);
+
+/*
+ * Look for a free pipe in new resource context that is used as a secondary DPP
+ * pipe in MPC blending tree associated with input OPP head pipe.
+ *
+ * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
+ * pipe idx of the free pipe
+ */
 int resource_find_free_pipe_used_in_cur_mpc_blending_tree(
                const struct resource_context *cur_res_ctx,
                struct resource_context *new_res_ctx,
                const struct pipe_ctx *cur_opp_head);
 
+/*
+ * Look for a free pipe in new resource context that is not used in current
+ * resource context.
+ *
+ * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
+ * pipe idx of the free pipe
+ */
 int recource_find_free_pipe_not_used_in_cur_res_ctx(
                const struct resource_context *cur_res_ctx,
                struct resource_context *new_res_ctx,
                const struct resource_pool *pool);
 
+/*
+ * Look for a free pipe in new resource context that is used as a secondary DPP
+ * pipe in any MPCC combine in current resource context.
+ * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
+ * pipe idx of the free pipe
+ */
 int resource_find_free_pipe_used_as_cur_sec_dpp_in_mpcc_combine(
                const struct resource_context *cur_res_ctx,
                struct resource_context *new_res_ctx,
                const struct resource_pool *pool);
 
+/*
+ * Look for any free pipe in new resource context.
+ * return - FREE_PIPE_INDEX_NOT_FOUND if free pipe is not found, otherwise
+ * pipe idx of the free pipe
+ */
 int resource_find_any_free_pipe(struct resource_context *new_res_ctx,
                const struct resource_pool *pool);
 
+/*
+ * Legacy find free secondary pipe logic deprecated for newer DCNs as it doesn't
+ * find the most optimal free pipe to prevent from time consuming hardware state
+ * transitions.
+ */
+struct pipe_ctx *resource_find_free_secondary_pipe_legacy(
+               struct resource_context *res_ctx,
+               const struct resource_pool *pool,
+               const struct pipe_ctx *primary_pipe);
+
+/*
+ * Get number of MPC "cuts" of the plane associated with the pipe. MPC slice
+ * count is equal to MPC splits + 1. For example if a plane is cut 3 times, it
+ * will have 4 pieces of slice.
+ * return - 0 if pipe is not used for a plane with MPCC combine. otherwise
+ * the number of MPC "cuts" for the plane.
+ */
+int resource_get_num_mpc_splits(const struct pipe_ctx *pipe);
+
+/*
+ * Get number of ODM "cuts" of the timing associated with the pipe. ODM slice
+ * count is equal to ODM splits + 1. For example if a timing is cut 3 times, it
+ * will have 4 pieces of slice.
+ * return - 0 if pipe is not used for ODM combine. otherwise
+ * the number of ODM "cuts" for the timing.
+ */
+int resource_get_num_odm_splits(const struct pipe_ctx *pipe);
+
+/*
+ * Get the OTG master pipe in resource context associated with the stream.
+ * return - NULL if not found. Otherwise the OTG master pipe associated with the
+ * stream.
+ */
+struct pipe_ctx *resource_get_otg_master_for_stream(
+               struct resource_context *res_ctx,
+               struct dc_stream_state *stream);
+
+/*
+ * Get the OTG master pipe for the input pipe context.
+ * return - the OTG master pipe for the input pipe
+ * context.
+ */
+struct pipe_ctx *resource_get_otg_master(const struct pipe_ctx *pipe_ctx);
+
+/*
+ * Get the OPP head pipe for the input pipe context.
+ * return - the OPP head pipe for the input pipe
+ * context.
+ */
+struct pipe_ctx *resource_get_opp_head(const struct pipe_ctx *pipe_ctx);
+
+
 bool resource_validate_attach_surfaces(
                const struct dc_validation_set set[],
                int set_count,
@@ -212,10 +410,6 @@ unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format);
 void get_audio_check(struct audio_info *aud_modes,
        struct audio_check *aud_chk);
 
-int get_num_mpc_splits(struct pipe_ctx *pipe);
-
-int get_num_odm_splits(struct pipe_ctx *pipe);
-
 bool get_temp_dp_link_res(struct dc_link *link,
                struct link_resource *link_res,
                struct dc_link_settings *link_settings);
index c7e1f2229afd5f729dc0bb0771ba90070eb80dd9..fe4282771cd07bc5f0a68decb18423746fd2e2ae 100644 (file)
@@ -675,7 +675,8 @@ bool dp_set_test_pattern(
                if (pipes[i].stream == NULL)
                        continue;
 
-               if (pipes[i].stream->link == link && !pipes[i].top_pipe && !pipes[i].prev_odm_pipe) {
+               if (resource_is_pipe_type(&pipes[i], OTG_MASTER) &&
+                               pipes[i].stream->link == link) {
                        pipe_ctx = &pipes[i];
                        break;
                }
index 7997936613fc35a4416e55520a267e2b16db0d36..79aef205598b7f4816a3c55077640d7b1b0332d9 100644 (file)
@@ -182,11 +182,8 @@ void link_resume(struct dc_link *link)
 static bool is_master_pipe_for_link(const struct dc_link *link,
                const struct pipe_ctx *pipe)
 {
-       return (pipe->stream &&
-                       pipe->stream->link &&
-                       pipe->stream->link == link &&
-                       pipe->top_pipe == NULL &&
-                       pipe->prev_odm_pipe == NULL);
+       return resource_is_pipe_type(pipe, OTG_MASTER) &&
+                       pipe->stream->link == link;
 }
 
 /*