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

drm/amd/display: fix dcn pipe reset sequence

This change fixes dcn10 front end reset sequence. Previously we
would reset front end during flip which led to issues
in certain MPO and 4k/5k scenarios. We would also never properly
power gate our front end.
Signed-off-by: default avatarDmytro Laktyushkin <Dmytro.Laktyushkin@amd.com>
Reviewed-by: default avatarCharlene Liu <Charlene.Liu@amd.com>
Acked-by: default avatarHarry Wentland <Harry.Wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 7f524a0d
......@@ -2380,7 +2380,7 @@ static void amdgpu_dm_do_flip(
surface_updates->flip_addr = &addr;
dc_update_surfaces_for_stream(adev->dm.dc, surface_updates, 1, acrtc->stream);
dc_update_surfaces_and_stream(adev->dm.dc, surface_updates, 1, acrtc->stream, NULL);
DRM_DEBUG_DRIVER("%s Flipping to hi: 0x%x, low: 0x%x \n",
__func__,
......
......@@ -511,12 +511,14 @@ static void split_stream_across_pipes(
struct pipe_ctx *primary_pipe,
struct pipe_ctx *secondary_pipe)
{
int pipe_idx = secondary_pipe->pipe_idx;
if (!primary_pipe->surface)
return;
secondary_pipe->stream = primary_pipe->stream;
secondary_pipe->tg = primary_pipe->tg;
*secondary_pipe = *primary_pipe;
secondary_pipe->pipe_idx = pipe_idx;
secondary_pipe->mpcc = pool->mpcc[secondary_pipe->pipe_idx];
secondary_pipe->mi = pool->mis[secondary_pipe->pipe_idx];
secondary_pipe->ipp = pool->ipps[secondary_pipe->pipe_idx];
......@@ -528,8 +530,6 @@ static void split_stream_across_pipes(
}
primary_pipe->bottom_pipe = secondary_pipe;
secondary_pipe->top_pipe = primary_pipe;
secondary_pipe->surface = primary_pipe->surface;
secondary_pipe->pipe_dlg_param = primary_pipe->pipe_dlg_param;
resource_build_scaling_params(primary_pipe);
resource_build_scaling_params(secondary_pipe);
......@@ -1011,10 +1011,13 @@ bool dcn_validate_bandwidth(
dcn_bw_calc_rq_dlg_ttu(dc, v, hsplit_pipe);
} else if (hsplit_pipe && hsplit_pipe->surface == pipe->surface) {
/* merge previously split pipe */
if (pipe->bottom_pipe->bottom_pipe)
pipe->bottom_pipe->bottom_pipe->top_pipe = pipe;
memset(pipe->bottom_pipe, 0, sizeof(*pipe->bottom_pipe));
pipe->bottom_pipe = pipe->bottom_pipe->bottom_pipe;
pipe->bottom_pipe = hsplit_pipe->bottom_pipe;
if (hsplit_pipe->bottom_pipe)
hsplit_pipe->bottom_pipe->top_pipe = pipe;
hsplit_pipe->surface = NULL;
hsplit_pipe->stream = NULL;
hsplit_pipe->top_pipe = NULL;
hsplit_pipe->bottom_pipe = NULL;
resource_build_scaling_params(pipe);
}
/* for now important to do this after pipe split for building e2e params */
......
......@@ -963,11 +963,8 @@ bool dc_post_update_surfaces_to_stream(struct dc *dc)
for (i = 0; i < core_dc->res_pool->pipe_count; i++)
if (context->res_ctx.pipe_ctx[i].stream == NULL
|| context->res_ctx.pipe_ctx[i].surface == NULL) {
context->res_ctx.pipe_ctx[i].pipe_idx = i;
core_dc->hwss.power_down_front_end(
core_dc, &context->res_ctx.pipe_ctx[i]);
}
|| context->res_ctx.pipe_ctx[i].surface == NULL)
core_dc->hwss.power_down_front_end(core_dc, i);
/* 3rd param should be true, temp w/a for RV*/
#if defined(CONFIG_DRM_AMD_DC_DCN1_0)
......@@ -989,7 +986,6 @@ bool dc_commit_surfaces_to_stream(
struct dc_plane_info plane_info[MAX_SURFACES];
struct dc_scaling_info scaling_info[MAX_SURFACES];
int i;
bool ret;
struct dc_stream_update *stream_update =
dm_alloc(sizeof(struct dc_stream_update));
......@@ -1038,10 +1034,10 @@ bool dc_commit_surfaces_to_stream(
new_surface_count,
dc_stream, stream_update);
ret = dc_post_update_surfaces_to_stream(dc);
dc_post_update_surfaces_to_stream(dc);
dm_free(stream_update);
return ret;
return true;
}
static bool is_surface_in_context(
......@@ -1217,14 +1213,6 @@ enum surface_update_type dc_check_update_surfaces_for_stream(
return overall_type;
}
void dc_update_surfaces_for_stream(struct dc *dc,
struct dc_surface_update *surface_updates, int surface_count,
const struct dc_stream *dc_stream)
{
dc_update_surfaces_and_stream(dc, surface_updates, surface_count,
dc_stream, NULL);
}
enum surface_update_type update_surface_trace_level = UPDATE_TYPE_FULL;
void dc_update_surfaces_and_stream(struct dc *dc,
......@@ -1401,7 +1389,7 @@ void dc_update_surfaces_and_stream(struct dc *dc,
}
}
if (!surface_count) /* reset */
if (surface_count == 0)
core_dc->hwss.apply_ctx_for_surface(core_dc, NULL, context);
/* Lock pipes for provided surfaces, or all active if full update*/
......
......@@ -1096,6 +1096,10 @@ bool resource_attach_surfaces_to_context(
free_pipe->surface = surface;
if (tail_pipe) {
free_pipe->tg = tail_pipe->tg;
free_pipe->stream_enc = tail_pipe->stream_enc;
free_pipe->audio = tail_pipe->audio;
free_pipe->clock_source = tail_pipe->clock_source;
free_pipe->top_pipe = tail_pipe;
tail_pipe->bottom_pipe = free_pipe;
}
......@@ -2300,6 +2304,9 @@ bool pipe_need_reprogram(
struct pipe_ctx *pipe_ctx_old,
struct pipe_ctx *pipe_ctx)
{
if (!pipe_ctx_old->stream)
return false;
if (pipe_ctx_old->stream->sink != pipe_ctx->stream->sink)
return true;
......
......@@ -415,9 +415,6 @@ bool dc_commit_surfaces_to_stream(
bool dc_post_update_surfaces_to_stream(
struct dc *dc);
void dc_update_surfaces_for_stream(struct dc *dc, struct dc_surface_update *updates,
int surface_count, const struct dc_stream *stream);
/* Surface update type is used by dc_update_surfaces_and_stream
* The update type is determined at the very beginning of the function based
* on parameters passed in and decides how much programming (or updating) is
......
......@@ -1185,8 +1185,7 @@ static void disable_vga_and_power_gate_all_controllers(
enable_display_pipe_clock_gating(ctx,
true);
dc->hwss.power_down_front_end(
dc, &dc->current_context->res_ctx.pipe_ctx[i]);
dc->hwss.power_down_front_end(dc, i);
}
}
......@@ -1340,7 +1339,7 @@ static void reset_single_pipe_hw_ctx(
resource_unreference_clock_source(&context->res_ctx, dc->res_pool,
&pipe_ctx->clock_source);
dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx);
dc->hwss.power_down_front_end((struct core_dc *)dc, pipe_ctx->pipe_idx);
pipe_ctx->stream = NULL;
}
......@@ -2538,17 +2537,17 @@ static void dce110_apply_ctx_for_surface(
}
}
static void dce110_power_down_fe(struct core_dc *dc, struct pipe_ctx *pipe)
static void dce110_power_down_fe(struct core_dc *dc, int fe_idx)
{
/* Do not power down fe when stream is active on dce*/
if (pipe->stream)
if (dc->current_context->res_ctx.pipe_ctx[fe_idx].stream)
return;
dc->hwss.enable_display_power_gating(
dc, pipe->pipe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE);
if (pipe->xfm)
pipe->xfm->funcs->transform_reset(pipe->xfm);
memset(&pipe->scl_data, 0, sizeof(struct scaler_data));
dc, fe_idx, dc->ctx->dc_bios, PIPE_GATING_CONTROL_ENABLE);
dc->res_pool->transforms[fe_idx]->funcs->transform_reset(
dc->res_pool->transforms[fe_idx]);
}
static const struct hw_sequencer_funcs dce110_funcs = {
......
......@@ -65,17 +65,17 @@ void dcn10_mpcc_set_bg_color(
static void set_output_mux(struct dcn10_mpcc *mpcc10, int opp_id, int mpcc_id)
{
ASSERT(mpcc10->opp_id == 0xf || opp_id == mpcc10->opp_id);
mpcc10->opp_id = opp_id;
ASSERT(mpcc10->base.opp_id == 0xf || opp_id == mpcc10->base.opp_id);
mpcc10->base.opp_id = opp_id;
REG_UPDATE(OPP_PIPE_CONTROL[opp_id], OPP_PIPE_CLOCK_EN, 1);
REG_SET(MUX[opp_id], 0, MPC_OUT_MUX, mpcc_id);
}
static void reset_output_mux(struct dcn10_mpcc *mpcc10)
{
REG_SET(MUX[mpcc10->opp_id], 0, MPC_OUT_MUX, 0xf);
REG_UPDATE(OPP_PIPE_CONTROL[mpcc10->opp_id], OPP_PIPE_CLOCK_EN, 0);
mpcc10->opp_id = 0xf;
REG_SET(MUX[mpcc10->base.opp_id], 0, MPC_OUT_MUX, 0xf);
REG_UPDATE(OPP_PIPE_CONTROL[mpcc10->base.opp_id], OPP_PIPE_CLOCK_EN, 0);
mpcc10->base.opp_id = 0xf;
}
static void dcn10_mpcc_set(struct mpcc *mpcc, struct mpcc_cfg *cfg)
......@@ -104,16 +104,17 @@ static void dcn10_mpcc_set(struct mpcc *mpcc, struct mpcc_cfg *cfg)
if (cfg->top_of_tree) {
if (cfg->opp_id != 0xf)
set_output_mux(mpcc10, cfg->opp_id, mpcc->inst);
else
else if (mpcc->opp_id != 0xf)
reset_output_mux(mpcc10);
}
mpcc10->base.opp_id = cfg->opp_id;
}
static void dcn10_mpcc_wait_idle(struct mpcc *mpcc)
{
struct dcn10_mpcc *mpcc10 = TO_DCN10_MPCC(mpcc);
REG_WAIT(MPCC_STATUS, MPCC_IDLE, 1, 1000, 1000);
REG_WAIT(MPCC_STATUS, MPCC_BUSY, 0, 1000, 1000);
}
......@@ -139,5 +140,5 @@ void dcn10_mpcc_construct(struct dcn10_mpcc *mpcc10,
mpcc10->mpcc_shift = mpcc_shift;
mpcc10->mpcc_mask = mpcc_mask;
mpcc10->opp_id = inst;
mpcc10->base.opp_id = inst;
}
......@@ -68,6 +68,7 @@ struct dcn_mpcc_registers {
SF(MPCC0_MPCC_CONTROL, MPCC_ALPHA_MULTIPLIED_MODE, mask_sh),\
SF(MPCC0_MPCC_CONTROL, MPCC_BLND_ACTIVE_OVERLAP_ONLY, mask_sh),\
SF(MPCC0_MPCC_STATUS, MPCC_IDLE, mask_sh),\
SF(MPCC0_MPCC_STATUS, MPCC_BUSY, mask_sh),\
SF(MPCC0_MPCC_OPP_ID, MPCC_OPP_ID, mask_sh),\
SF(MPCC0_MPCC_BG_G_Y, MPCC_BG_G_Y, mask_sh),\
SF(MPCC0_MPCC_BG_R_CR, MPCC_BG_R_CR, mask_sh),\
......@@ -83,6 +84,7 @@ struct dcn_mpcc_registers {
type MPCC_ALPHA_MULTIPLIED_MODE;\
type MPCC_BLND_ACTIVE_OVERLAP_ONLY;\
type MPCC_IDLE;\
type MPCC_BUSY;\
type MPCC_OPP_ID;\
type MPCC_BG_G_Y;\
type MPCC_BG_R_CR;\
......@@ -103,8 +105,6 @@ struct dcn10_mpcc {
const struct dcn_mpcc_registers *mpcc_regs;
const struct dcn_mpcc_shift *mpcc_shift;
const struct dcn_mpcc_mask *mpcc_mask;
int opp_id;
};
void dcn10_mpcc_construct(struct dcn10_mpcc *mpcc10,
......
......@@ -575,6 +575,8 @@ void dcn10_lock(struct timing_generator *tg)
{
struct dcn10_timing_generator *tgn10 = DCN10TG_FROM_TG(tg);
REG_SET(OTG_GLOBAL_CONTROL0, 0,
OTG_MASTER_UPDATE_LOCK_SEL, tg->inst);
REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
OTG_MASTER_UPDATE_LOCK, 1);
}
......@@ -587,9 +589,9 @@ void dcn10_unlock(struct timing_generator *tg)
OTG_MASTER_UPDATE_LOCK, 0);
/* why are we waiting here? */
REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL,
/*REG_WAIT(OTG_DOUBLE_BUFFER_CONTROL,
OTG_UPDATE_PENDING, 0,
20000, 200000);
20000, 200000);*/
}
static void dcn10_get_position(struct timing_generator *tg,
......
......@@ -37,6 +37,7 @@
SRI(OTG_VREADY_PARAM, OTG, inst),\
SRI(OTG_BLANK_CONTROL, OTG, inst),\
SRI(OTG_MASTER_UPDATE_LOCK, OTG, inst),\
SRI(OTG_GLOBAL_CONTROL0, OTG, inst),\
SRI(OTG_DOUBLE_BUFFER_CONTROL, OTG, inst),\
SRI(OTG_H_TOTAL, OTG, inst),\
SRI(OTG_H_BLANK_START_END, OTG, inst),\
......@@ -83,6 +84,7 @@ struct dcn_tg_registers {
uint32_t OTG_VREADY_PARAM;
uint32_t OTG_BLANK_CONTROL;
uint32_t OTG_MASTER_UPDATE_LOCK;
uint32_t OTG_GLOBAL_CONTROL0;
uint32_t OTG_DOUBLE_BUFFER_CONTROL;
uint32_t OTG_H_TOTAL;
uint32_t OTG_H_BLANK_START_END;
......@@ -134,6 +136,7 @@ struct dcn_tg_registers {
SF(OTG0_OTG_BLANK_CONTROL, OTG_BLANK_DE_MODE, mask_sh),\
SF(OTG0_OTG_BLANK_CONTROL, OTG_CURRENT_BLANK_STATE, mask_sh),\
SF(OTG0_OTG_MASTER_UPDATE_LOCK, OTG_MASTER_UPDATE_LOCK, mask_sh),\
SF(OTG0_OTG_GLOBAL_CONTROL0, OTG_MASTER_UPDATE_LOCK_SEL, mask_sh),\
SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_UPDATE_PENDING, mask_sh),\
SF(OTG0_OTG_DOUBLE_BUFFER_CONTROL, OTG_BLANK_DATA_DOUBLE_BUFFER_EN, mask_sh),\
SF(OTG0_OTG_H_TOTAL, OTG_H_TOTAL, mask_sh),\
......@@ -224,6 +227,7 @@ struct dcn_tg_registers {
type OTG_CURRENT_BLANK_STATE;\
type OTG_MASTER_UPDATE_LOCK;\
type OTG_UPDATE_PENDING;\
type OTG_MASTER_UPDATE_LOCK_SEL;\
type OTG_BLANK_DATA_DOUBLE_BUFFER_EN;\
type OTG_H_TOTAL;\
type OTG_H_BLANK_START;\
......
......@@ -40,6 +40,7 @@ struct mpcc {
const struct mpcc_funcs *funcs;
struct dc_context *ctx;
int inst;
int opp_id;
};
struct mpcc_funcs {
......
......@@ -105,7 +105,7 @@ struct hw_sequencer_funcs {
struct dc_bios *dcb,
enum pipe_gating_control power_gating);
void (*power_down_front_end)(struct core_dc *dc, struct pipe_ctx *pipe);
void (*power_down_front_end)(struct core_dc *dc, int fe_idx);
void (*power_on_front_end)(struct core_dc *dc,
struct pipe_ctx *pipe,
......
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