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,
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
}
......
......@@ -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;
for (odm_pipe = pipe_ctx->next_odm_pipe; odm_pipe; odm_pipe = odm_pipe->next_odm_pipe)
opp_cnt++;
if (bot_odm_pipe) {
struct output_pixel_processor *bot_opp = bot_odm_pipe->stream_res.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;
bot_opp->funcs->opp_program_bit_depth_reduction(bot_opp, &params);
width /= 2;
bot_opp->funcs->opp_set_disp_pattern_generator(bot_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,
......
......@@ -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;
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) {
struct display_stream_compressor *bot_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);
}
}
......
......@@ -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);
/* retain new surface, but only once per stream */
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)
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;
free_pipe = acquire_free_pipe_for_head(context, pool, head_pipe);
/* retain new surfaces */
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;
}
#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++) {
......
......@@ -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(
......
......@@ -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;
......
......@@ -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 ||
......
......@@ -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;
}
......
......@@ -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;
......
......@@ -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
};
......
......@@ -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_ */
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