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 коммит произвёл Alex Deucher
Родитель 9a25e13b91
Коммит 5b5abe9526
18 изменённых файлов: 116 добавлений и 61 удалений

Просмотреть файл

@ -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) bool amdgpu_dm_psr_enable(struct dc_stream_state *stream)
{ {
struct dc_link *link = stream->link; 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"); DRM_DEBUG_DRIVER("Enabling psr...\n");
triggers.cursor_update = true; vsync_rate_hz = div64_u64(div64_u64((
triggers.overlay_update = true; stream->timing.pix_clk_100hz * 100),
triggers.surface_update = true; 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, &stream, 1,
&triggers); &params);
return dc_link_set_psr_allow_active(link, true, false); return dc_link_set_psr_allow_active(link, true, false);
} }

Просмотреть файл

@ -510,10 +510,10 @@ bool dc_stream_program_csc_matrix(struct dc *dc, struct dc_stream_state *stream)
return ret; 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, struct dc_stream_state **streams,
int num_streams, int num_streams,
const struct dc_static_screen_events *events) const struct dc_static_screen_params *params)
{ {
int i = 0; int i = 0;
int j = 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) static void dc_destruct(struct dc *dc)

Просмотреть файл

@ -2542,7 +2542,7 @@ bool dc_link_setup_psr(struct dc_link *link,
transmitter_to_phy_id(link->link_enc->transmitter); transmitter_to_phy_id(link->link_enc->transmitter);
psr_context->crtcTimingVerticalTotal = stream->timing.v_total; 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), timing.pix_clk_100hz * 100),
stream->timing.v_total), stream->timing.v_total),
stream->timing.h_total); stream->timing.h_total);

Просмотреть файл

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

Просмотреть файл

@ -439,10 +439,10 @@ bool dc_stream_get_crc(struct dc *dc,
uint32_t *g_y, uint32_t *g_y,
uint32_t *b_cb); 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, struct dc_stream_state **stream,
int num_streams, 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, void dc_stream_set_dyn_expansion(struct dc *dc, struct dc_stream_state *stream,
enum dc_dynamic_expansion option); enum dc_dynamic_expansion option);

Просмотреть файл

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

Просмотреть файл

@ -1373,9 +1373,13 @@ static enum dc_status apply_single_controller_ctx_to_hw(
// DRR should set trigger event to monitor surface update event // DRR should set trigger event to monitor surface update event
if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80; 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) 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->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)) if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg( 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}; struct drr_params params = {0};
// DRR should set trigger event to monitor surface update event // DRR should set trigger event to monitor surface update event
unsigned int event_triggers = 0x80; 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_max = vmax;
params.vertical_total_min = vmin; params.vertical_total_min = vmin;
@ -1721,7 +1727,7 @@ static void set_drr(struct pipe_ctx **pipe_ctx,
if (vmax != 0 && vmin != 0) if (vmax != 0 && vmin != 0)
pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx[i]->stream_res.tg, 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, 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 i;
unsigned int value = 0; unsigned int triggers = 0;
if (events->overlay_update) if (params->triggers.overlay_update)
value |= 0x100; triggers |= 0x100;
if (events->surface_update) if (params->triggers.surface_update)
value |= 0x80; triggers |= 0x80;
if (events->cursor_update) if (params->triggers.cursor_update)
value |= 0x2; triggers |= 0x2;
if (events->force_trigger) if (params->triggers.force_trigger)
value |= 0x1; triggers |= 0x1;
if (num_pipes) { if (num_pipes) {
struct dc *dc = pipe_ctx[0]->stream->ctx->dc; struct dc *dc = pipe_ctx[0]->stream->ctx->dc;
if (dc->fbc_compressor) if (dc->fbc_compressor)
value |= 0x84; triggers |= 0x84;
} }
for (i = 0; i < num_pipes; i++) for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs-> 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);
} }
/* /*

Просмотреть файл

@ -469,22 +469,27 @@ void dce110_timing_generator_set_drr(
void dce110_timing_generator_set_static_screen_control( void dce110_timing_generator_set_static_screen_control(
struct timing_generator *tg, struct timing_generator *tg,
uint32_t value) uint32_t event_triggers,
uint32_t num_frames)
{ {
struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg);
uint32_t static_screen_cntl = 0; uint32_t static_screen_cntl = 0;
uint32_t addr = 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); addr = CRTC_REG(mmCRTC_STATIC_SCREEN_CONTROL);
static_screen_cntl = dm_read_reg(tg->ctx, addr); static_screen_cntl = dm_read_reg(tg->ctx, addr);
set_reg_field_value(static_screen_cntl, set_reg_field_value(static_screen_cntl,
value, event_triggers,
CRTC_STATIC_SCREEN_CONTROL, CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_EVENT_MASK); CRTC_STATIC_SCREEN_EVENT_MASK);
set_reg_field_value(static_screen_cntl, set_reg_field_value(static_screen_cntl,
2, num_frames,
CRTC_STATIC_SCREEN_CONTROL, CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_FRAME_COUNT); CRTC_STATIC_SCREEN_FRAME_COUNT);

Просмотреть файл

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

Просмотреть файл

@ -819,13 +819,18 @@ void dce120_tg_set_colors(struct timing_generator *tg,
static void dce120_timing_generator_set_static_screen_control( static void dce120_timing_generator_set_static_screen_control(
struct timing_generator *tg, struct timing_generator *tg,
uint32_t value) uint32_t event_triggers,
uint32_t num_frames)
{ {
struct dce110_timing_generator *tg110 = DCE110TG_FROM_TG(tg); 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_REG_UPDATE_2(CRTC0_CRTC_STATIC_SCREEN_CONTROL,
CRTC_STATIC_SCREEN_EVENT_MASK, value, CRTC_STATIC_SCREEN_EVENT_MASK, event_triggers,
CRTC_STATIC_SCREEN_FRAME_COUNT, 2); CRTC_STATIC_SCREEN_FRAME_COUNT, num_frames);
} }
void dce120_timing_generator_set_test_pattern( void dce120_timing_generator_set_test_pattern(

Просмотреть файл

@ -2704,6 +2704,8 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
struct drr_params params = {0}; struct drr_params params = {0};
// DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow // DRR set trigger event mapped to OTG_TRIG_A (bit 11) for manual control flow
unsigned int event_triggers = 0x800; 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_max = vmax;
params.vertical_total_min = vmin; params.vertical_total_min = vmin;
@ -2720,7 +2722,7 @@ void dcn10_set_drr(struct pipe_ctx **pipe_ctx,
if (vmax != 0 && vmin != 0) if (vmax != 0 && vmin != 0)
pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control( pipe_ctx[i]->stream_res.tg->funcs->set_static_screen_control(
pipe_ctx[i]->stream_res.tg, 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, 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 i;
unsigned int value = 0; unsigned int triggers = 0;
if (events->surface_update) if (params->triggers.surface_update)
value |= 0x80; triggers |= 0x80;
if (events->cursor_update) if (params->triggers.cursor_update)
value |= 0x2; triggers |= 0x2;
if (events->force_trigger) if (params->triggers.force_trigger)
value |= 0x1; triggers |= 0x1;
for (i = 0; i < num_pipes; i++) for (i = 0; i < num_pipes; i++)
pipe_ctx[i]->stream_res.tg->funcs-> 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( static void dcn10_config_stereo_parameters(

Просмотреть файл

@ -132,7 +132,7 @@ void dcn10_get_position(struct pipe_ctx **pipe_ctx,
int num_pipes, int num_pipes,
struct crtc_position *position); struct crtc_position *position);
void dcn10_set_static_screen_control(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);
void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc); void dcn10_setup_stereo(struct pipe_ctx *pipe_ctx, struct dc *dc);
void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable); void dce110_set_avmute(struct pipe_ctx *pipe_ctx, bool enable);
void dcn10_log_hw_state(struct dc *dc, void dcn10_log_hw_state(struct dc *dc,

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -686,9 +686,13 @@ enum dc_status dcn20_enable_stream_timing(
// DRR should set trigger event to monitor surface update event // DRR should set trigger event to monitor surface update event
if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0) if (stream->adjust.v_total_min != 0 && stream->adjust.v_total_max != 0)
event_triggers = 0x80; 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) 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->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 crtc source select for non-virtual signal*/
/* TODO program FMT */ /* TODO program FMT */

Просмотреть файл

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

Просмотреть файл

@ -42,7 +42,7 @@ struct dc_state;
struct dc_stream_status; struct dc_stream_status;
struct dc_writeback_info; struct dc_writeback_info;
struct dchub_init_data; struct dchub_init_data;
struct dc_static_screen_events; struct dc_static_screen_params;
struct resource_pool; struct resource_pool;
struct dc_phy_addr_space_config; struct dc_phy_addr_space_config;
struct dc_virtual_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); unsigned int vmid, unsigned int vmid_frame_number);
void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx, void (*set_static_screen_control)(struct pipe_ctx **pipe_ctx,
int num_pipes, int num_pipes,
const struct dc_static_screen_events *events); const struct dc_static_screen_params *events);
/* Stream Related */ /* Stream Related */
void (*enable_stream)(struct pipe_ctx *pipe_ctx); void (*enable_stream)(struct pipe_ctx *pipe_ctx);

Просмотреть файл

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