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: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Acked-by: Leo Li <sunpeng.li@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
committed by
Alex Deucher
parent
8cd61c313d
commit
180db303ff
@@ -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)
|
|||||||
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(
|
|||||||
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(
|
|||||||
|
|
||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
&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(
|
|||||||
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(
|
|||||||
{
|
{
|
||||||
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 {
|
|||||||
|
|
||||||
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;
|
||||||
|
|||||||
Reference in New Issue
Block a user