drm/amd/display: make PSR static screen entry within 30 ms

[Why]
With different refresh rate panels, the PSR entry/exit time is
different since it is dependent on 2 frame entry time today

[How]
Make static screen num frame entry time to be calculated
such that entry time is within 30 ms instead of fixed num
frames.

Signed-off-by: Anthony Koo <Anthony.Koo@amd.com>
Reviewed-by: Tony Cheng <Tony.Cheng@amd.com>
Acked-by: Aric Cyr <Aric.Cyr@amd.com>
Acked-by: Harry Wentland <harry.wentland@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Anthony Koo 2019-12-09 17:26:34 -05:00 committed by Alex Deucher
parent 9a25e13b91
commit 5b5abe9526
18 changed files with 116 additions and 61 deletions

View File

@ -8393,17 +8393,37 @@ static bool amdgpu_dm_link_setup_psr(struct dc_stream_state *stream)
bool amdgpu_dm_psr_enable(struct dc_stream_state *stream)
{
struct dc_link *link = stream->link;
struct dc_static_screen_events triggers = {0};
unsigned int vsync_rate_hz = 0;
struct dc_static_screen_params params = {0};
/* Calculate number of static frames before generating interrupt to
* enter PSR.
*/
unsigned int frame_time_microsec = 1000000 / vsync_rate_hz;
// Init fail safe of 2 frames static
unsigned int num_frames_static = 2;
DRM_DEBUG_DRIVER("Enabling psr...\n");
triggers.cursor_update = true;
triggers.overlay_update = true;
triggers.surface_update = true;
vsync_rate_hz = div64_u64(div64_u64((
stream->timing.pix_clk_100hz * 100),
stream->timing.v_total),
stream->timing.h_total);
dc_stream_set_static_screen_events(link->ctx->dc,
/* Round up
* Calculate number of frames such that at least 30 ms of time has
* passed.
*/
if (vsync_rate_hz != 0)
num_frames_static = (30000 / frame_time_microsec) + 1;
params.triggers.cursor_update = true;
params.triggers.overlay_update = true;
params.triggers.surface_update = true;
params.num_frames = num_frames_static;
dc_stream_set_static_screen_params(link->ctx->dc,
&stream, 1,
&triggers);
&params);
return dc_link_set_psr_allow_active(link, true, false);
}

View File

@ -510,10 +510,10 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
return ret;
}
void dc_stream_set_static_screen_events(struct dc *dc,
void dc_stream_set_static_screen_params(struct dc *dc,
struct dc_stream_state **streams,
int num_streams,
const struct dc_static_screen_events *events)
const struct dc_static_screen_params *params)
{
int i = 0;
int j = 0;
@ -532,7 +532,7 @@ void dc_stream_set_static_screen_events(struct dc *dc,
}
}
dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, events);
dc->hwss.set_static_screen_control(pipes_affected, num_pipes_affected, params);
}
static void dc_destruct(struct dc *dc)

View File

