Commit 180db303 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher

drm/amd/display: Add below the range support for FreeSync

[Why]
When the flip-rate is below the minimum supported variable refresh rate
range for the monitor the front porch wait will timeout and be
frequently misaligned resulting in stuttering and/or flickering.

The FreeSync module can still maintain a smooth and flicker free
image when the monitor has a refresh rate range such that the maximum
refresh > 2 * minimum refresh by utilizing low framerate compensation,
"below the range".

[How]
Hook up the pre-flip and post-flip handlers from the FreeSync module.
These adjust the minimum/maximum vrr range to duplicate frames
when appropriate by tracking flip timestamps.
Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Acked-by: default avatarLeo Li <sunpeng.li@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 8cd61c31
...@@ -331,12 +331,29 @@ static void dm_crtc_high_irq(void *interrupt_params) ...@@ -331,12 +331,29 @@ static void dm_crtc_high_irq(void *interrupt_params)
struct common_irq_params *irq_params = interrupt_params; struct common_irq_params *irq_params = interrupt_params;
struct amdgpu_device *adev = irq_params->adev; struct amdgpu_device *adev = irq_params->adev;
struct amdgpu_crtc *acrtc; struct amdgpu_crtc *acrtc;
struct dm_crtc_state *acrtc_state;
acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK); acrtc = get_crtc_by_otg_inst(adev, irq_params->irq_src - IRQ_TYPE_VBLANK);
if (acrtc) { if (acrtc) {
drm_crtc_handle_vblank(&acrtc->base); drm_crtc_handle_vblank(&acrtc->base);
amdgpu_dm_crtc_handle_crc_irq(&acrtc->base); amdgpu_dm_crtc_handle_crc_irq(&acrtc->base);
acrtc_state = to_dm_crtc_state(acrtc->base.state);
if (acrtc_state->stream &&
acrtc_state->vrr_params.supported &&
acrtc_state->freesync_config.state == VRR_STATE_ACTIVE_VARIABLE) {
mod_freesync_handle_v_update(
adev->dm.freesync_module,
acrtc_state->stream,
&acrtc_state->vrr_params);
dc_stream_adjust_vmin_vmax(
adev->dm.dc,
acrtc_state->stream,
&acrtc_state->vrr_params.adjust);
}
} }
} }
...@@ -3009,7 +3026,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) ...@@ -3009,7 +3026,7 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc)
dc_stream_retain(state->stream); dc_stream_retain(state->stream);
} }
state->adjust = cur->adjust; state->vrr_params = cur->vrr_params;
state->vrr_infopacket = cur->vrr_infopacket; state->vrr_infopacket = cur->vrr_infopacket;
state->abm_level = cur->abm_level; state->abm_level = cur->abm_level;
state->vrr_supported = cur->vrr_supported; state->vrr_supported = cur->vrr_supported;
...@@ -4455,9 +4472,11 @@ struct dc_stream_status *dc_state_get_stream_status( ...@@ -4455,9 +4472,11 @@ struct dc_stream_status *dc_state_get_stream_status(
static void update_freesync_state_on_stream( static void update_freesync_state_on_stream(
struct amdgpu_display_manager *dm, struct amdgpu_display_manager *dm,
struct dm_crtc_state *new_crtc_state, struct dm_crtc_state *new_crtc_state,
struct dc_stream_state *new_stream) struct dc_stream_state *new_stream,
struct dc_plane_state *surface,
u32 flip_timestamp_in_us)
{ {
struct mod_vrr_params vrr = {0}; struct mod_vrr_params vrr_params = new_crtc_state->vrr_params;
struct dc_info_packet vrr_infopacket = {0}; struct dc_info_packet vrr_infopacket = {0};
struct mod_freesync_config config = new_crtc_state->freesync_config; struct mod_freesync_config config = new_crtc_state->freesync_config;
...@@ -4484,43 +4503,52 @@ static void update_freesync_state_on_stream( ...@@ -4484,43 +4503,52 @@ static void update_freesync_state_on_stream(
mod_freesync_build_vrr_params(dm->freesync_module, mod_freesync_build_vrr_params(dm->freesync_module,
new_stream, new_stream,
&config, &vrr); &config, &vrr_params);
if (surface) {
mod_freesync_handle_preflip(
dm->freesync_module,
surface,
new_stream,
flip_timestamp_in_us,
&vrr_params);
}
mod_freesync_build_vrr_infopacket( mod_freesync_build_vrr_infopacket(
dm->freesync_module, dm->freesync_module,
new_stream, new_stream,
&vrr, &vrr_params,
PACKET_TYPE_VRR, PACKET_TYPE_VRR,
TRANSFER_FUNC_UNKNOWN, TRANSFER_FUNC_UNKNOWN,
&vrr_infopacket); &vrr_infopacket);
new_crtc_state->freesync_timing_changed = new_crtc_state->freesync_timing_changed =
(memcmp(&new_crtc_state->adjust, (memcmp(&new_crtc_state->vrr_params.adjust,
&vrr.adjust, &vrr_params.adjust,
sizeof(vrr.adjust)) != 0); sizeof(vrr_params.adjust)) != 0);
new_crtc_state->freesync_vrr_info_changed = new_crtc_state->freesync_vrr_info_changed =
(memcmp(&new_crtc_state->vrr_infopacket, (memcmp(&new_crtc_state->vrr_infopacket,
&vrr_infopacket, &vrr_infopacket,
sizeof(vrr_infopacket)) != 0); sizeof(vrr_infopacket)) != 0);
new_crtc_state->adjust = vrr.adjust; new_crtc_state->vrr_params = vrr_params;
new_crtc_state->vrr_infopacket = vrr_infopacket; new_crtc_state->vrr_infopacket = vrr_infopacket;
new_stream->adjust = new_crtc_state->adjust; new_stream->adjust = new_crtc_state->vrr_params.adjust;
new_stream->vrr_infopacket = vrr_infopacket; new_stream->vrr_infopacket = vrr_infopacket;
if (new_crtc_state->freesync_vrr_info_changed) if (new_crtc_state->freesync_vrr_info_changed)
DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d", DRM_DEBUG_KMS("VRR packet update: crtc=%u enabled=%d state=%d",
new_crtc_state->base.crtc->base.id, new_crtc_state->base.crtc->base.id,
(int)new_crtc_state->base.vrr_enabled, (int)new_crtc_state->base.vrr_enabled,
(int)vrr.state); (int)vrr_params.state);
if (new_crtc_state->freesync_timing_changed) if (new_crtc_state->freesync_timing_changed)
DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n", DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n",
new_crtc_state->base.crtc->base.id, new_crtc_state->base.crtc->base.id,
vrr.adjust.v_total_min, vrr_params.adjust.v_total_min,
vrr.adjust.v_total_max); vrr_params.adjust.v_total_max);
} }
/* /*
...@@ -4547,6 +4575,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, ...@@ -4547,6 +4575,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
struct dc_stream_update stream_update = {0}; struct dc_stream_update stream_update = {0};
struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state);
struct dc_stream_status *stream_status; struct dc_stream_status *stream_status;
struct dc_plane_state *surface;
/* Prepare wait for target vblank early - before the fence-waits */ /* Prepare wait for target vblank early - before the fence-waits */
...@@ -4595,6 +4624,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, ...@@ -4595,6 +4624,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
addr.address.grph.addr.low_part = lower_32_bits(afb->address); addr.address.grph.addr.low_part = lower_32_bits(afb->address);
addr.address.grph.addr.high_part = upper_32_bits(afb->address); addr.address.grph.addr.high_part = upper_32_bits(afb->address);
addr.flip_immediate = async_flip; addr.flip_immediate = async_flip;
addr.flip_timestamp_in_us = ktime_get_ns() / 1000;
if (acrtc->base.state->event) if (acrtc->base.state->event)
...@@ -4609,8 +4639,10 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, ...@@ -4609,8 +4639,10 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
return; return;
} }
surface_updates->surface = stream_status->plane_states[0]; surface = stream_status->plane_states[0];
if (!surface_updates->surface) { surface_updates->surface = surface;
if (!surface) {
DRM_ERROR("No surface for CRTC: id=%d\n", DRM_ERROR("No surface for CRTC: id=%d\n",
acrtc->crtc_id); acrtc->crtc_id);
return; return;
...@@ -4621,7 +4653,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, ...@@ -4621,7 +4653,9 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
update_freesync_state_on_stream( update_freesync_state_on_stream(
&adev->dm, &adev->dm,
acrtc_state, acrtc_state,
acrtc_state->stream); acrtc_state->stream,
surface,
addr.flip_timestamp_in_us);
if (acrtc_state->freesync_timing_changed) if (acrtc_state->freesync_timing_changed)
stream_update.adjust = stream_update.adjust =
...@@ -4632,7 +4666,16 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, ...@@ -4632,7 +4666,16 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc,
&acrtc_state->stream->vrr_infopacket; &acrtc_state->stream->vrr_infopacket;
} }
/* Update surface timing information. */
surface->time.time_elapsed_in_us[surface->time.index] =
addr.flip_timestamp_in_us - surface->time.prev_update_time_in_us;
surface->time.prev_update_time_in_us = addr.flip_timestamp_in_us;
surface->time.index++;
if (surface->time.index >= DC_PLANE_UPDATE_TIMES_MAX)
surface->time.index = 0;
mutex_lock(&adev->dm.dc_lock); mutex_lock(&adev->dm.dc_lock);
dc_commit_updates_for_stream(adev->dm.dc, dc_commit_updates_for_stream(adev->dm.dc,
surface_updates, surface_updates,
1, 1,
...@@ -5324,6 +5367,7 @@ static void get_freesync_config_for_crtc( ...@@ -5324,6 +5367,7 @@ static void get_freesync_config_for_crtc(
config.max_refresh_in_uhz = config.max_refresh_in_uhz =
aconnector->max_vfreq * 1000000; aconnector->max_vfreq * 1000000;
config.vsif_supported = true; config.vsif_supported = true;
config.btr = true;
} }
new_crtc_state->freesync_config = config; new_crtc_state->freesync_config = config;
...@@ -5334,8 +5378,8 @@ static void reset_freesync_config_for_crtc( ...@@ -5334,8 +5378,8 @@ static void reset_freesync_config_for_crtc(
{ {
new_crtc_state->vrr_supported = false; new_crtc_state->vrr_supported = false;
memset(&new_crtc_state->adjust, 0, memset(&new_crtc_state->vrr_params, 0,
sizeof(new_crtc_state->adjust)); sizeof(new_crtc_state->vrr_params));
memset(&new_crtc_state->vrr_infopacket, 0, memset(&new_crtc_state->vrr_infopacket, 0,
sizeof(new_crtc_state->vrr_infopacket)); sizeof(new_crtc_state->vrr_infopacket));
} }
......
...@@ -268,7 +268,7 @@ struct dm_crtc_state { ...@@ -268,7 +268,7 @@ struct dm_crtc_state {
bool vrr_supported; bool vrr_supported;
struct mod_freesync_config freesync_config; struct mod_freesync_config freesync_config;
struct dc_crtc_timing_adjust adjust; struct mod_vrr_params vrr_params;
struct dc_info_packet vrr_infopacket; struct dc_info_packet vrr_infopacket;
int abm_level; int abm_level;
......
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