drm/amd/display: re structure odm to allow 4 to 1 support

Currently odm is handled using top_bottom pipe by special casing
the differing opps to differentiate from mpc combine.

Since top/bottom pipe list was made to track mpc muxing this creates
difficulties in adding a 4 pipe odm case support.

Rather than continue using mpc combine list, this change reworks odm
to use it's own linked list to keep track of odm combine pipes. This
also opens up options for using mpo with odm, if a practical use case
is ever found.

Signed-off-by: Dmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: Charlene Liu <Charlene.Liu@amd.com>
Acked-by: Leo Li <sunpeng.li@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Dmytro Laktyushkin 2019-08-06 17:17:28 -04:00 committed by Alex Deucher
parent bad4c3e665
commit b1f6d01c4a
12 changed files with 316 additions and 265 deletions

View file

@ -1860,9 +1860,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->stream &&
pipe_ctx->stream == stream) {
if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {
if (stream_update->periodic_interrupt0 &&
dc->hwss.setup_periodic_interrupt)
@ -1888,7 +1886,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dither_option) {
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
#endif
resource_build_bit_depth_reduction_params(pipe_ctx->stream,
&pipe_ctx->stream->bit_depth_params);
@ -1896,10 +1894,12 @@ static void commit_planes_do_stream_update(struct dc *dc,
&stream->bit_depth_params,
&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
if (odm_pipe)
while (odm_pipe) {
odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
&stream->bit_depth_params,
&stream->clamping);
odm_pipe = odm_pipe->next_odm_pipe;
}
#endif
}

View file

@ -3095,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link,
controller_test_pattern, color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) {
struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
if (bot_odm_pipe) {
struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
width /= 2;
bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
width /= opp_cnt;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
controller_test_pattern,
color_depth,
NULL,
@ -3131,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link,
color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) {
struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
if (bot_odm_pipe) {
struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
width /= 2;
bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
width /= opp_cnt;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
color_depth,
NULL,

View file

@ -275,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
for (i = 0; i < MAX_PIPES; i++) {
if (pipes[i].stream != NULL &&
!pipes[i].top_pipe &&
!pipes[i].top_pipe && !pipes[i].prev_odm_pipe &&
pipes[i].stream->link != NULL &&
pipes[i].stream_res.stream_enc != NULL) {
udelay(100);
@ -381,7 +381,11 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
struct display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
struct dc *core_dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream;
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
if (enable) {
struct dsc_config dsc_cfg;
@ -389,26 +393,24 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
enum optc_dsc_mode optc_dsc_mode;
/* Enable DSC hw block */
dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right) / opp_cnt;
dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top + stream->timing.v_border_bottom;
dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
dsc_cfg.color_depth = stream->timing.display_color_depth;
dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % opp_cnt == 0);
dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
if (odm_pipe) {
struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc;
dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
struct display_stream_compressor *odm_dsc = odm_pipe->stream_res.dsc;
dsc_cfg.pic_width /= 2;
ASSERT(dsc_cfg.dc_dsc_cfg.num_slices_h % 2 == 0);
dsc_cfg.dc_dsc_cfg.num_slices_h /= 2;
dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
bot_dsc->funcs->dsc_set_config(bot_dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
bot_dsc->funcs->dsc_enable(bot_dsc, odm_pipe->stream_res.opp->inst);
} else {
dsc->funcs->dsc_set_config(dsc, &dsc_cfg, &dsc_optc_cfg);
dsc->funcs->dsc_enable(dsc, pipe_ctx->stream_res.opp->inst);
odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
}
dsc_cfg.dc_dsc_cfg.num_slices_h *= opp_cnt;
dsc_cfg.pic_width *= opp_cnt;
optc_dsc_mode = dsc_optc_cfg.is_pixel_format_444 ? OPTC_DSC_ENABLED_444 : OPTC_DSC_ENABLED_NATIVE_SUBSAMPLED;
@ -449,7 +451,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
/* disable DSC block */
pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc);
if (odm_pipe)
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
}
}

View file

@ -1117,8 +1117,9 @@ struct pipe_ctx *resource_get_head_pipe_for_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) {
if (res_ctx->pipe_ctx[i].stream == stream
&& !res_ctx->pipe_ctx[i].top_pipe
&& !res_ctx->pipe_ctx[i].prev_odm_pipe) {
return &res_ctx->pipe_ctx[i];
break;
}
@ -1126,15 +1127,11 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
return NULL;
}
static struct pipe_ctx *resource_get_tail_pipe_for_stream(
static struct pipe_ctx *resource_get_tail_pipe(
struct resource_context *res_ctx,
struct dc_stream_state *stream)
struct pipe_ctx *head_pipe)
{
struct pipe_ctx *head_pipe, *tail_pipe;
head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
if (!head_pipe)
return NULL;
struct pipe_ctx *tail_pipe;
tail_pipe = head_pipe->bottom_pipe;
@ -1150,31 +1147,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream(
* A free_pipe for a stream is defined here as a pipe
* that has no surface attached yet
*/
static struct pipe_ctx *acquire_free_pipe_for_stream(
static struct pipe_ctx *acquire_free_pipe_for_head(
struct dc_state *context,
const struct resource_pool *pool,
struct dc_stream_state *stream)
struct pipe_ctx *head_pipe)
{
int i;
struct resource_context *res_ctx = &context->res_ctx;
struct pipe_ctx *head_pipe = NULL;
/* Find head pipe, which has the back end set up*/
head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
if (!head_pipe) {
ASSERT(0);
return NULL;
}
if (!head_pipe->plane_state)
return head_pipe;
/* Re-use pipe already acquired for this stream if available*/
for (i = pool->pipe_count - 1; i >= 0; i--) {
if (res_ctx->pipe_ctx[i].stream == stream &&
if (res_ctx->pipe_ctx[i].stream == head_pipe->stream &&
!res_ctx->pipe_ctx[i].plane_state) {
return &res_ctx->pipe_ctx[i];
}
@ -1188,8 +1174,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream(
if (!pool->funcs->acquire_idle_pipe_for_layer)
return NULL;
return pool->funcs->acquire_idle_pipe_for_layer(context, pool, stream);
return pool->funcs->acquire_idle_pipe_for_layer(context, pool, head_pipe->stream);
}
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
@ -1203,7 +1188,7 @@ static int acquire_first_split_pipe(
for (i = 0; i < pool->pipe_count; i++) {
struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[i];
if (split_pipe->top_pipe && !dc_res_is_odm_head_pipe(split_pipe) &&
if (split_pipe->top_pipe &&
split_pipe->top_pipe->plane_state == split_pipe->plane_state) {
split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
if (split_pipe->bottom_pipe)
@ -1264,39 +1249,41 @@ bool dc_add_plane_to_context(
return false;
}
tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream);
ASSERT(tail_pipe);
free_pipe = acquire_free_pipe_for_stream(context, pool, stream);
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
if (!free_pipe) {
int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
if (pipe_idx >= 0)
free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
}
#endif
if (!free_pipe)
return false;
/* retain new surfaces */
/* retain new surface, but only once per stream */
dc_plane_state_retain(plane_state);
free_pipe->plane_state = plane_state;
if (head_pipe != free_pipe) {
free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
free_pipe->clock_source = tail_pipe->clock_source;
free_pipe->top_pipe = tail_pipe;
tail_pipe->bottom_pipe = free_pipe;
} else if (free_pipe->bottom_pipe && free_pipe->bottom_pipe->plane_state == NULL) {
ASSERT(free_pipe->bottom_pipe->stream_res.opp != free_pipe->stream_res.opp);
free_pipe->bottom_pipe->plane_state = plane_state;
while (head_pipe) {
tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
ASSERT(tail_pipe);
free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
if (!free_pipe) {
int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
if (pipe_idx >= 0)
free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
}
#endif
if (!free_pipe) {
dc_plane_state_release(plane_state);
return false;
}
free_pipe->plane_state = plane_state;
if (head_pipe != free_pipe) {
free_pipe->stream_res.tg = tail_pipe->stream_res.tg;
free_pipe->stream_res.abm = tail_pipe->stream_res.abm;
free_pipe->stream_res.opp = tail_pipe->stream_res.opp;
free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc;
free_pipe->stream_res.audio = tail_pipe->stream_res.audio;
free_pipe->clock_source = tail_pipe->clock_source;
free_pipe->top_pipe = tail_pipe;
tail_pipe->bottom_pipe = free_pipe;
}
head_pipe = head_pipe->next_odm_pipe;
}
/* assign new surfaces*/
stream_status->plane_states[stream_status->plane_count] = plane_state;
@ -1305,35 +1292,6 @@ bool dc_add_plane_to_context(
return true;
}
struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *bottom_pipe = pipe_ctx->bottom_pipe;
/* ODM should only be updated once per otg */
if (pipe_ctx->top_pipe)
return NULL;
while (bottom_pipe) {
if (bottom_pipe->stream_res.opp != pipe_ctx->stream_res.opp)
break;
bottom_pipe = bottom_pipe->bottom_pipe;
}
return bottom_pipe;
}
bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *top_pipe = pipe_ctx->top_pipe;
if (!top_pipe)
return false;
if (top_pipe && top_pipe->stream_res.opp == pipe_ctx->stream_res.opp)
return false;
return true;
}
bool dc_remove_plane_from_context(
const struct dc *dc,
struct dc_stream_state *stream,
@ -1360,12 +1318,6 @@ bool dc_remove_plane_from_context(
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->plane_state == plane_state) {
if (dc_res_is_odm_head_pipe(pipe_ctx)) {
pipe_ctx->plane_state = NULL;
pipe_ctx->bottom_pipe = NULL;
continue;
}
if (pipe_ctx->top_pipe)
pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
@ -1380,13 +1332,10 @@ bool dc_remove_plane_from_context(
* For head pipe detach surfaces from pipe for tail
* pipe just zero it out
*/
if (!pipe_ctx->top_pipe) {
if (!pipe_ctx->top_pipe)
pipe_ctx->plane_state = NULL;
if (!dc_res_get_odm_bottom_pipe(pipe_ctx))
pipe_ctx->bottom_pipe = NULL;
} else {
else
memset(pipe_ctx, 0, sizeof(*pipe_ctx));
}
}
}
@ -1755,9 +1704,6 @@ enum dc_status dc_remove_stream_from_ctx(
for (i = 0; i < MAX_PIPES; i++) {
if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
!new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
struct pipe_ctx *odm_pipe =
dc_res_get_odm_bottom_pipe(&new_ctx->res_ctx.pipe_ctx[i]);
del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
ASSERT(del_pipe->stream_res.stream_enc);
@ -1782,8 +1728,6 @@ enum dc_status dc_remove_stream_from_ctx(
dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
memset(del_pipe, 0, sizeof(*del_pipe));
if (odm_pipe)
memset(odm_pipe, 0, sizeof(*odm_pipe));
break;
}
@ -2497,6 +2441,12 @@ void dc_resource_state_copy_construct(
if (cur_pipe->bottom_pipe)
cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx];
if (cur_pipe->next_odm_pipe)
cur_pipe->next_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->next_odm_pipe->pipe_idx];
if (cur_pipe->prev_odm_pipe)
cur_pipe->prev_odm_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->prev_odm_pipe->pipe_idx];
}
for (i = 0; i < dst_ctx->stream_count; i++) {

View file

@ -1341,7 +1341,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
struct drr_params params = {0};
unsigned int event_triggers = 0;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
#endif
if (dc->hwss.disable_stream_gating) {
@ -1409,7 +1409,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
&stream->bit_depth_params,
&stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
if (odm_pipe) {
while (odm_pipe) {
odm_pipe->stream_res.opp->funcs->opp_set_dyn_expansion(
odm_pipe->stream_res.opp,
COLOR_SPACE_YCBCR601,
@ -1420,6 +1420,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
odm_pipe->stream_res.opp,
&stream->bit_depth_params,
&stream->clamping);
odm_pipe = odm_pipe->next_odm_pipe;
}
#endif
@ -2079,7 +2080,7 @@ enum dc_status dce110_apply_ctx_to_hw(
if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
continue;
if (pipe_ctx->top_pipe)
if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
continue;
status = apply_single_controller_ctx_to_hw(

View file

@ -2537,7 +2537,7 @@ struct pipe_ctx *find_top_pipe_for_stream(
if (pipe_ctx->stream != stream)
continue;
if (!pipe_ctx->top_pipe)
if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe)
return pipe_ctx;
}
return NULL;

View file

@ -529,11 +529,9 @@ enum dc_status dcn20_enable_stream_timing(
struct dc_stream_state *stream = pipe_ctx->stream;
struct drr_params params = {0};
unsigned int event_triggers = 0;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
#endif
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
/* by upper caller loop, pipe0 is parent pipe and be called first.
* back end is set up by for pipe0. Other children pipe share back end
@ -544,14 +542,17 @@ enum dc_status dcn20_enable_stream_timing(
/* TODO check if timing_changed, disable stream if timing changed */
if (odm_pipe) {
int opp_inst[2] = { pipe_ctx->stream_res.opp->inst, odm_pipe->stream_res.opp->inst };
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
opp_cnt++;
}
if (opp_cnt > 1)
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, 2,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
}
/* HW program guide assume display already disable
* by unplug sequence. OTG assume stop.
*/
@ -575,7 +576,7 @@ enum dc_status dcn20_enable_stream_timing(
pipe_ctx->stream->signal,
true);
if (odm_pipe)
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_pipe->stream_res.opp->funcs->opp_pipe_clock_control(
odm_pipe->stream_res.opp,
true);
@ -661,7 +662,7 @@ bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx,
*/
if (mpc->funcs->power_on_mpc_mem_pwr)
mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true);
if ((pipe_ctx->top_pipe == NULL || dc_res_is_odm_head_pipe(pipe_ctx))
if (pipe_ctx->top_pipe == NULL
&& mpc->funcs->set_output_gamma && stream->out_transfer_func) {
if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func->pwl;
@ -823,17 +824,21 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx,
static void dcn20_update_odm(struct dc *dc, struct dc_state *context, struct pipe_ctx *pipe_ctx)
{
struct pipe_ctx *combine_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
if (combine_pipe) {
int opp_inst[2] = { pipe_ctx->stream_res.opp->inst,
combine_pipe->stream_res.opp->inst };
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
opp_cnt++;
}
if (opp_cnt > 1)
pipe_ctx->stream_res.tg->funcs->set_odm_combine(
pipe_ctx->stream_res.tg,
opp_inst, 2,
opp_inst, opp_cnt,
&pipe_ctx->stream->timing);
} else
else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
}
@ -848,7 +853,8 @@ void dcn20_blank_pixel_data(
struct dc_stream_state *stream = pipe_ctx->stream;
enum dc_color_space color_space = stream->output_color_space;
enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR;
struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
int odm_cnt = 1;
int width = stream->timing.h_addressable + stream->timing.h_border_left + stream->timing.h_border_right;
int height = stream->timing.v_addressable + stream->timing.v_border_bottom + stream->timing.v_border_top;
@ -856,8 +862,10 @@ void dcn20_blank_pixel_data(
/* get opp dpg blank color */
color_space_to_black_color(dc, color_space, &black_color);
if (bot_odm_pipe)
width = width / 2;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
odm_cnt++;
width = width / odm_cnt;
if (blank) {
if (stream_res->abm)
@ -877,9 +885,9 @@ void dcn20_blank_pixel_data(
width,
height);
if (bot_odm_pipe) {
bot_odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator(
bot_odm_pipe->stream_res.opp,
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator(
odm_pipe->stream_res.opp,
dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ?
CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern,
stream->timing.display_color_depth,
@ -1021,7 +1029,7 @@ static void dcn20_program_all_pipe_in_tree(
struct pipe_ctx *pipe_ctx,
struct dc_state *context)
{
if (pipe_ctx->top_pipe == NULL) {
if (pipe_ctx->top_pipe == NULL && !pipe_ctx->prev_odm_pipe) {
bool blank = !is_pipe_tree_visible(pipe_ctx);
pipe_ctx->stream_res.tg->funcs->program_global_sync(
@ -1312,8 +1320,8 @@ bool dcn20_update_bandwidth(
pipe_ctx->stream_res.tg->funcs->set_vtg_params(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
dc->hwss.blank_pixel_data(dc, pipe_ctx, blank);
if (pipe_ctx->prev_odm_pipe == NULL)
dc->hwss.blank_pixel_data(dc, pipe_ctx, blank);
}
pipe_ctx->plane_res.hubp->funcs->hubp_setup(
@ -1403,12 +1411,15 @@ static void dcn20_disable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx
{
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
struct dce_hwseq *hws = dc->hwseq;
struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
if (pipe_ctx->stream_res.dsc) {
struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
if (bot_odm_pipe)
dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true);
while (odm_pipe) {
dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
odm_pipe = odm_pipe->next_odm_pipe;
}
}
#endif
}
@ -1417,12 +1428,15 @@ static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx)
{
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
struct dce_hwseq *hws = dc->hwseq;
struct pipe_ctx *bot_odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
if (pipe_ctx->stream_res.dsc) {
struct pipe_ctx *odm_pipe = pipe_ctx->next_odm_pipe;
dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
if (bot_odm_pipe)
dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false);
while (odm_pipe) {
dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
odm_pipe = odm_pipe->next_odm_pipe;
}
}
#endif
}
@ -1552,18 +1566,22 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
struct encoder_unblank_param params = { { 0 } };
struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link;
params.odm = dc_res_get_odm_bottom_pipe(pipe_ctx);
struct pipe_ctx *odm_pipe;
params.opp_cnt = 1;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
params.opp_cnt++;
}
/* only 3 items below are used by unblank */
params.timing = pipe_ctx->stream->timing;
params.link_settings.link_rate = link_settings->link_rate;
if (dc_is_dp_signal(pipe_ctx->stream->signal)) {
if (optc1_is_two_pixels_per_containter(&stream->timing) || params.odm)
if (optc1_is_two_pixels_per_containter(&stream->timing) || params.opp_cnt)
params.timing.pix_clk_100hz /= 2;
pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine(
pipe_ctx->stream_res.stream_enc, params.odm);
pipe_ctx->stream_res.stream_enc, params.opp_cnt);
pipe_ctx->stream_res.stream_enc->funcs->dp_unblank(pipe_ctx->stream_res.stream_enc, &params);
}
@ -1654,7 +1672,7 @@ static void dcn20_reset_hw_ctx_wrap(
if (!pipe_ctx_old->stream)
continue;
if (pipe_ctx_old->top_pipe)
if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
continue;
if (!pipe_ctx->stream ||

View file

@ -1319,7 +1319,11 @@ static void get_pixel_clock_parameters(
struct pixel_clk_params *pixel_clk_params)
{
const struct dc_stream_state *stream = pipe_ctx->stream;
bool odm_combine = dc_res_get_odm_bottom_pipe(pipe_ctx) != NULL;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
pixel_clk_params->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
pixel_clk_params->encoder_object_id = stream->link->link_enc->id;
@ -1337,7 +1341,9 @@ static void get_pixel_clock_parameters(
if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
pixel_clk_params->color_depth = COLOR_DEPTH_888;
if (optc1_is_two_pixels_per_containter(&stream->timing) || odm_combine)
if (opp_cnt == 4)
pixel_clk_params->requested_pix_clk_100hz /= 4;
else if (optc1_is_two_pixels_per_containter(&stream->timing) || opp_cnt == 2)
pixel_clk_params->requested_pix_clk_100hz /= 2;
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING)
@ -1481,22 +1487,16 @@ static enum dc_status remove_dsc_from_stream_resource(struct dc *dc,
for (i = 0; i < MAX_PIPES; i++) {
if (new_ctx->res_ctx.pipe_ctx[i].stream == dc_stream && !new_ctx->res_ctx.pipe_ctx[i].top_pipe) {
pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i];
break;
if (pipe_ctx->stream_res.dsc)
release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc);
}
}
if (!pipe_ctx)
return DC_ERROR_UNEXPECTED;
if (pipe_ctx->stream_res.dsc) {
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
release_dsc(&new_ctx->res_ctx, dc->res_pool, &pipe_ctx->stream_res.dsc);
if (odm_pipe)
release_dsc(&new_ctx->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc);
}
return DC_OK;
else
return DC_OK;
}
#endif
@ -1595,17 +1595,94 @@ static void swizzle_to_dml_params(
}
}
static bool dcn20_split_stream_for_combine(
static bool dcn20_split_stream_for_odm(
struct resource_context *res_ctx,
const struct resource_pool *pool,
struct pipe_ctx *prev_odm_pipe,
struct pipe_ctx *next_odm_pipe)
{
int pipe_idx = next_odm_pipe->pipe_idx;
struct scaler_data *sd = &prev_odm_pipe->plane_res.scl_data;
struct pipe_ctx *sec_next_pipe = next_odm_pipe->next_odm_pipe;
int new_width;
*next_odm_pipe = *prev_odm_pipe;
next_odm_pipe->next_odm_pipe = sec_next_pipe;
next_odm_pipe->pipe_idx = pipe_idx;
next_odm_pipe->plane_res.mi = pool->mis[next_odm_pipe->pipe_idx];
next_odm_pipe->plane_res.hubp = pool->hubps[next_odm_pipe->pipe_idx];
next_odm_pipe->plane_res.ipp = pool->ipps[next_odm_pipe->pipe_idx];
next_odm_pipe->plane_res.xfm = pool->transforms[next_odm_pipe->pipe_idx];
next_odm_pipe->plane_res.dpp = pool->dpps[next_odm_pipe->pipe_idx];
next_odm_pipe->plane_res.mpcc_inst = pool->dpps[next_odm_pipe->pipe_idx]->inst;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
next_odm_pipe->stream_res.dsc = NULL;
#endif
if (prev_odm_pipe->next_odm_pipe && prev_odm_pipe->next_odm_pipe != next_odm_pipe) {
ASSERT(!next_odm_pipe->next_odm_pipe);
next_odm_pipe->next_odm_pipe = prev_odm_pipe->next_odm_pipe;
next_odm_pipe->next_odm_pipe->prev_odm_pipe = next_odm_pipe;
}
prev_odm_pipe->next_odm_pipe = next_odm_pipe;
next_odm_pipe->prev_odm_pipe = prev_odm_pipe;
ASSERT(next_odm_pipe->top_pipe == NULL);
if (prev_odm_pipe->plane_state) {
/* HACTIVE halved for odm combine */
sd->h_active /= 2;
/* Copy scl_data to secondary pipe */
next_odm_pipe->plane_res.scl_data = *sd;
/* Calculate new vp and recout for left pipe */
/* Need at least 16 pixels width per side */
if (sd->recout.x + 16 >= sd->h_active)
return false;
new_width = sd->h_active - sd->recout.x;
sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->recout.width - new_width));
sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->recout.width - new_width));
sd->recout.width = new_width;
/* Calculate new vp and recout for right pipe */
sd = &next_odm_pipe->plane_res.scl_data;
new_width = sd->recout.width + sd->recout.x - sd->h_active;
/* Need at least 16 pixels width per side */
if (new_width <= 16)
return false;
sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->recout.width - new_width));
sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->recout.width - new_width));
sd->recout.width = new_width;
sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->h_active - sd->recout.x));
sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->h_active - sd->recout.x));
sd->recout.x = 0;
}
next_odm_pipe->stream_res.opp = pool->opps[next_odm_pipe->pipe_idx];
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (next_odm_pipe->stream->timing.flags.DSC == 1) {
acquire_dsc(res_ctx, pool, &next_odm_pipe->stream_res.dsc);
ASSERT(next_odm_pipe->stream_res.dsc);
if (next_odm_pipe->stream_res.dsc == NULL)
return false;
}
#endif
return true;
}
static void dcn20_split_stream_for_mpc(
struct resource_context *res_ctx,
const struct resource_pool *pool,
struct pipe_ctx *primary_pipe,
struct pipe_ctx *secondary_pipe,
bool is_odm_combine)
struct pipe_ctx *secondary_pipe)
{
int pipe_idx = secondary_pipe->pipe_idx;
struct scaler_data *sd = &primary_pipe->plane_res.scl_data;
struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe;
int new_width;
*secondary_pipe = *primary_pipe;
secondary_pipe->bottom_pipe = sec_bot_pipe;
@ -1628,57 +1705,9 @@ static bool dcn20_split_stream_for_combine(
primary_pipe->bottom_pipe = secondary_pipe;
secondary_pipe->top_pipe = primary_pipe;
if (is_odm_combine) {
if (primary_pipe->plane_state) {
/* HACTIVE halved for odm combine */
sd->h_active /= 2;
/* Copy scl_data to secondary pipe */
secondary_pipe->plane_res.scl_data = *sd;
/* Calculate new vp and recout for left pipe */
/* Need at least 16 pixels width per side */
if (sd->recout.x + 16 >= sd->h_active)
return false;
new_width = sd->h_active - sd->recout.x;
sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->recout.width - new_width));
sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->recout.width - new_width));
sd->recout.width = new_width;
/* Calculate new vp and recout for right pipe */
sd = &secondary_pipe->plane_res.scl_data;
new_width = sd->recout.width + sd->recout.x - sd->h_active;
/* Need at least 16 pixels width per side */
if (new_width <= 16)
return false;
sd->viewport.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->recout.width - new_width));
sd->viewport_c.width -= dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->recout.width - new_width));
sd->recout.width = new_width;
sd->viewport.x += dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz, sd->h_active - sd->recout.x));
sd->viewport_c.x += dc_fixpt_floor(dc_fixpt_mul_int(
sd->ratios.horz_c, sd->h_active - sd->recout.x));
sd->recout.x = 0;
}
secondary_pipe->stream_res.opp = pool->opps[secondary_pipe->pipe_idx];
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (secondary_pipe->stream->timing.flags.DSC == 1) {
acquire_dsc(res_ctx, pool, &secondary_pipe->stream_res.dsc);
ASSERT(secondary_pipe->stream_res.dsc);
if (secondary_pipe->stream_res.dsc == NULL)
return false;
}
#endif
} else {
ASSERT(primary_pipe->plane_state);
resource_build_scaling_params(primary_pipe);
resource_build_scaling_params(secondary_pipe);
}
return true;
ASSERT(primary_pipe->plane_state);
resource_build_scaling_params(primary_pipe);
resource_build_scaling_params(secondary_pipe);
}
void dcn20_populate_dml_writeback_from_context(
@ -2108,20 +2137,24 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx)
struct pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i];
struct dc_stream_state *stream = pipe_ctx->stream;
struct dsc_config dsc_cfg;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
/* Only need to validate top pipe */
if (pipe_ctx->top_pipe || !stream || !stream->timing.flags.DSC)
if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe || !stream || !stream->timing.flags.DSC)
continue;
dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left
+ stream->timing.h_border_right;
dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left
+ stream->timing.h_border_right) / opp_cnt;
dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top
+ stream->timing.v_border_bottom;
if (dc_res_get_odm_bottom_pipe(pipe_ctx))
dsc_cfg.pic_width /= 2;
dsc_cfg.pixel_encoding = stream->timing.pixel_encoding;
dsc_cfg.color_depth = stream->timing.display_color_depth;
dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg;
dsc_cfg.dc_dsc_cfg.num_slices_h /= opp_cnt;
if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg))
return false;
@ -2145,6 +2178,8 @@ static struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc,
* if this primary pipe has a bottom pipe in prev. state
* and if the bottom pipe is still available (which it should be),
* pick that pipe as secondary
* Same logic applies for ODM pipes. Since mpo is not allowed with odm
* check in else case.
*/
if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe) {
preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].bottom_pipe->pipe_idx;
@ -2152,6 +2187,12 @@ static struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc,
secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
secondary_pipe->pipe_idx = preferred_pipe_idx;
}
} else if (dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe) {
preferred_pipe_idx = dc->current_state->res_ctx.pipe_ctx[primary_pipe->pipe_idx].next_odm_pipe->pipe_idx;
if (res_ctx->pipe_ctx[preferred_pipe_idx].stream == NULL) {
secondary_pipe = &res_ctx->pipe_ctx[preferred_pipe_idx];
secondary_pipe->pipe_idx = preferred_pipe_idx;
}
}
/*
@ -2222,6 +2263,38 @@ bool dcn20_fast_validate_bw(
if (!pipes)
return false;
/* merge previously split odm pipes since mode support needs to make the decision */
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
struct pipe_ctx *odm_pipe = pipe->next_odm_pipe;
if (pipe->prev_odm_pipe)
continue;
pipe->next_odm_pipe = NULL;
while (odm_pipe) {
struct pipe_ctx *next_odm_pipe = odm_pipe->next_odm_pipe;
odm_pipe->plane_state = NULL;
odm_pipe->stream = NULL;
odm_pipe->top_pipe = NULL;
odm_pipe->bottom_pipe = NULL;
odm_pipe->prev_odm_pipe = NULL;
odm_pipe->next_odm_pipe = NULL;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (odm_pipe->stream_res.dsc)
release_dsc(&context->res_ctx, dc->res_pool, &odm_pipe->stream_res.dsc);
#endif
/* Clear plane_res and stream_res */
memset(&odm_pipe->plane_res, 0, sizeof(odm_pipe->plane_res));
memset(&odm_pipe->stream_res, 0, sizeof(odm_pipe->stream_res));
odm_pipe = next_odm_pipe;
}
if (pipe->plane_state)
resource_build_scaling_params(pipe);
}
/* merge previously mpc split pipes since mode support needs to make the decision */
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe;
@ -2229,7 +2302,6 @@ bool dcn20_fast_validate_bw(
if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state)
continue;
/* merge previously split pipe since mode support needs to make the decision */
pipe->bottom_pipe = hsplit_pipe->bottom_pipe;
if (hsplit_pipe->bottom_pipe)
hsplit_pipe->bottom_pipe->top_pipe = pipe;
@ -2237,10 +2309,7 @@ bool dcn20_fast_validate_bw(
hsplit_pipe->stream = NULL;
hsplit_pipe->top_pipe = NULL;
hsplit_pipe->bottom_pipe = NULL;
#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
if (hsplit_pipe->stream_res.dsc && hsplit_pipe->stream_res.dsc != pipe->stream_res.dsc)
release_dsc(&context->res_ctx, dc->res_pool, &hsplit_pipe->stream_res.dsc);
#endif
/* Clear plane_res and stream_res */
memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res));
memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res));
@ -2353,10 +2422,9 @@ bool dcn20_fast_validate_bw(
if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) {
hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
ASSERT(hsplit_pipe);
if (!dcn20_split_stream_for_combine(
if (!dcn20_split_stream_for_odm(
&context->res_ctx, dc->res_pool,
pipe, hsplit_pipe,
true))
pipe, hsplit_pipe))
goto validate_fail;
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
dcn20_build_mapped_resource(dc, context, pipe->stream);
@ -2397,11 +2465,15 @@ bool dcn20_fast_validate_bw(
if (!hsplit_pipe)
continue;
if (!dcn20_split_stream_for_combine(
if (context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) {
if (!dcn20_split_stream_for_odm(
&context->res_ctx, dc->res_pool,
pipe, hsplit_pipe))
goto validate_fail;
} else
dcn20_split_stream_for_mpc(
&context->res_ctx, dc->res_pool,
pipe, hsplit_pipe,
context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]))
goto validate_fail;
pipe, hsplit_pipe);
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
}
} else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) {

View file

@ -460,7 +460,7 @@ void enc2_stream_encoder_dp_unblank(
uint64_t m_vid_l = n_vid;
/* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */
if (is_two_pixels_per_containter(&param->timing) || param->odm) {
if (is_two_pixels_per_containter(&param->timing) || param->opp_cnt) {
/*this logic should be the same in get_pixel_clock_parameters() */
n_multiply = 1;
}

View file

@ -297,6 +297,8 @@ struct pipe_ctx {
struct pipe_ctx *top_pipe;
struct pipe_ctx *bottom_pipe;
struct pipe_ctx *next_odm_pipe;
struct pipe_ctx *prev_odm_pipe;
#ifdef CONFIG_DRM_AMD_DC_DCN1_0
struct _vcs_dpi_display_dlg_regs_st dlg_regs;

View file

@ -91,7 +91,7 @@ struct encoder_unblank_param {
struct dc_link_settings link_settings;
struct dc_crtc_timing timing;
#ifdef CONFIG_DRM_AMD_DC_DCN2_0
bool odm;
int opp_cnt;
#endif
};

View file

@ -179,7 +179,4 @@ void update_audio_usage(
unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format);
struct pipe_ctx *dc_res_get_odm_bottom_pipe(struct pipe_ctx *pipe_ctx);
bool dc_res_is_odm_head_pipe(struct pipe_ctx *pipe_ctx);
#endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */