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:
parent
9a25e13b91
commit
5b5abe9526
|
@ -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);
|
||||
¶ms);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -157,11 +157,14 @@ struct dc_surface_dcc_cap {
|
|||
bool const_color_support;
|
||||
};
|
||||
|
||||
struct dc_static_screen_events {
|
||||
struct dc_static_screen_params {
|
||||
struct {
|
||||
bool force_trigger;
|
||||
bool cursor_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 *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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue