Commit b1f6d01c authored by Dmytro Laktyushkin's avatar Dmytro Laktyushkin Committed by Alex Deucher

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: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: default avatarCharlene Liu <Charlene.Liu@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent bad4c3e6
...@@ -1860,9 +1860,7 @@ static void commit_planes_do_stream_update(struct dc *dc, ...@@ -1860,9 +1860,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
for (j = 0; j < dc->res_pool->pipe_count; j++) { for (j = 0; j < dc->res_pool->pipe_count; j++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[j];
if (!pipe_ctx->top_pipe && if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe && pipe_ctx->stream == stream) {
pipe_ctx->stream &&
pipe_ctx->stream == stream) {
if (stream_update->periodic_interrupt0 && if (stream_update->periodic_interrupt0 &&
dc->hwss.setup_periodic_interrupt) dc->hwss.setup_periodic_interrupt)
...@@ -1888,7 +1886,7 @@ static void commit_planes_do_stream_update(struct dc *dc, ...@@ -1888,7 +1886,7 @@ static void commit_planes_do_stream_update(struct dc *dc,
if (stream_update->dither_option) { if (stream_update->dither_option) {
#if defined(CONFIG_DRM_AMD_DC_DCN2_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 #endif
resource_build_bit_depth_reduction_params(pipe_ctx->stream, resource_build_bit_depth_reduction_params(pipe_ctx->stream,
&pipe_ctx->stream->bit_depth_params); &pipe_ctx->stream->bit_depth_params);
...@@ -1896,10 +1894,12 @@ static void commit_planes_do_stream_update(struct dc *dc, ...@@ -1896,10 +1894,12 @@ static void commit_planes_do_stream_update(struct dc *dc,
&stream->bit_depth_params, &stream->bit_depth_params,
&stream->clamping); &stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #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, odm_pipe->stream_res.opp->funcs->opp_program_fmt(odm_pipe->stream_res.opp,
&stream->bit_depth_params, &stream->bit_depth_params,
&stream->clamping); &stream->clamping);
odm_pipe = odm_pipe->next_odm_pipe;
}
#endif #endif
} }
......
...@@ -3095,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link, ...@@ -3095,14 +3095,19 @@ static void set_crtc_test_pattern(struct dc_link *link,
controller_test_pattern, color_depth); controller_test_pattern, color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) { 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) { for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.opp; opp_cnt++;
bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params); width /= opp_cnt;
width /= 2;
bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp, 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, controller_test_pattern,
color_depth, color_depth,
NULL, NULL,
...@@ -3131,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link, ...@@ -3131,14 +3136,18 @@ static void set_crtc_test_pattern(struct dc_link *link,
color_depth); color_depth);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #if defined(CONFIG_DRM_AMD_DC_DCN2_0)
else if (opp->funcs->opp_set_disp_pattern_generator) { 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;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
if (bot_odm_pipe) { width /= opp_cnt;
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) {
struct output_pixel_processor *odm_opp = odm_pipe->stream_res.opp;
bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params); odm_opp->funcs->opp_program_bit_depth_reduction(odm_opp, &params);
width /= 2; odm_opp->funcs->opp_set_disp_pattern_generator(odm_opp,
bot_opp->funcs->opp_set_disp_pattern_generator(bot_opp,
CONTROLLER_DP_TEST_PATTERN_VIDEOMODE, CONTROLLER_DP_TEST_PATTERN_VIDEOMODE,
color_depth, color_depth,
NULL, NULL,
......
...@@ -275,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link, ...@@ -275,7 +275,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
if (pipes[i].stream != NULL && 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->link != NULL &&
pipes[i].stream_res.stream_enc != NULL) { pipes[i].stream_res.stream_enc != NULL) {
udelay(100); udelay(100);
...@@ -381,7 +381,11 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -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 display_stream_compressor *dsc = pipe_ctx->stream_res.dsc;
struct dc *core_dc = pipe_ctx->stream->ctx->dc; struct dc *core_dc = pipe_ctx->stream->ctx->dc;
struct dc_stream_state *stream = pipe_ctx->stream; 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) { if (enable) {
struct dsc_config dsc_cfg; struct dsc_config dsc_cfg;
...@@ -389,26 +393,24 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable) ...@@ -389,26 +393,24 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
enum optc_dsc_mode optc_dsc_mode; enum optc_dsc_mode optc_dsc_mode;
/* Enable DSC hw block */ /* 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.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.pixel_encoding = stream->timing.pixel_encoding;
dsc_cfg.color_depth = stream->timing.display_color_depth; dsc_cfg.color_depth = stream->timing.display_color_depth;
dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; 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;
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;
if (odm_pipe) { odm_dsc->funcs->dsc_set_config(odm_dsc, &dsc_cfg, &dsc_optc_cfg);
struct display_stream_compressor *bot_dsc = odm_pipe->stream_res.dsc; odm_dsc->funcs->dsc_enable(odm_dsc, odm_pipe->stream_res.opp->inst);
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);
} }
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; 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) ...@@ -449,7 +451,7 @@ void dp_set_dsc_on_stream(struct pipe_ctx *pipe_ctx, bool enable)
/* disable DSC block */ /* disable DSC block */
pipe_ctx->stream_res.dsc->funcs->dsc_disable(pipe_ctx->stream_res.dsc); 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); odm_pipe->stream_res.dsc->funcs->dsc_disable(odm_pipe->stream_res.dsc);
} }
} }
......
...@@ -1117,8 +1117,9 @@ struct pipe_ctx *resource_get_head_pipe_for_stream( ...@@ -1117,8 +1117,9 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
{ {
int i; int i;
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
if (res_ctx->pipe_ctx[i].stream == stream && if (res_ctx->pipe_ctx[i].stream == stream
!res_ctx->pipe_ctx[i].top_pipe) { && !res_ctx->pipe_ctx[i].top_pipe
&& !res_ctx->pipe_ctx[i].prev_odm_pipe) {
return &res_ctx->pipe_ctx[i]; return &res_ctx->pipe_ctx[i];
break; break;
} }
...@@ -1126,15 +1127,11 @@ struct pipe_ctx *resource_get_head_pipe_for_stream( ...@@ -1126,15 +1127,11 @@ struct pipe_ctx *resource_get_head_pipe_for_stream(
return NULL; 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 resource_context *res_ctx,
struct dc_stream_state *stream) struct pipe_ctx *head_pipe)
{ {
struct pipe_ctx *head_pipe, *tail_pipe; struct pipe_ctx *tail_pipe;
head_pipe = resource_get_head_pipe_for_stream(res_ctx, stream);
if (!head_pipe)
return NULL;
tail_pipe = head_pipe->bottom_pipe; tail_pipe = head_pipe->bottom_pipe;
...@@ -1150,31 +1147,20 @@ static struct pipe_ctx *resource_get_tail_pipe_for_stream( ...@@ -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 * A free_pipe for a stream is defined here as a pipe
* that has no surface attached yet * 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, struct dc_state *context,
const struct resource_pool *pool, const struct resource_pool *pool,
struct dc_stream_state *stream) struct pipe_ctx *head_pipe)
{ {
int i; int i;
struct resource_context *res_ctx = &context->res_ctx; 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) if (!head_pipe->plane_state)
return head_pipe; return head_pipe;
/* Re-use pipe already acquired for this stream if available*/ /* Re-use pipe already acquired for this stream if available*/
for (i = pool->pipe_count - 1; i >= 0; i--) { 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) { !res_ctx->pipe_ctx[i].plane_state) {
return &res_ctx->pipe_ctx[i]; return &res_ctx->pipe_ctx[i];
} }
...@@ -1188,8 +1174,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream( ...@@ -1188,8 +1174,7 @@ static struct pipe_ctx *acquire_free_pipe_for_stream(
if (!pool->funcs->acquire_idle_pipe_for_layer) if (!pool->funcs->acquire_idle_pipe_for_layer)
return NULL; 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) #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
...@@ -1203,7 +1188,7 @@ static int acquire_first_split_pipe( ...@@ -1203,7 +1188,7 @@ static int acquire_first_split_pipe(
for (i = 0; i < pool->pipe_count; i++) { for (i = 0; i < pool->pipe_count; i++) {
struct pipe_ctx *split_pipe = &res_ctx->pipe_ctx[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->plane_state == split_pipe->plane_state) {
split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe; split_pipe->top_pipe->bottom_pipe = split_pipe->bottom_pipe;
if (split_pipe->bottom_pipe) if (split_pipe->bottom_pipe)
...@@ -1264,39 +1249,41 @@ bool dc_add_plane_to_context( ...@@ -1264,39 +1249,41 @@ bool dc_add_plane_to_context(
return false; return false;
} }
tail_pipe = resource_get_tail_pipe_for_stream(&context->res_ctx, stream); /* retain new surface, but only once per stream */
ASSERT(tail_pipe); dc_plane_state_retain(plane_state);
free_pipe = acquire_free_pipe_for_stream(context, pool, stream); while (head_pipe) {
tail_pipe = resource_get_tail_pipe(&context->res_ctx, head_pipe);
ASSERT(tail_pipe);
#if defined(CONFIG_DRM_AMD_DC_DCN1_0) free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
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 */ #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
dc_plane_state_retain(plane_state); if (!free_pipe) {
free_pipe->plane_state = plane_state; int pipe_idx = acquire_first_split_pipe(&context->res_ctx, pool, stream);
if (pipe_idx >= 0)
if (head_pipe != free_pipe) { free_pipe = &context->res_ctx.pipe_ctx[pipe_idx];
free_pipe->stream_res.tg = tail_pipe->stream_res.tg; }
free_pipe->stream_res.abm = tail_pipe->stream_res.abm; #endif
free_pipe->stream_res.opp = tail_pipe->stream_res.opp; if (!free_pipe) {
free_pipe->stream_res.stream_enc = tail_pipe->stream_res.stream_enc; dc_plane_state_release(plane_state);
free_pipe->stream_res.audio = tail_pipe->stream_res.audio; return false;
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;
}
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*/ /* assign new surfaces*/
stream_status->plane_states[stream_status->plane_count] = plane_state; stream_status->plane_states[stream_status->plane_count] = plane_state;
...@@ -1305,35 +1292,6 @@ bool dc_add_plane_to_context( ...@@ -1305,35 +1292,6 @@ bool dc_add_plane_to_context(
return true; 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( bool dc_remove_plane_from_context(
const struct dc *dc, const struct dc *dc,
struct dc_stream_state *stream, struct dc_stream_state *stream,
...@@ -1360,12 +1318,6 @@ bool dc_remove_plane_from_context( ...@@ -1360,12 +1318,6 @@ bool dc_remove_plane_from_context(
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->plane_state == plane_state) { 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) if (pipe_ctx->top_pipe)
pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe; pipe_ctx->top_pipe->bottom_pipe = pipe_ctx->bottom_pipe;
...@@ -1380,13 +1332,10 @@ bool dc_remove_plane_from_context( ...@@ -1380,13 +1332,10 @@ bool dc_remove_plane_from_context(
* For head pipe detach surfaces from pipe for tail * For head pipe detach surfaces from pipe for tail
* pipe just zero it out * pipe just zero it out
*/ */
if (!pipe_ctx->top_pipe) { if (!pipe_ctx->top_pipe)
pipe_ctx->plane_state = NULL; pipe_ctx->plane_state = NULL;
if (!dc_res_get_odm_bottom_pipe(pipe_ctx)) else
pipe_ctx->bottom_pipe = NULL;
} else {
memset(pipe_ctx, 0, sizeof(*pipe_ctx)); memset(pipe_ctx, 0, sizeof(*pipe_ctx));
}
} }
} }
...@@ -1755,9 +1704,6 @@ enum dc_status dc_remove_stream_from_ctx( ...@@ -1755,9 +1704,6 @@ enum dc_status dc_remove_stream_from_ctx(
for (i = 0; i < MAX_PIPES; i++) { for (i = 0; i < MAX_PIPES; i++) {
if (new_ctx->res_ctx.pipe_ctx[i].stream == stream && if (new_ctx->res_ctx.pipe_ctx[i].stream == stream &&
!new_ctx->res_ctx.pipe_ctx[i].top_pipe) { !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]; del_pipe = &new_ctx->res_ctx.pipe_ctx[i];
ASSERT(del_pipe->stream_res.stream_enc); ASSERT(del_pipe->stream_res.stream_enc);
...@@ -1782,8 +1728,6 @@ enum dc_status dc_remove_stream_from_ctx( ...@@ -1782,8 +1728,6 @@ enum dc_status dc_remove_stream_from_ctx(
dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream); dc->res_pool->funcs->remove_stream_from_ctx(dc, new_ctx, stream);
memset(del_pipe, 0, sizeof(*del_pipe)); memset(del_pipe, 0, sizeof(*del_pipe));
if (odm_pipe)
memset(odm_pipe, 0, sizeof(*odm_pipe));
break; break;
} }
...@@ -2497,6 +2441,12 @@ void dc_resource_state_copy_construct( ...@@ -2497,6 +2441,12 @@ void dc_resource_state_copy_construct(
if (cur_pipe->bottom_pipe) if (cur_pipe->bottom_pipe)
cur_pipe->bottom_pipe = &dst_ctx->res_ctx.pipe_ctx[cur_pipe->bottom_pipe->pipe_idx]; 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++) { for (i = 0; i < dst_ctx->stream_count; i++) {
......
...@@ -1341,7 +1341,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( ...@@ -1341,7 +1341,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
struct drr_params params = {0}; struct drr_params params = {0};
unsigned int event_triggers = 0; unsigned int event_triggers = 0;
#if defined(CONFIG_DRM_AMD_DC_DCN2_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 #endif
if (dc->hwss.disable_stream_gating) { if (dc->hwss.disable_stream_gating) {
...@@ -1409,7 +1409,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( ...@@ -1409,7 +1409,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
&stream->bit_depth_params, &stream->bit_depth_params,
&stream->clamping); &stream->clamping);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) #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->funcs->opp_set_dyn_expansion(
odm_pipe->stream_res.opp, odm_pipe->stream_res.opp,
COLOR_SPACE_YCBCR601, COLOR_SPACE_YCBCR601,
...@@ -1420,6 +1420,7 @@ static enum dc_status apply_single_controller_ctx_to_hw( ...@@ -1420,6 +1420,7 @@ static enum dc_status apply_single_controller_ctx_to_hw(
odm_pipe->stream_res.opp, odm_pipe->stream_res.opp,
&stream->bit_depth_params, &stream->bit_depth_params,
&stream->clamping); &stream->clamping);
odm_pipe = odm_pipe->next_odm_pipe;
} }
#endif #endif
...@@ -2079,7 +2080,7 @@ enum dc_status dce110_apply_ctx_to_hw( ...@@ -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)) if (pipe_ctx_old->stream && !pipe_need_reprogram(pipe_ctx_old, pipe_ctx))
continue; continue;
if (pipe_ctx->top_pipe) if (pipe_ctx->top_pipe || pipe_ctx->prev_odm_pipe)
continue; continue;
status = apply_single_controller_ctx_to_hw( status = apply_single_controller_ctx_to_hw(
......
...@@ -2537,7 +2537,7 @@ struct pipe_ctx *find_top_pipe_for_stream( ...@@ -2537,7 +2537,7 @@ struct pipe_ctx *find_top_pipe_for_stream(
if (pipe_ctx->stream != stream) if (pipe_ctx->stream != stream)
continue; continue;
if (!pipe_ctx->top_pipe) if (!pipe_ctx->top_pipe && !pipe_ctx->prev_odm_pipe)
return pipe_ctx; return pipe_ctx;
} }
return NULL; return NULL;
......
...@@ -529,11 +529,9 @@ enum dc_status dcn20_enable_stream_timing( ...@@ -529,11 +529,9 @@ enum dc_status dcn20_enable_stream_timing(
struct dc_stream_state *stream = pipe_ctx->stream; struct dc_stream_state *stream = pipe_ctx->stream;
struct drr_params params = {0}; struct drr_params params = {0};
unsigned int event_triggers = 0; unsigned int event_triggers = 0;
struct pipe_ctx *odm_pipe;
int opp_cnt = 1;
#if defined(CONFIG_DRM_AMD_DC_DCN2_0) int opp_inst[MAX_PIPES] = { pipe_ctx->stream_res.opp->inst };
struct pipe_ctx *odm_pipe = dc_res_get_odm_bottom_pipe(pipe_ctx);
#endif
/* by upper caller loop, pipe0 is parent pipe and be called first. /* 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 * 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( ...@@ -544,14 +542,17 @@ enum dc_status dcn20_enable_stream_timing(
/* TODO check if timing_changed, disable stream if timing changed */ /* TODO check if timing_changed, disable stream if timing changed */
if (odm_pipe) { for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
int opp_inst[2] = { pipe_ctx->stream_res.opp->inst, odm_pipe->stream_res.opp->inst }; 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->funcs->set_odm_combine(
pipe_ctx->stream_res.tg, pipe_ctx->stream_res.tg,
opp_inst, 2, opp_inst, opp_cnt,
&pipe_ctx->stream->timing); &pipe_ctx->stream->timing);
}
/* HW program guide assume display already disable /* HW program guide assume display already disable
* by unplug sequence. OTG assume stop. * by unplug sequence. OTG assume stop.
*/ */
...@@ -575,7 +576,7 @@ enum dc_status dcn20_enable_stream_timing( ...@@ -575,7 +576,7 @@ enum dc_status dcn20_enable_stream_timing(
pipe_ctx->stream->signal, pipe_ctx->stream->signal,
true); 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->funcs->opp_pipe_clock_control(
odm_pipe->stream_res.opp, odm_pipe->stream_res.opp,
true); true);
...@@ -661,7 +662,7 @@ bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx, ...@@ -661,7 +662,7 @@ bool dcn20_set_output_transfer_func(struct pipe_ctx *pipe_ctx,
*/ */
if (mpc->funcs->power_on_mpc_mem_pwr) if (mpc->funcs->power_on_mpc_mem_pwr)
mpc->funcs->power_on_mpc_mem_pwr(mpc, mpcc_id, true); 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) { && mpc->funcs->set_output_gamma && stream->out_transfer_func) {
if (stream->out_transfer_func->type == TF_TYPE_HWPWL) if (stream->out_transfer_func->type == TF_TYPE_HWPWL)
params = &stream->out_transfer_func->pwl; params = &stream->out_transfer_func->pwl;
...@@ -823,17 +824,21 @@ bool dcn20_set_input_transfer_func(struct pipe_ctx *pipe_ctx, ...@@ -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) 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) { for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
int opp_inst[2] = { pipe_ctx->stream_res.opp->inst, opp_inst[opp_cnt] = odm_pipe->stream_res.opp->inst;
combine_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->funcs->set_odm_combine(
pipe_ctx->stream_res.tg, pipe_ctx->stream_res.tg,
opp_inst, 2, opp_inst, opp_cnt,
&pipe_ctx->stream->timing); &pipe_ctx->stream->timing);
} else else
pipe_ctx->stream_res.tg->funcs->set_odm_bypass( pipe_ctx->stream_res.tg->funcs->set_odm_bypass(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
} }
...@@ -848,7 +853,8 @@ void dcn20_blank_pixel_data( ...@@ -848,7 +853,8 @@ void dcn20_blank_pixel_data(
struct dc_stream_state *stream = pipe_ctx->stream; struct dc_stream_state *stream = pipe_ctx->stream;
enum dc_color_space color_space = stream->output_color_space; enum dc_color_space color_space = stream->output_color_space;
enum controller_dp_test_pattern test_pattern = CONTROLLER_DP_TEST_PATTERN_SOLID_COLOR; 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 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; 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( ...@@ -856,8 +862,10 @@ void dcn20_blank_pixel_data(
/* get opp dpg blank color */ /* get opp dpg blank color */
color_space_to_black_color(dc, color_space, &black_color); color_space_to_black_color(dc, color_space, &black_color);
if (bot_odm_pipe) for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
width = width / 2; odm_cnt++;
width = width / odm_cnt;
if (blank) { if (blank) {
if (stream_res->abm) if (stream_res->abm)
...@@ -877,9 +885,9 @@ void dcn20_blank_pixel_data( ...@@ -877,9 +885,9 @@ void dcn20_blank_pixel_data(
width, width,
height); height);
if (bot_odm_pipe) { for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe) {
bot_odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator( odm_pipe->stream_res.opp->funcs->opp_set_disp_pattern_generator(
bot_odm_pipe->stream_res.opp, odm_pipe->stream_res.opp,
dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ? dc->debug.visual_confirm != VISUAL_CONFIRM_DISABLE ?
CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern, CONTROLLER_DP_TEST_PATTERN_COLORRAMP : test_pattern,
stream->timing.display_color_depth, stream->timing.display_color_depth,
...@@ -1021,7 +1029,7 @@ static void dcn20_program_all_pipe_in_tree( ...@@ -1021,7 +1029,7 @@ static void dcn20_program_all_pipe_in_tree(
struct pipe_ctx *pipe_ctx, struct pipe_ctx *pipe_ctx,
struct dc_state *context) 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); bool blank = !is_pipe_tree_visible(pipe_ctx);
pipe_ctx->stream_res.tg->funcs->program_global_sync( pipe_ctx->stream_res.tg->funcs->program_global_sync(
...@@ -1312,8 +1320,8 @@ bool dcn20_update_bandwidth( ...@@ -1312,8 +1320,8 @@ bool dcn20_update_bandwidth(
pipe_ctx->stream_res.tg->funcs->set_vtg_params( pipe_ctx->stream_res.tg->funcs->set_vtg_params(
pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing); pipe_ctx->stream_res.tg, &pipe_ctx->stream->timing);
if (pipe_ctx->prev_odm_pipe == NULL)
dc->hwss.blank_pixel_data(dc, pipe_ctx, blank); dc->hwss.blank_pixel_data(dc, pipe_ctx, blank);
} }
pipe_ctx->plane_res.hubp->funcs->hubp_setup( 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 ...@@ -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 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
struct dce_hwseq *hws = dc->hwseq; 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) { 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); dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, true);
if (bot_odm_pipe) while (odm_pipe) {
dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, true); dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, true);
odm_pipe = odm_pipe->next_odm_pipe;
}
} }
#endif #endif
} }
...@@ -1417,12 +1428,15 @@ static void dcn20_enable_stream_gating(struct dc *dc, struct pipe_ctx *pipe_ctx) ...@@ -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 #ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
struct dce_hwseq *hws = dc->hwseq; 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) { 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); dcn20_dsc_pg_control(hws, pipe_ctx->stream_res.dsc->inst, false);
if (bot_odm_pipe) while (odm_pipe) {
dcn20_dsc_pg_control(hws, bot_odm_pipe->stream_res.dsc->inst, false); dcn20_dsc_pg_control(hws, odm_pipe->stream_res.dsc->inst, false);
odm_pipe = odm_pipe->next_odm_pipe;
}
} }
#endif #endif
} }
...@@ -1552,18 +1566,22 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx, ...@@ -1552,18 +1566,22 @@ void dcn20_unblank_stream(struct pipe_ctx *pipe_ctx,
struct encoder_unblank_param params = { { 0 } }; struct encoder_unblank_param params = { { 0 } };
struct dc_stream_state *stream = pipe_ctx->stream; struct dc_stream_state *stream = pipe_ctx->stream;
struct dc_link *link = stream->link; 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 */ /* only 3 items below are used by unblank */
params.timing = pipe_ctx->stream->timing; params.timing = pipe_ctx->stream->timing;
params.link_settings.link_rate = link_settings->link_rate; params.link_settings.link_rate = link_settings->link_rate;
if (dc_is_dp_signal(pipe_ctx->stream->signal)) { 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; params.timing.pix_clk_100hz /= 2;
pipe_ctx->stream_res.stream_enc->funcs->dp_set_odm_combine( 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); 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( ...@@ -1654,7 +1672,7 @@ static void dcn20_reset_hw_ctx_wrap(
if (!pipe_ctx_old->stream) if (!pipe_ctx_old->stream)
continue; continue;
if (pipe_ctx_old->top_pipe) if (pipe_ctx_old->top_pipe || pipe_ctx_old->prev_odm_pipe)
continue; continue;
if (!pipe_ctx->stream || if (!pipe_ctx->stream ||
......
...@@ -1319,7 +1319,11 @@ static void get_pixel_clock_parameters( ...@@ -1319,7 +1319,11 @@ static void get_pixel_clock_parameters(
struct pixel_clk_params *pixel_clk_params) struct pixel_clk_params *pixel_clk_params)
{ {
const struct dc_stream_state *stream = pipe_ctx->stream; 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->requested_pix_clk_100hz = stream->timing.pix_clk_100hz;
pixel_clk_params->encoder_object_id = stream->link->link_enc->id; pixel_clk_params->encoder_object_id = stream->link->link_enc->id;
...@@ -1337,7 +1341,9 @@ static void get_pixel_clock_parameters( ...@@ -1337,7 +1341,9 @@ static void get_pixel_clock_parameters(
if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422) if (stream->timing.pixel_encoding == PIXEL_ENCODING_YCBCR422)
pixel_clk_params->color_depth = COLOR_DEPTH_888; 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; pixel_clk_params->requested_pix_clk_100hz /= 2;
if (stream->timing.timing_3d_format == TIMING_3D_FORMAT_HW_FRAME_PACKING) 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, ...@@ -1481,22 +1487,16 @@ static enum dc_status remove_dsc_from_stream_resource(struct dc *dc,
for (i = 0; i < MAX_PIPES; i++) { 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) { 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]; 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) if (!pipe_ctx)
return DC_ERROR_UNEXPECTED; return DC_ERROR_UNEXPECTED;
else
if (pipe_ctx->stream_res.dsc) { return DC_OK;
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;
} }
#endif #endif
...@@ -1595,17 +1595,94 @@ static void swizzle_to_dml_params( ...@@ -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, struct resource_context *res_ctx,
const struct resource_pool *pool, const struct resource_pool *pool,
struct pipe_ctx *primary_pipe, struct pipe_ctx *primary_pipe,
struct pipe_ctx *secondary_pipe, struct pipe_ctx *secondary_pipe)
bool is_odm_combine)
{ {
int pipe_idx = secondary_pipe->pipe_idx; 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; struct pipe_ctx *sec_bot_pipe = secondary_pipe->bottom_pipe;
int new_width;
*secondary_pipe = *primary_pipe; *secondary_pipe = *primary_pipe;
secondary_pipe->bottom_pipe = sec_bot_pipe; secondary_pipe->bottom_pipe = sec_bot_pipe;
...@@ -1628,57 +1705,9 @@ static bool dcn20_split_stream_for_combine( ...@@ -1628,57 +1705,9 @@ static bool dcn20_split_stream_for_combine(
primary_pipe->bottom_pipe = secondary_pipe; primary_pipe->bottom_pipe = secondary_pipe;
secondary_pipe->top_pipe = primary_pipe; secondary_pipe->top_pipe = primary_pipe;
if (is_odm_combine) { ASSERT(primary_pipe->plane_state);
if (primary_pipe->plane_state) { resource_build_scaling_params(primary_pipe);
/* HACTIVE halved for odm combine */ resource_build_scaling_params(secondary_pipe);
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;
} }
void dcn20_populate_dml_writeback_from_context( void dcn20_populate_dml_writeback_from_context(
...@@ -2108,20 +2137,24 @@ static bool dcn20_validate_dsc(struct dc *dc, struct dc_state *new_ctx) ...@@ -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 pipe_ctx *pipe_ctx = &new_ctx->res_ctx.pipe_ctx[i];
struct dc_stream_state *stream = pipe_ctx->stream; struct dc_stream_state *stream = pipe_ctx->stream;
struct dsc_config dsc_cfg; 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 */ /* 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; continue;
dsc_cfg.pic_width = stream->timing.h_addressable + stream->timing.h_border_left dsc_cfg.pic_width = (stream->timing.h_addressable + stream->timing.h_border_left
+ stream->timing.h_border_right; + stream->timing.h_border_right) / opp_cnt;
dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top dsc_cfg.pic_height = stream->timing.v_addressable + stream->timing.v_border_top
+ stream->timing.v_border_bottom; + 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.pixel_encoding = stream->timing.pixel_encoding;
dsc_cfg.color_depth = stream->timing.display_color_depth; dsc_cfg.color_depth = stream->timing.display_color_depth;
dsc_cfg.dc_dsc_cfg = stream->timing.dsc_cfg; 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)) if (!pipe_ctx->stream_res.dsc->funcs->dsc_validate_stream(pipe_ctx->stream_res.dsc, &dsc_cfg))
return false; return false;
...@@ -2145,6 +2178,8 @@ static struct pipe_ctx *dcn20_find_secondary_pipe(struct dc *dc, ...@@ -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 * if this primary pipe has a bottom pipe in prev. state
* and if the bottom pipe is still available (which it should be), * and if the bottom pipe is still available (which it should be),
* pick that pipe as secondary * 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) { 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; 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, ...@@ -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 = &res_ctx->pipe_ctx[preferred_pipe_idx];
secondary_pipe->pipe_idx = 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( ...@@ -2222,6 +2263,38 @@ bool dcn20_fast_validate_bw(
if (!pipes) if (!pipes)
return false; 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++) { for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i]; struct pipe_ctx *pipe = &context->res_ctx.pipe_ctx[i];
struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe; struct pipe_ctx *hsplit_pipe = pipe->bottom_pipe;
...@@ -2229,7 +2302,6 @@ bool dcn20_fast_validate_bw( ...@@ -2229,7 +2302,6 @@ bool dcn20_fast_validate_bw(
if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state) if (!hsplit_pipe || hsplit_pipe->plane_state != pipe->plane_state)
continue; continue;
/* merge previously split pipe since mode support needs to make the decision */
pipe->bottom_pipe = hsplit_pipe->bottom_pipe; pipe->bottom_pipe = hsplit_pipe->bottom_pipe;
if (hsplit_pipe->bottom_pipe) if (hsplit_pipe->bottom_pipe)
hsplit_pipe->bottom_pipe->top_pipe = pipe; hsplit_pipe->bottom_pipe->top_pipe = pipe;
...@@ -2237,10 +2309,7 @@ bool dcn20_fast_validate_bw( ...@@ -2237,10 +2309,7 @@ bool dcn20_fast_validate_bw(
hsplit_pipe->stream = NULL; hsplit_pipe->stream = NULL;
hsplit_pipe->top_pipe = NULL; hsplit_pipe->top_pipe = NULL;
hsplit_pipe->bottom_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 */ /* Clear plane_res and stream_res */
memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res)); memset(&hsplit_pipe->plane_res, 0, sizeof(hsplit_pipe->plane_res));
memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res)); memset(&hsplit_pipe->stream_res, 0, sizeof(hsplit_pipe->stream_res));
...@@ -2353,10 +2422,9 @@ bool dcn20_fast_validate_bw( ...@@ -2353,10 +2422,9 @@ bool dcn20_fast_validate_bw(
if (!pipe->top_pipe && !pipe->plane_state && context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]) { 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); hsplit_pipe = dcn20_find_secondary_pipe(dc, &context->res_ctx, dc->res_pool, pipe);
ASSERT(hsplit_pipe); ASSERT(hsplit_pipe);
if (!dcn20_split_stream_for_combine( if (!dcn20_split_stream_for_odm(
&context->res_ctx, dc->res_pool, &context->res_ctx, dc->res_pool,
pipe, hsplit_pipe, pipe, hsplit_pipe))
true))
goto validate_fail; goto validate_fail;
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
dcn20_build_mapped_resource(dc, context, pipe->stream); dcn20_build_mapped_resource(dc, context, pipe->stream);
...@@ -2397,11 +2465,15 @@ bool dcn20_fast_validate_bw( ...@@ -2397,11 +2465,15 @@ bool dcn20_fast_validate_bw(
if (!hsplit_pipe) if (!hsplit_pipe)
continue; 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, &context->res_ctx, dc->res_pool,
pipe, hsplit_pipe, pipe, hsplit_pipe);
context->bw_ctx.dml.vba.ODMCombineEnabled[pipe_idx]))
goto validate_fail;
pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx; pipe_split_from[hsplit_pipe->pipe_idx] = pipe_idx;
} }
} else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) { } else if (hsplit_pipe && hsplit_pipe->plane_state == pipe->plane_state) {
......
...@@ -460,7 +460,7 @@ void enc2_stream_encoder_dp_unblank( ...@@ -460,7 +460,7 @@ void enc2_stream_encoder_dp_unblank(
uint64_t m_vid_l = n_vid; uint64_t m_vid_l = n_vid;
/* YCbCr 4:2:0 : Computed VID_M will be 2X the input rate */ /* 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() */ /*this logic should be the same in get_pixel_clock_parameters() */
n_multiply = 1; n_multiply = 1;
} }
......
...@@ -297,6 +297,8 @@ struct pipe_ctx { ...@@ -297,6 +297,8 @@ struct pipe_ctx {
struct pipe_ctx *top_pipe; struct pipe_ctx *top_pipe;
struct pipe_ctx *bottom_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 #ifdef CONFIG_DRM_AMD_DC_DCN1_0
struct _vcs_dpi_display_dlg_regs_st dlg_regs; struct _vcs_dpi_display_dlg_regs_st dlg_regs;
......
...@@ -91,7 +91,7 @@ struct encoder_unblank_param { ...@@ -91,7 +91,7 @@ struct encoder_unblank_param {
struct dc_link_settings link_settings; struct dc_link_settings link_settings;
struct dc_crtc_timing timing; struct dc_crtc_timing timing;
#ifdef CONFIG_DRM_AMD_DC_DCN2_0 #ifdef CONFIG_DRM_AMD_DC_DCN2_0
bool odm; int opp_cnt;
#endif #endif
}; };
......
...@@ -179,7 +179,4 @@ void update_audio_usage( ...@@ -179,7 +179,4 @@ void update_audio_usage(
unsigned int resource_pixel_format_to_bpp(enum surface_pixel_format format); 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_ */ #endif /* DRIVERS_GPU_DRM_AMD_DC_DEV_DC_INC_RESOURCE_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment