Commit 6c5be4ac authored by Wenjing Liu's avatar Wenjing Liu Committed by Alex Deucher

drm/amd/display: add global master update lock for DCN2

[why]
when an update programming sequence requires both
front end and back end pipe to be updated synchronously,
a global update lock needs to be set to ensure that
we don't get a frame with only front end update but
not the back end update.

[how]
setup global lock parameters on enable_stream_timing.
enable global lock when pipe_control_lock_global is called.
disable global lock when pipe_control_lock is called.
Signed-off-by: default avatarWenjing Liu <Wenjing.Liu@amd.com>
Reviewed-by: default avatarTony Cheng <Tony.Cheng@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 64f223b0
......@@ -727,6 +727,10 @@ enum dc_status dcn20_enable_stream_timing(
pipe_ctx->stream->signal,
true);
if (pipe_ctx->stream_res.tg->funcs->setup_global_lock)
pipe_ctx->stream_res.tg->funcs->setup_global_lock(
pipe_ctx->stream_res.tg);
/* program otg blank color */
color_space = stream->output_color_space;
color_space_to_black_color(dc, color_space, &black_color);
......
......@@ -330,6 +330,65 @@ void optc2_triplebuffer_unlock(struct timing_generator *optc)
}
void optc2_setup_global_lock(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
uint32_t v_blank_start = 0;
uint32_t h_blank_start = 0, h_total = 0;
REG_SET(OTG_GLOBAL_CONTROL1, 0, MASTER_UPDATE_LOCK_DB_EN, 1);
REG_SET(OTG_GLOBAL_CONTROL2, 0, DIG_UPDATE_LOCATION, 20);
REG_GET(OTG_V_BLANK_START_END, OTG_V_BLANK_START, &v_blank_start);
REG_GET(OTG_H_BLANK_START_END, OTG_H_BLANK_START, &h_blank_start);
REG_GET(OTG_H_TOTAL, OTG_H_TOTAL, &h_total);
REG_UPDATE_2(OTG_GLOBAL_CONTROL1,
MASTER_UPDATE_LOCK_DB_X,
h_blank_start - 200 - 1,
MASTER_UPDATE_LOCK_DB_Y,
v_blank_start - 1);
}
void optc2_lock_global(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 1);
REG_SET(OTG_GLOBAL_CONTROL0, 0,
OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
OTG_MASTER_UPDATE_LOCK, 1);
/* Should be fast, status does not update on maximus */
if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
REG_WAIT(OTG_MASTER_UPDATE_LOCK,
UPDATE_LOCK_STATUS, 1,
1, 10);
}
void optc2_lock(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_UPDATE(OTG_GLOBAL_CONTROL2, GLOBAL_UPDATE_LOCK_EN, 0);
REG_SET(OTG_GLOBAL_CONTROL0, 0,
OTG_MASTER_UPDATE_LOCK_SEL, optc->inst);
REG_SET(OTG_MASTER_UPDATE_LOCK, 0,
OTG_MASTER_UPDATE_LOCK, 1);
/* Should be fast, status does not update on maximus */
if (optc->ctx->dce_environment != DCE_ENV_FPGA_MAXIMUS)
REG_WAIT(OTG_MASTER_UPDATE_LOCK,
UPDATE_LOCK_STATUS, 1,
1, 10);
}
void optc2_lock_doublebuffer_enable(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
......@@ -424,8 +483,10 @@ static struct timing_generator_funcs dcn20_tg_funcs = {
.triplebuffer_lock = optc2_triplebuffer_lock,
.triplebuffer_unlock = optc2_triplebuffer_unlock,
.disable_reset_trigger = optc1_disable_reset_trigger,
.lock = optc1_lock,
.lock = optc2_lock,
.unlock = optc1_unlock,
.lock_global = optc2_lock_global,
.setup_global_lock = optc2_setup_global_lock,
.lock_doublebuffer_enable = optc2_lock_doublebuffer_enable,
.lock_doublebuffer_disable = optc2_lock_doublebuffer_disable,
.enable_optc_clock = optc1_enable_optc_clock,
......
......@@ -104,6 +104,9 @@ void optc2_get_optc_source(struct timing_generator *optc,
void optc2_triplebuffer_lock(struct timing_generator *optc);
void optc2_triplebuffer_unlock(struct timing_generator *optc);
void optc2_lock(struct timing_generator *optc);
void optc2_lock_global(struct timing_generator *optc);
void optc2_setup_global_lock(struct timing_generator *optc);
void optc2_lock_doublebuffer_disable(struct timing_generator *optc);
void optc2_lock_doublebuffer_enable(struct timing_generator *optc);
void optc2_program_manual_trigger(struct timing_generator *optc);
......
......@@ -184,8 +184,10 @@ struct timing_generator_funcs {
bool (*did_triggered_reset_occur)(struct timing_generator *tg);
void (*setup_global_swap_lock)(struct timing_generator *tg,
const struct dcp_gsl_params *gsl_params);
void (*setup_global_lock)(struct timing_generator *tg);
void (*unlock)(struct timing_generator *tg);
void (*lock)(struct timing_generator *tg);
void (*lock_global)(struct timing_generator *tg);
void (*lock_doublebuffer_disable)(struct timing_generator *tg);
void (*lock_doublebuffer_enable)(struct timing_generator *tg);
#if defined(CONFIG_DRM_AMD_DC_DCN2_0)
......
......@@ -205,6 +205,7 @@ struct hw_sequencer_funcs {
struct dc *dc,
struct pipe_ctx *pipe,
bool lock);
void (*pipe_control_lock_global)(
struct 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