drm/amd/display: implement pipe type definition and adding accessors

[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>
This commit is contained in:
Wenjing Liu 2023-07-28 13:42:37 -04:00 committed by Alex Deucher
parent 133fe0dd99
commit 53f3288079
19 changed files with 374 additions and 184 deletions

View 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];

View 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;
pipe_ctx = resource_get_opp_head(pipe_ctx);
if (!pipe_ctx)
return 0;
split_pipe = pipe_ctx->prev_odm_pipe;
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];
cur_pipe = &cur_res_ctx->pipe_ctx[i];
new_pipe = &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) {
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 ||

View 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++);

View 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;

View 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;

View 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)

View 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);

View 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);

View 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);

View 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;
}

View 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;

View 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++;

View 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];

View 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);
}

View 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;

View 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) {

View 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);

View 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;
}

View 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;
}
/*