Commit e63e2491 authored by Eryk Brol's avatar Eryk Brol Committed by Alex Deucher

drm/amd/display: Ensure DRR triggers in BP

[Why]
In the previous implementation DRR event sometimes came
in during FP2 region which is a keep-out zone. This
would cause the frame not to latch until the next frame
which resulted in heavy flicker. To fix this we need
to make sure that it triggers in the BP.

[How]
1. Remove DRR programming during flip
2. Setup manual trigger for DRR event and trigger it
after surface programming is complete
Signed-off-by: default avatarEryk Brol <eryk.brol@amd.com>
Reviewed-by: default avatarAric Cyr <Aric.Cyr@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 313a9a21
......@@ -5127,6 +5127,11 @@ static void update_freesync_state_on_stream(
amdgpu_dm_vrr_active(new_crtc_state)) {
mod_freesync_handle_v_update(dm->freesync_module,
new_stream, &vrr_params);
/* Need to call this before the frame ends. */
dc_stream_adjust_vmin_vmax(dm->dc,
new_crtc_state->stream,
&vrr_params.adjust);
}
}
......@@ -5465,11 +5470,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
}
if (acrtc_state->stream) {
if (acrtc_state->freesync_timing_changed)
bundle->stream_update.adjust =
&acrtc_state->stream->adjust;
if (acrtc_state->freesync_vrr_info_changed)
bundle->stream_update.vrr_infopacket =
&acrtc_state->stream->vrr_infopacket;
......@@ -5490,6 +5490,20 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
if (acrtc_state->abm_level != dm_old_crtc_state->abm_level)
bundle->stream_update.abm_level = &acrtc_state->abm_level;
/*
* If FreeSync state on the stream has changed then we need to
* re-adjust the min/max bounds now that DC doesn't handle this
* as part of commit.
*/
if (amdgpu_dm_vrr_active(dm_old_crtc_state) !=
amdgpu_dm_vrr_active(acrtc_state)) {
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
dc_stream_adjust_vmin_vmax(
dm->dc, acrtc_state->stream,
&acrtc_state->vrr_params.adjust);
spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags);
}
mutex_lock(&dm->dc_lock);
dc_commit_updates_for_stream(dm->dc,
bundle->surface_updates,
......
......@@ -263,7 +263,7 @@ bool dc_stream_adjust_vmin_vmax(struct dc *dc,
for (i = 0; i < MAX_PIPES; i++) {
struct pipe_ctx *pipe = &dc->current_state->res_ctx.pipe_ctx[i];
if (pipe->stream == stream && pipe->stream_res.stream_enc) {
if (pipe->stream == stream && pipe->stream_res.tg) {
pipe->stream->adjust = *adjust;
dc->hwss.set_drr(&pipe,
1,
......@@ -1745,13 +1745,6 @@ static void commit_planes_do_stream_update(struct dc *dc,
pipe_ctx->stream &&
pipe_ctx->stream == stream) {
/* Fast update*/
// VRR program can be done as part of FAST UPDATE
if (stream_update->adjust)
dc->hwss.set_drr(&pipe_ctx, 1,
stream_update->adjust->v_total_min,
stream_update->adjust->v_total_max);
if (stream_update->periodic_interrupt0 &&
dc->hwss.setup_periodic_interrupt)
dc->hwss.setup_periodic_interrupt(pipe_ctx, VLINE0);
......@@ -1909,6 +1902,20 @@ static void commit_planes_for_stream(struct dc *dc,
dc->hwss.pipe_control_lock(dc, top_pipe_to_program, false);
}
// Fire manual trigger
for (i = 0; i < dc->res_pool->pipe_count; i++) {
struct pipe_ctx *pipe_ctx = &context->res_ctx.pipe_ctx[i];
if (pipe_ctx->top_pipe ||
!pipe_ctx->stream ||
pipe_ctx->stream != stream ||
!srf_updates[i].flip_addr)
continue;
if (pipe_ctx->stream_res.tg->funcs->program_manual_trigger)
pipe_ctx->stream_res.tg->funcs->program_manual_trigger(pipe_ctx->stream_res.tg);
}
}
void dc_commit_updates_for_stream(struct dc *dc,
......
......@@ -172,7 +172,6 @@ struct dc_stream_update {
struct periodic_interrupt_config *periodic_interrupt0;
struct periodic_interrupt_config *periodic_interrupt1;
struct dc_crtc_timing_adjust *adjust;
struct dc_info_packet *vrr_infopacket;
struct dc_info_packet *vsc_infopacket;
struct dc_info_packet *vsp_infopacket;
......
......@@ -2506,8 +2506,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
{
int i = 0;
struct drr_params params = {0};
// DRR should set trigger event to monitor surface update event
unsigned int event_triggers = 0x80;
// DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
unsigned int event_triggers = 0x800;
params.vertical_total_max = vmax;
params.vertical_total_min = vmin;
......
......@@ -791,6 +791,32 @@ void optc1_set_static_screen_control(
OTG_STATIC_SCREEN_FRAME_COUNT, 2);
}
void optc1_setup_manual_trigger(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_SET(OTG_GLOBAL_CONTROL2, 0,
MANUAL_FLOW_CONTROL_SEL, optc->inst);
REG_SET_8(OTG_TRIGA_CNTL, 0,
OTG_TRIGA_SOURCE_SELECT, 22,
OTG_TRIGA_SOURCE_PIPE_SELECT, optc->inst,
OTG_TRIGA_RISING_EDGE_DETECT_CNTL, 1,
OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, 0,
OTG_TRIGA_POLARITY_SELECT, 0,
OTG_TRIGA_FREQUENCY_SELECT, 0,
OTG_TRIGA_DELAY, 0,
OTG_TRIGA_CLEAR, 1);
}
void optc1_program_manual_trigger(struct timing_generator *optc)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
REG_SET(OTG_MANUAL_FLOW_CONTROL, 0,
MANUAL_FLOW_CONTROL, 1);
}
/**
*****************************************************************************
......@@ -823,6 +849,10 @@ void optc1_set_drr(
OTG_FORCE_LOCK_ON_EVENT, 0,
OTG_SET_V_TOTAL_MIN_MASK_EN, 0,
OTG_SET_V_TOTAL_MIN_MASK, 0);
// Setup manual flow control for EOF via TRIG_A
optc->funcs->setup_manual_trigger(optc);
} else {
REG_UPDATE_4(OTG_V_TOTAL_CONTROL,
OTG_SET_V_TOTAL_MIN_MASK, 0,
......@@ -1458,6 +1488,8 @@ static const struct timing_generator_funcs dcn10_tg_funcs = {
.get_crc = optc1_get_crc,
.configure_crc = optc1_configure_crc,
.set_vtg_params = optc1_set_vtg_params,
.program_manual_trigger = optc1_program_manual_trigger,
.setup_manual_trigger = optc1_setup_manual_trigger
};
void dcn10_timing_generator_init(struct optc *optc1)
......
......@@ -85,13 +85,17 @@
SRI(OTG_CRC0_WINDOWA_Y_CONTROL, OTG, inst),\
SRI(OTG_CRC0_WINDOWB_X_CONTROL, OTG, inst),\
SRI(OTG_CRC0_WINDOWB_Y_CONTROL, OTG, inst),\
SR(GSL_SOURCE_SELECT)
SR(GSL_SOURCE_SELECT),\
SRI(OTG_GLOBAL_CONTROL2, OTG, inst),\
SRI(OTG_TRIGA_MANUAL_TRIG, OTG, inst)
#define TG_COMMON_REG_LIST_DCN1_0(inst) \
TG_COMMON_REG_LIST_DCN(inst),\
SRI(OTG_TEST_PATTERN_PARAMETERS, OTG, inst),\
SRI(OTG_TEST_PATTERN_CONTROL, OTG, inst),\
SRI(OTG_TEST_PATTERN_COLOR, OTG, inst)
SRI(OTG_TEST_PATTERN_COLOR, OTG, inst),\
SRI(OTG_MANUAL_FLOW_CONTROL, OTG, inst)
struct dcn_optc_registers {
......@@ -125,6 +129,8 @@ struct dcn_optc_registers {
uint32_t OTG_V_TOTAL_MIN;
uint32_t OTG_V_TOTAL_CONTROL;
uint32_t OTG_TRIGA_CNTL;
uint32_t OTG_TRIGA_MANUAL_TRIG;
uint32_t OTG_MANUAL_FLOW_CONTROL;
uint32_t OTG_FORCE_COUNT_NOW_CNTL;
uint32_t OTG_STATIC_SCREEN_CONTROL;
uint32_t OTG_STATUS_FRAME_COUNT;
......@@ -215,6 +221,11 @@ struct dcn_optc_registers {
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_SOURCE_PIPE_SELECT, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_RISING_EDGE_DETECT_CNTL, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FALLING_EDGE_DETECT_CNTL, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_POLARITY_SELECT, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_FREQUENCY_SELECT, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_DELAY, mask_sh),\
SF(OTG0_OTG_TRIGA_CNTL, OTG_TRIGA_CLEAR, mask_sh),\
SF(OTG0_OTG_TRIGA_MANUAL_TRIG, OTG_TRIGA_MANUAL_TRIG, mask_sh),\
SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_EVENT_MASK, mask_sh),\
SF(OTG0_OTG_STATIC_SCREEN_CONTROL, OTG_STATIC_SCREEN_FRAME_COUNT, mask_sh),\
SF(OTG0_OTG_STATUS_FRAME_COUNT, OTG_FRAME_COUNT, mask_sh),\
......@@ -271,8 +282,8 @@ struct dcn_optc_registers {
SF(OTG0_OTG_CRC0_WINDOWB_Y_CONTROL, OTG_CRC0_WINDOWB_Y_END, mask_sh),\
SF(GSL_SOURCE_SELECT, GSL0_READY_SOURCE_SEL, mask_sh),\
SF(GSL_SOURCE_SELECT, GSL1_READY_SOURCE_SEL, mask_sh),\
SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh)
SF(GSL_SOURCE_SELECT, GSL2_READY_SOURCE_SEL, mask_sh),\
SF(OTG0_OTG_GLOBAL_CONTROL2, MANUAL_FLOW_CONTROL_SEL, mask_sh)
#define TG_COMMON_MASK_SH_LIST_DCN1_0(mask_sh)\
TG_COMMON_MASK_SH_LIST_DCN(mask_sh),\
......@@ -287,7 +298,8 @@ struct dcn_optc_registers {
SF(OTG0_OTG_TEST_PATTERN_CONTROL, OTG_TEST_PATTERN_COLOR_FORMAT, mask_sh),\
SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_MASK, mask_sh),\
SF(OTG0_OTG_TEST_PATTERN_COLOR, OTG_TEST_PATTERN_DATA, mask_sh),\
SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh)
SF(ODM0_OPTC_DATA_SOURCE_SELECT, OPTC_SRC_SEL, mask_sh),\
SF(OTG0_OTG_MANUAL_FLOW_CONTROL, MANUAL_FLOW_CONTROL, mask_sh),\
#define TG_REG_FIELD_LIST_DCN1_0(type) \
type VSTARTUP_START;\
......@@ -343,6 +355,11 @@ struct dcn_optc_registers {
type OTG_TRIGA_SOURCE_PIPE_SELECT;\
type OTG_TRIGA_RISING_EDGE_DETECT_CNTL;\
type OTG_TRIGA_FALLING_EDGE_DETECT_CNTL;\
type OTG_TRIGA_POLARITY_SELECT;\
type OTG_TRIGA_FREQUENCY_SELECT;\
type OTG_TRIGA_DELAY;\
type OTG_TRIGA_CLEAR;\
type OTG_TRIGA_MANUAL_TRIG;\
type OTG_STATIC_SCREEN_EVENT_MASK;\
type OTG_STATIC_SCREEN_FRAME_COUNT;\
type OTG_FRAME_COUNT;\
......@@ -421,7 +438,9 @@ struct dcn_optc_registers {
type OTG_CRC0_WINDOWB_Y_END;\
type GSL0_READY_SOURCE_SEL;\
type GSL1_READY_SOURCE_SEL;\
type GSL2_READY_SOURCE_SEL;
type GSL2_READY_SOURCE_SEL;\
type MANUAL_FLOW_CONTROL;\
type MANUAL_FLOW_CONTROL_SEL;
#define TG_REG_FIELD_LIST(type) \
......
......@@ -238,6 +238,9 @@ struct timing_generator_funcs {
bool (*get_crc)(struct timing_generator *tg,
uint32_t *r_cr, uint32_t *g_y, uint32_t *b_cb);
void (*program_manual_trigger)(struct timing_generator *optc);
void (*setup_manual_trigger)(struct timing_generator *optc);
void (*set_vtg_params)(struct timing_generator *optc,
const struct dc_crtc_timing *dc_crtc_timing);
};
......
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