@ -2542,7 +2542,7 @@ bool dc_link_setup_psr(struct dc_link *link,
transmitter_to_phy_id(link->link_enc->transmitter);
psr_context->crtcTimingVerticalTotal = stream->timing.v_total;
psr_context->vsyncRateHz = div64_u64(div64_u64((stream->
psr_context->vsync_rate_hz = div64_u64(div64_u64((stream->
timing.pix_clk_100hz * 100),
stream->timing.v_total),
stream->timing.h_total);

View File

@ -157,11 +157,14 @@ struct dc_surface_dcc_cap {
bool const_color_support;
};
struct dc_static_screen_events {
bool force_trigger;
bool cursor_update;
bool surface_update;
bool overlay_update;
struct dc_static_screen_params {
struct {
bool force_trigger;
bool cursor_update;
bool surface_update;
bool overlay_update;
} triggers;
unsigned int num_frames;
};

View File

@ -439,10 +439,10 @@ bool dc_stream_get_crc(struct dc *dc,
uint32_t *g_y,
uint32_t *b_cb);
void dc_stream_set_static_screen_events(struct dc *dc,
void dc_stream_set_static_screen_params(struct dc *dc,
struct dc_stream_state **stream,
int num_streams,
const struct dc_static_screen_events *events);
const struct dc_static_screen_params *params);
void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream,
enum dc_dynamic_expansion option);

View File

@ -729,7 +729,7 @@ struct psr_context {
/* The VSync rate in Hz used to calculate the
* step size for smooth brightness feature
*/
unsigned int vsyncRateHz;
unsigned int vsync_rate_hz;
unsigned int skipPsrWaitForPllLock;
unsigned int numberOfControllers;
/* Unused, for future use. To indicate that first changed frame from

View File

@ -1373,9 +1373,13 @@ static enum dc_status apply_single_controller_ctx_to_hw(
// DRR should set trigger event to monitor surface update event
if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80;
/* Event triggers and num frames initialized for DRR, but can be
* later updated for PSR use. Note DRR trigger events are generated
* regardless of whether num frames met.
*/
if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx->stream_res.tg, event_triggers);
pipe_ctx->stream_res.tg, event_triggers, 2);
if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
@ -1706,6 +1710,8 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
struct drr_params params = {0};
// DRR should set trigger event to monitor surface update event
unsigned int event_triggers = 0x80;
// Note DRR trigger events are generated regardless of whether num frames met.
unsigned int num_frames = 2;
params.vertical_total_max = vmax;
params.vertical_total_min = vmin;
@ -1721,7 +1727,7 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
if (vmax != 0 && vmin != 0)
pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx[i]->stream_res.tg,
event_triggers);
event_triggers, num_frames);
}
}
@ -1738,30 +1744,31 @@ static void get_position(struct pipe_ctx **pipe_ctx,
}
static void set_static_screen_control(struct pipe_ctx **pipe_ctx,
int num_pipes, const struct dc_static_screen_events *events)
int num_pipes, const struct dc_static_screen_params *params)
{
unsigned int i;
unsigned int value = 0;
unsigned int triggers = 0;
if (events->overlay_update)
value |= 0x100;
if (events->surface_update)
value |= 0x80;
if (events->cursor_update)
value |= 0x2;
if (events->force_trigger)
value |= 0x1;
if (params->triggers.overlay_update)
triggers |= 0x100;
if (params->triggers.surface_update)
triggers |= 0x80;
if (params->triggers.cursor_update)
triggers |= 0x2;
if (params->triggers.force_trigger)
triggers |= 0x1;
if (num_pipes) {
struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
if (dc->fbc_compressor)
value |= 0x84;
triggers |= 0x84;
}
for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs->
set_static_screen_control(pipe_ctx[i]->stream_res.tg, value);
set_static_screen_control(pipe_ctx[i]->stream_res.tg,
triggers, params->num_frames);
}
/*

View File

@ -469,22 +469,27 @@ void dce110_timing_generator_set_drr(
void dce110_timing_generator_set_static_screen_control(
struct timing_generator *tg,
uint32_t value)
uint32_t event_triggers,
uint32_t num_frames)
{
struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
uint32_t static_screen_cntl = 0;
uint32_t addr = 0;
// By register spec, it only takes 8 bit value
if (num_frames > 0xFF)
num_frames = 0xFF;
addr = CRTC_REG(mmCRTC_STATIC_SCREEN_CONTROL);
static_screen_cntl = dm_read_reg(tg->ctx, addr);
set_reg_field_value(static_screen_cntl,
value,
event_triggers,
CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_EVENT_MASK);
set_reg_field_value(static_screen_cntl,
2,
num_frames,
CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_FRAME_COUNT);

View File

@ -231,7 +231,8 @@ void dce110_timing_generator_set_drr(
void dce110_timing_generator_set_static_screen_control(
struct timing_generator *tg,
uint32_t value);
uint32_t event_triggers,
uint32_t num_frames);
void dce110_timing_generator_get_crtc_scanoutpos(
struct timing_generator *tg,

View File

@ -819,13 +819,18 @@ void dce120_tg_set_colors(struct timing_generator *tg,
static void dce120_timing_generator_set_static_screen_control(
struct timing_generator *tg,
uint32_t value)
uint32_t event_triggers,
uint32_t num_frames)
{
struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
// By register spec, it only takes 8 bit value
if (num_frames > 0xFF)
num_frames = 0xFF;
CRTC_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_EVENT_MASK, value,
CRTC_STATIC_SCREEN_FRAME_COUNT, 2);
CRTC_STATIC_SCREEN_EVENT_MASK, event_triggers,
CRTC_STATIC_SCREEN_FRAME_COUNT, num_frames);
}
void dce120_timing_generator_set_test_pattern(

View File

@ -2704,6 +2704,8 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
struct drr_params params = {0};
// DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
unsigned int event_triggers = 0x800;
// Note DRR trigger events are generated regardless of whether num frames met.
unsigned int num_frames = 2;
params.vertical_total_max = vmax;
params.vertical_total_min = vmin;
@ -2720,7 +2722,7 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
if (vmax != 0 && vmin != 0)
pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx[i]->stream_res.tg,
event_triggers);
event_triggers, num_frames);
}
}
@ -2737,21 +2739,22 @@ void dcn10_get_position(struct pipe_ctx **pipe_ctx,
}
void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx,
int num_pipes, const struct dc_static_screen_events *events)
int num_pipes, const struct dc_static_screen_params *params)
{
unsigned int i;
unsigned int value = 0;
unsigned int triggers = 0;
if (events->surface_update)
value |= 0x80;
if (events->cursor_update)
value |= 0x2;
if (events->force_trigger)
value |= 0x1;
if (params->triggers.surface_update)
triggers |= 0x80;
if (params->triggers.cursor_update)
triggers |= 0x2;
if (params->triggers.force_trigger)
triggers |= 0x1;
for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs->
set_static_screen_control(pipe_ctx[i]->stream_res.tg, value);
set_static_screen_control(pipe_ctx[i]->stream_res.tg,
triggers, params->num_frames);
}
static void dcn10_config_stereo_parameters(

View File

@ -132,7 +132,7 @@ void dcn10_get_position(struct pipe_ctx **pipe_ctx,
int num_pipes,
struct crtc_position *position);
void dcn10_set_static_screen_control(struct pipe_ctx **pipe_ctx,
int num_pipes, const struct dc_static_screen_events *events);
int num_pipes, const struct dc_static_screen_params *params);
void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc);
void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
void dcn10_log_hw_state(struct dc *dc,

View File

@ -789,21 +789,26 @@ void optc1_set_early_control(
void optc1_set_static_screen_control(
struct timing_generator *optc,
uint32_t value)
uint32_t event_triggers,
uint32_t num_frames)
{
struct optc *optc1 = DCN10TG_FROM_TG(optc);
// By register spec, it only takes 8 bit value
if (num_frames > 0xFF)
num_frames = 0xFF;
/* Bit 8 is no longer applicable in RV for PSR case,
* set bit 8 to 0 if given
*/
if ((value & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
if ((event_triggers & STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN)
!= 0)
value = value &
event_triggers = event_triggers &
~STATIC_SCREEN_EVENT_MASK_RANGETIMING_DOUBLE_BUFFER_UPDATE_EN;
REG_SET_2(OTG_STATIC_SCREEN_CONTROL, 0,
OTG_STATIC_SCREEN_EVENT_MASK, value,
OTG_STATIC_SCREEN_FRAME_COUNT, 2);
OTG_STATIC_SCREEN_EVENT_MASK, event_triggers,
OTG_STATIC_SCREEN_FRAME_COUNT, num_frames);
}
void optc1_setup_manual_trigger(struct timing_generator *optc)

View File

@ -625,7 +625,8 @@ void optc1_set_drr(
void optc1_set_static_screen_control(
struct timing_generator *optc,
uint32_t value);
uint32_t event_triggers,
uint32_t num_frames);
void optc1_program_stereo(struct timing_generator *optc,
const struct dc_crtc_timing *timing, struct crtc_stereo_flags *flags);

View File

@ -686,9 +686,13 @@ enum dc_status dcn20_enable_stream_timing(
// DRR should set trigger event to monitor surface update event
if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80;
/* Event triggers and num frames initialized for DRR, but can be
* later updated for PSR use. Note DRR trigger events are generated
* regardless of whether num frames met.
*/
if (pipe_ctx->stream_res.tg->funcs->set_static_screen_control)
pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx->stream_res.tg, event_triggers);
pipe_ctx->stream_res.tg, event_triggers, 2);
/* TODO program crtc source select for non-virtual signal*/
/* TODO program FMT */

View File

@ -208,7 +208,8 @@ struct timing_generator_funcs {
bool enable, const struct dc_crtc_timing *timing);
void (*set_drr)(struct timing_generator *tg, const struct drr_params *params);
void (*set_static_screen_control)(struct timing_generator *tg,
uint32_t value);
uint32_t event_triggers,
uint32_t num_frames);
void (*set_test_pattern)(
struct timing_generator *tg,
enum controller_dp_test_pattern test_pattern,

View File

@ -42,7 +42,7 @@ struct dc_state;
struct dc_stream_status;
struct dc_writeback_info;
struct dchub_init_data;
struct dc_static_screen_events;
struct dc_static_screen_params;
struct resource_pool;
struct dc_phy_addr_space_config;
struct dc_virtual_addr_space_config;
@ -102,7 +102,7 @@ struct hw_sequencer_funcs {
unsigned int vmid, unsigned int vmid_frame_number);
void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx,
int num_pipes,
const struct dc_static_screen_events *events);
const struct dc_static_screen_params *events);
/* Stream Related */
void (*enable_stream)(struct pipe_ctx *pipe_ctx);

View File

@ -51,7 +51,7 @@ struct dc_state;
struct dc_stream_status;
struct dc_writeback_info;
struct dchub_init_data;
struct dc_static_screen_events;
struct dc_static_screen_params;
struct resource_pool;
struct resource_context;
struct stream_resource;