mirror of
https://github.com/torvalds/linux.git
synced 2026-09-23 05:04:02 +02:00
drm/amd/display: add FreeSync/VRR module
[WHAT] Group the FreeSync/VRR helpers from amdgpu_dm.c into a dedicated amdgpu_dm_freesync.c and amdgpu_dm_freesync.h. The moved functions are: is_dc_timing_adjust_needed, is_timing_unchanged_for_freesync, set_freesync_fixed_config, reset_freesync_config_for_crtc, get_freesync_config_for_crtc, update_freesync_state_on_stream, update_stream_irq_parameters, amdgpu_dm_handle_vrr_transition. The FreeSync/VRR helpers exposed by amdgpu_dm_freesync.h are called from amdgpu_dm.c, so give the seven that lacked a namespace prefix the standard amdgpu_dm_ prefix: Relocate the corresponding KUnit tests into amdgpu_dm_freesync_test.c. No functional change. Reviewed-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
66517ca0cd
commit
09dd9fbc0b
|
|
@ -45,7 +45,8 @@ AMDGPUDM = \
|
|||
amdgpu_dm_backlight.o \
|
||||
amdgpu_dm_audio.o \
|
||||
amdgpu_dm_dmub.o \
|
||||
amdgpu_dm_connector.o
|
||||
amdgpu_dm_connector.o \
|
||||
amdgpu_dm_freesync.o
|
||||
|
||||
ifdef CONFIG_DRM_AMD_DC_FP
|
||||
AMDGPUDM += dc_fpu.o
|
||||
|
|
|
|||
|
|
@ -71,6 +71,7 @@
|
|||
#include "amdgpu_dm_dmub.h"
|
||||
#include "amdgpu_dm_connector.h"
|
||||
#include "amdgpu_dm_pp_smu.h"
|
||||
#include "amdgpu_dm_freesync.h"
|
||||
|
||||
#include "ivsrcid/ivsrcid_vislands30.h"
|
||||
|
||||
|
|
@ -127,7 +128,6 @@ MODULE_FIRMWARE(FIRMWARE_NAVI12_DMCU);
|
|||
/* basic init/fini API */
|
||||
static int amdgpu_dm_init(struct amdgpu_device *adev);
|
||||
static void amdgpu_dm_fini(struct amdgpu_device *adev);
|
||||
STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
|
||||
|
||||
/*
|
||||
* initializes drm_device display related structures, based on the information
|
||||
|
|
@ -147,10 +147,6 @@ STATIC_IFN_KUNIT void dm_enable_per_frame_crtc_master_sync(struct dc_state *cont
|
|||
static int amdgpu_dm_atomic_check(struct drm_device *dev,
|
||||
struct drm_atomic_commit *state);
|
||||
|
||||
STATIC_IFN_KUNIT bool
|
||||
is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state);
|
||||
|
||||
static inline void amdgpu_dm_exit_ips_for_hw_access(struct dc *dc)
|
||||
{
|
||||
if (dc->ctx->dmub_srv && !dc->ctx->dmub_srv->idle_exit_counter)
|
||||
|
|
@ -248,20 +244,6 @@ STATIC_IFN_KUNIT int dm_soft_reset(struct amdgpu_ip_block *ip_block)
|
|||
}
|
||||
EXPORT_IF_KUNIT(dm_soft_reset);
|
||||
|
||||
STATIC_IFN_KUNIT bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state)
|
||||
{
|
||||
if (new_state->stream->adjust.timing_adjust_pending)
|
||||
return true;
|
||||
if (new_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)
|
||||
return true;
|
||||
else if (amdgpu_dm_crtc_vrr_active(old_state) != amdgpu_dm_crtc_vrr_active(new_state))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
EXPORT_IF_KUNIT(is_dc_timing_adjust_needed);
|
||||
|
||||
/*
|
||||
* DC will program planes with their z-order determined by their ordering
|
||||
* in the dc_surface_updates array. This comparator is used to sort them
|
||||
|
|
@ -1542,7 +1524,7 @@ static void dm_destroy_cached_state(struct amdgpu_device *adev)
|
|||
for_each_new_crtc_in_state(dm->cached_state, crtc, new_crtc_state, i) {
|
||||
new_crtc_state->active_changed = true;
|
||||
dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
|
||||
reset_freesync_config_for_crtc(dm_new_crtc_state);
|
||||
amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -3614,213 +3596,6 @@ static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
|
|||
acrtc->crtc_id);
|
||||
}
|
||||
|
||||
static void update_freesync_state_on_stream(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state,
|
||||
struct dc_stream_state *new_stream,
|
||||
struct dc_plane_state *surface,
|
||||
u32 flip_timestamp_in_us)
|
||||
{
|
||||
struct mod_vrr_params vrr_params;
|
||||
struct dc_info_packet vrr_infopacket = {0};
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
|
||||
unsigned long flags;
|
||||
bool pack_sdp_v1_3 = false;
|
||||
struct amdgpu_dm_connector *aconn;
|
||||
enum vrr_packet_type packet_type = PACKET_TYPE_VRR;
|
||||
|
||||
if (!new_stream)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Determine why min/max totals and vrefresh can be 0 here.
|
||||
* For now it's sufficient to just guard against these conditions.
|
||||
*/
|
||||
|
||||
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
vrr_params = acrtc->dm_irq_params.vrr_params;
|
||||
|
||||
if (surface) {
|
||||
mod_freesync_handle_preflip(
|
||||
dm->freesync_module,
|
||||
surface,
|
||||
new_stream,
|
||||
flip_timestamp_in_us,
|
||||
&vrr_params);
|
||||
|
||||
if (adev->family < AMDGPU_FAMILY_AI &&
|
||||
amdgpu_dm_crtc_vrr_active(new_crtc_state)) {
|
||||
mod_freesync_handle_v_update(dm->freesync_module,
|
||||
new_stream, &vrr_params);
|
||||
|
||||
/* Need to call this before the frame ends. */
|
||||
dc_stream_adjust_vmin_vmax(dm->dc,
|
||||
new_crtc_state->stream,
|
||||
&vrr_params.adjust);
|
||||
}
|
||||
}
|
||||
|
||||
aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
|
||||
|
||||
if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) {
|
||||
pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
|
||||
|
||||
if (aconn->vsdb_info.amd_vsdb_version == 1)
|
||||
packet_type = PACKET_TYPE_FS_V1;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 2)
|
||||
packet_type = PACKET_TYPE_FS_V2;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 3)
|
||||
packet_type = PACKET_TYPE_FS_V3;
|
||||
|
||||
mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL,
|
||||
&new_stream->adaptive_sync_infopacket);
|
||||
}
|
||||
|
||||
mod_freesync_build_vrr_infopacket(
|
||||
dm->freesync_module,
|
||||
new_stream,
|
||||
&vrr_params,
|
||||
packet_type,
|
||||
TRANSFER_FUNC_UNKNOWN,
|
||||
&vrr_infopacket,
|
||||
pack_sdp_v1_3);
|
||||
|
||||
new_crtc_state->freesync_vrr_info_changed |=
|
||||
(memcmp(&new_crtc_state->vrr_infopacket,
|
||||
&vrr_infopacket,
|
||||
sizeof(vrr_infopacket)) != 0);
|
||||
|
||||
acrtc->dm_irq_params.vrr_params = vrr_params;
|
||||
new_crtc_state->vrr_infopacket = vrr_infopacket;
|
||||
|
||||
new_stream->vrr_infopacket = vrr_infopacket;
|
||||
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
|
||||
|
||||
if (new_crtc_state->freesync_vrr_info_changed)
|
||||
drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
|
||||
new_crtc_state->base.crtc->base.id,
|
||||
(int)new_crtc_state->base.vrr_enabled,
|
||||
(int)vrr_params.state);
|
||||
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
|
||||
static void update_stream_irq_parameters(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state)
|
||||
{
|
||||
struct dc_stream_state *new_stream = new_crtc_state->stream;
|
||||
struct mod_vrr_params vrr_params;
|
||||
struct mod_freesync_config config = new_crtc_state->freesync_config;
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
|
||||
unsigned long flags;
|
||||
|
||||
if (!new_stream)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Determine why min/max totals and vrefresh can be 0 here.
|
||||
* For now it's sufficient to just guard against these conditions.
|
||||
*/
|
||||
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
vrr_params = acrtc->dm_irq_params.vrr_params;
|
||||
|
||||
if (new_crtc_state->vrr_supported &&
|
||||
config.min_refresh_in_uhz &&
|
||||
config.max_refresh_in_uhz) {
|
||||
/*
|
||||
* if freesync compatible mode was set, config.state will be set
|
||||
* in atomic check
|
||||
*/
|
||||
if (config.state == VRR_STATE_ACTIVE_FIXED && config.fixed_refresh_in_uhz &&
|
||||
(!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) ||
|
||||
new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)) {
|
||||
vrr_params.max_refresh_in_uhz = config.max_refresh_in_uhz;
|
||||
vrr_params.min_refresh_in_uhz = config.min_refresh_in_uhz;
|
||||
vrr_params.fixed_refresh_in_uhz = config.fixed_refresh_in_uhz;
|
||||
vrr_params.state = VRR_STATE_ACTIVE_FIXED;
|
||||
} else {
|
||||
config.state = new_crtc_state->base.vrr_enabled ?
|
||||
VRR_STATE_ACTIVE_VARIABLE :
|
||||
VRR_STATE_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
config.state = VRR_STATE_UNSUPPORTED;
|
||||
}
|
||||
|
||||
mod_freesync_build_vrr_params(dm->freesync_module,
|
||||
new_stream,
|
||||
&config, &vrr_params);
|
||||
|
||||
new_crtc_state->freesync_config = config;
|
||||
/* Copy state for access from DM IRQ handler */
|
||||
acrtc->dm_irq_params.freesync_config = config;
|
||||
acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes;
|
||||
acrtc->dm_irq_params.vrr_params = vrr_params;
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
|
||||
static void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state)
|
||||
{
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
|
||||
bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state);
|
||||
|
||||
/* Only DCE gates vupdate on VRR, keep it enabled for DCN */
|
||||
bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0;
|
||||
|
||||
if (!old_vrr_active && new_vrr_active) {
|
||||
/* Transition VRR inactive -> active:
|
||||
* While VRR is active, we must not disable vblank irq, as a
|
||||
* reenable after disable would compute bogus vblank/pflip
|
||||
* timestamps if it likely happened inside display front-porch.
|
||||
*
|
||||
* We also need vupdate irq for the actual core vblank handling
|
||||
* at end of vblank.
|
||||
*/
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0);
|
||||
WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
|
||||
scoped_guard(mutex, &dm->dc_lock) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, new_state->stream, true,
|
||||
psr_event_vrr_transition, true);
|
||||
amdgpu_dm_replay_set_event(dm, new_state->stream, true,
|
||||
replay_event_vrr, true);
|
||||
}
|
||||
} else if (old_vrr_active && !new_vrr_active) {
|
||||
/* Transition VRR active -> inactive:
|
||||
* Allow vblank irq disable again for fixed refresh rate.
|
||||
*/
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0);
|
||||
drm_crtc_vblank_put(new_state->base.crtc);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
|
||||
scoped_guard(mutex, &dm->dc_lock) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, new_state->stream, false,
|
||||
psr_event_vrr_transition, false);
|
||||
amdgpu_dm_replay_set_event(dm, new_state->stream, false,
|
||||
replay_event_vrr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void amdgpu_dm_commit_cursors(struct drm_atomic_commit *state)
|
||||
{
|
||||
struct drm_plane *plane;
|
||||
|
|
@ -4177,7 +3952,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
|||
}
|
||||
|
||||
if (plane == pcrtc->primary)
|
||||
update_freesync_state_on_stream(
|
||||
amdgpu_dm_update_freesync_state_on_stream(
|
||||
dm,
|
||||
acrtc_state,
|
||||
acrtc_state->stream,
|
||||
|
|
@ -4295,7 +4070,7 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
|
|||
* re-adjust the min/max bounds now that DC doesn't handle this
|
||||
* as part of commit.
|
||||
*/
|
||||
if (is_dc_timing_adjust_needed(dm_old_crtc_state, acrtc_state)) {
|
||||
if (amdgpu_dm_is_dc_timing_adjust_needed(dm_old_crtc_state, acrtc_state)) {
|
||||
spin_lock_irqsave(&pcrtc->dev->event_lock, flags);
|
||||
dc_stream_adjust_vmin_vmax(
|
||||
dm->dc, acrtc_state->stream,
|
||||
|
|
@ -5346,7 +5121,7 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_commit *state)
|
|||
dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
|
||||
|
||||
/* For freesync config update on crtc state and params for irq */
|
||||
update_stream_irq_parameters(dm, dm_new_crtc_state);
|
||||
amdgpu_dm_update_stream_irq_parameters(dm, dm_new_crtc_state);
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
|
|
@ -5546,108 +5321,6 @@ static int do_aquire_global_lock(struct drm_device *dev,
|
|||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
|
||||
STATIC_IFN_KUNIT void get_freesync_config_for_crtc(
|
||||
struct dm_crtc_state *new_crtc_state,
|
||||
struct dm_connector_state *new_con_state)
|
||||
{
|
||||
struct mod_freesync_config config = {0};
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_display_mode *mode = &new_crtc_state->base.mode;
|
||||
int vrefresh = drm_mode_vrefresh(mode);
|
||||
bool fs_vid_mode = false;
|
||||
|
||||
if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
return;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(new_con_state->base.connector);
|
||||
|
||||
new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
|
||||
vrefresh >= aconnector->min_vfreq &&
|
||||
vrefresh <= aconnector->max_vfreq;
|
||||
|
||||
if (new_crtc_state->vrr_supported) {
|
||||
new_crtc_state->stream->ignore_msa_timing_param = true;
|
||||
fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000;
|
||||
config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000;
|
||||
config.vsif_supported = true;
|
||||
config.btr = true;
|
||||
|
||||
if (fs_vid_mode) {
|
||||
config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz;
|
||||
goto out;
|
||||
} else if (new_crtc_state->base.vrr_enabled) {
|
||||
config.state = VRR_STATE_ACTIVE_VARIABLE;
|
||||
} else {
|
||||
config.state = VRR_STATE_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
config.state = VRR_STATE_UNSUPPORTED;
|
||||
}
|
||||
out:
|
||||
new_crtc_state->freesync_config = config;
|
||||
}
|
||||
EXPORT_IF_KUNIT(get_freesync_config_for_crtc);
|
||||
|
||||
STATIC_IFN_KUNIT void reset_freesync_config_for_crtc(
|
||||
struct dm_crtc_state *new_crtc_state)
|
||||
{
|
||||
new_crtc_state->vrr_supported = false;
|
||||
|
||||
memset(&new_crtc_state->vrr_infopacket, 0,
|
||||
sizeof(new_crtc_state->vrr_infopacket));
|
||||
}
|
||||
EXPORT_IF_KUNIT(reset_freesync_config_for_crtc);
|
||||
|
||||
STATIC_IFN_KUNIT bool
|
||||
is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state)
|
||||
{
|
||||
const struct drm_display_mode *old_mode, *new_mode;
|
||||
|
||||
if (!old_crtc_state || !new_crtc_state)
|
||||
return false;
|
||||
|
||||
old_mode = &old_crtc_state->mode;
|
||||
new_mode = &new_crtc_state->mode;
|
||||
|
||||
if (old_mode->clock == new_mode->clock &&
|
||||
old_mode->hdisplay == new_mode->hdisplay &&
|
||||
old_mode->vdisplay == new_mode->vdisplay &&
|
||||
old_mode->htotal == new_mode->htotal &&
|
||||
old_mode->vtotal != new_mode->vtotal &&
|
||||
old_mode->hsync_start == new_mode->hsync_start &&
|
||||
old_mode->vsync_start != new_mode->vsync_start &&
|
||||
old_mode->hsync_end == new_mode->hsync_end &&
|
||||
old_mode->vsync_end != new_mode->vsync_end &&
|
||||
old_mode->hskew == new_mode->hskew &&
|
||||
old_mode->vscan == new_mode->vscan &&
|
||||
(old_mode->vsync_end - old_mode->vsync_start) ==
|
||||
(new_mode->vsync_end - new_mode->vsync_start))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_IF_KUNIT(is_timing_unchanged_for_freesync);
|
||||
|
||||
STATIC_IFN_KUNIT void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
|
||||
{
|
||||
u64 num, den, res;
|
||||
struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
|
||||
|
||||
dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
num = (unsigned long long)new_crtc_state->mode.clock * 1000 * 1000000;
|
||||
den = (unsigned long long)new_crtc_state->mode.htotal *
|
||||
(unsigned long long)new_crtc_state->mode.vtotal;
|
||||
|
||||
res = div_u64(num, den);
|
||||
dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res;
|
||||
}
|
||||
EXPORT_IF_KUNIT(set_freesync_fixed_config);
|
||||
|
||||
static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
||||
struct drm_atomic_commit *state,
|
||||
struct drm_crtc *crtc,
|
||||
|
|
@ -5744,7 +5417,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
|||
*/
|
||||
if (amdgpu_freesync_vid_mode &&
|
||||
dm_new_crtc_state->stream &&
|
||||
is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(new_crtc_state, old_crtc_state))
|
||||
goto skip_modeset;
|
||||
|
||||
if (dm_new_crtc_state->stream &&
|
||||
|
|
@ -5786,14 +5459,14 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
|||
if (amdgpu_freesync_vid_mode && dm_new_crtc_state->stream &&
|
||||
dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) &&
|
||||
dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream) &&
|
||||
is_timing_unchanged_for_freesync(new_crtc_state,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(new_crtc_state,
|
||||
old_crtc_state)) {
|
||||
new_crtc_state->mode_changed = false;
|
||||
drm_dbg_driver(adev_to_drm(adev),
|
||||
"Mode change not required for front porch change, setting mode_changed to %d",
|
||||
new_crtc_state->mode_changed);
|
||||
|
||||
set_freesync_fixed_config(dm_new_crtc_state);
|
||||
amdgpu_dm_set_freesync_fixed_config(dm_new_crtc_state);
|
||||
|
||||
goto skip_modeset;
|
||||
} else if (amdgpu_freesync_vid_mode && aconnector &&
|
||||
|
|
@ -5803,7 +5476,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
|||
|
||||
high_mode = amdgpu_dm_get_highest_refresh_rate_mode(aconnector, false);
|
||||
if (!drm_mode_equal(&new_crtc_state->mode, high_mode))
|
||||
set_freesync_fixed_config(dm_new_crtc_state);
|
||||
amdgpu_dm_set_freesync_fixed_config(dm_new_crtc_state);
|
||||
}
|
||||
|
||||
ret = dm_atomic_get_state(state, &dm_state);
|
||||
|
|
@ -5825,7 +5498,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
|||
dc_stream_release(dm_old_crtc_state->stream);
|
||||
dm_new_crtc_state->stream = NULL;
|
||||
|
||||
reset_freesync_config_for_crtc(dm_new_crtc_state);
|
||||
amdgpu_dm_reset_freesync_config_for_crtc(dm_new_crtc_state);
|
||||
|
||||
*lock_and_validation_needed = true;
|
||||
|
||||
|
|
@ -5913,7 +5586,7 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
|
|||
}
|
||||
|
||||
/* Update Freesync settings. */
|
||||
get_freesync_config_for_crtc(dm_new_crtc_state,
|
||||
amdgpu_dm_get_freesync_config_for_crtc(dm_new_crtc_state,
|
||||
dm_new_conn_state);
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -1172,16 +1172,8 @@ void dm_get_plane_scale(struct drm_plane_state *plane_state,
|
|||
int *out_plane_scale_w, int *out_plane_scale_h);
|
||||
bool is_scaling_state_different(const struct dm_connector_state *dm_state,
|
||||
const struct dm_connector_state *old_dm_state);
|
||||
bool is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state);
|
||||
void set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state);
|
||||
bool is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state);
|
||||
void set_multisync_trigger_params(struct dc_stream_state *stream);
|
||||
void set_master_stream(struct dc_stream_state *stream_set[], int stream_count);
|
||||
void reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
|
||||
void get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
|
||||
struct dm_connector_state *new_con_state);
|
||||
void dm_enable_per_frame_crtc_master_sync(struct dc_state *context);
|
||||
struct hdcp_workqueue;
|
||||
bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
|
||||
|
|
|
|||
362
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
Normal file
362
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
/*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_modes.h>
|
||||
#include <drm/drm_vblank.h>
|
||||
|
||||
#include "dc.h"
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_dm_crtc.h"
|
||||
#include "amdgpu_dm_psr.h"
|
||||
#include "amdgpu_dm_replay.h"
|
||||
#include "amdgpu_dm_freesync.h"
|
||||
#include "dm_helpers.h"
|
||||
#include "modules/inc/mod_freesync.h"
|
||||
|
||||
bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state)
|
||||
{
|
||||
if (new_state->stream->adjust.timing_adjust_pending)
|
||||
return true;
|
||||
if (new_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)
|
||||
return true;
|
||||
else if (amdgpu_dm_crtc_vrr_active(old_state) != amdgpu_dm_crtc_vrr_active(new_state))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_is_dc_timing_adjust_needed);
|
||||
|
||||
bool
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state)
|
||||
{
|
||||
const struct drm_display_mode *old_mode, *new_mode;
|
||||
|
||||
if (!old_crtc_state || !new_crtc_state)
|
||||
return false;
|
||||
|
||||
old_mode = &old_crtc_state->mode;
|
||||
new_mode = &new_crtc_state->mode;
|
||||
|
||||
if (old_mode->clock == new_mode->clock &&
|
||||
old_mode->hdisplay == new_mode->hdisplay &&
|
||||
old_mode->vdisplay == new_mode->vdisplay &&
|
||||
old_mode->htotal == new_mode->htotal &&
|
||||
old_mode->vtotal != new_mode->vtotal &&
|
||||
old_mode->hsync_start == new_mode->hsync_start &&
|
||||
old_mode->vsync_start != new_mode->vsync_start &&
|
||||
old_mode->hsync_end == new_mode->hsync_end &&
|
||||
old_mode->vsync_end != new_mode->vsync_end &&
|
||||
old_mode->hskew == new_mode->hskew &&
|
||||
old_mode->vscan == new_mode->vscan &&
|
||||
(old_mode->vsync_end - old_mode->vsync_start) ==
|
||||
(new_mode->vsync_end - new_mode->vsync_start))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_is_timing_unchanged_for_freesync);
|
||||
|
||||
void amdgpu_dm_set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state)
|
||||
{
|
||||
u64 num, den, res;
|
||||
struct drm_crtc_state *new_crtc_state = &dm_new_crtc_state->base;
|
||||
|
||||
dm_new_crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
num = (unsigned long long)new_crtc_state->mode.clock * 1000 * 1000000;
|
||||
den = (unsigned long long)new_crtc_state->mode.htotal *
|
||||
(unsigned long long)new_crtc_state->mode.vtotal;
|
||||
|
||||
res = div_u64(num, den);
|
||||
dm_new_crtc_state->freesync_config.fixed_refresh_in_uhz = res;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_set_freesync_fixed_config);
|
||||
|
||||
void amdgpu_dm_reset_freesync_config_for_crtc(
|
||||
struct dm_crtc_state *new_crtc_state)
|
||||
{
|
||||
new_crtc_state->vrr_supported = false;
|
||||
|
||||
memset(&new_crtc_state->vrr_infopacket, 0,
|
||||
sizeof(new_crtc_state->vrr_infopacket));
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_reset_freesync_config_for_crtc);
|
||||
|
||||
void amdgpu_dm_get_freesync_config_for_crtc(
|
||||
struct dm_crtc_state *new_crtc_state,
|
||||
struct dm_connector_state *new_con_state)
|
||||
{
|
||||
struct mod_freesync_config config = {0};
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct drm_display_mode *mode = &new_crtc_state->base.mode;
|
||||
int vrefresh = drm_mode_vrefresh(mode);
|
||||
bool fs_vid_mode = false;
|
||||
|
||||
if (new_con_state->base.connector->connector_type == DRM_MODE_CONNECTOR_WRITEBACK)
|
||||
return;
|
||||
|
||||
aconnector = to_amdgpu_dm_connector(new_con_state->base.connector);
|
||||
|
||||
new_crtc_state->vrr_supported = new_con_state->freesync_capable &&
|
||||
vrefresh >= aconnector->min_vfreq &&
|
||||
vrefresh <= aconnector->max_vfreq;
|
||||
|
||||
if (new_crtc_state->vrr_supported) {
|
||||
new_crtc_state->stream->ignore_msa_timing_param = true;
|
||||
fs_vid_mode = new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
config.min_refresh_in_uhz = aconnector->min_vfreq * 1000000;
|
||||
config.max_refresh_in_uhz = aconnector->max_vfreq * 1000000;
|
||||
config.vsif_supported = true;
|
||||
config.btr = true;
|
||||
|
||||
if (fs_vid_mode) {
|
||||
config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
config.fixed_refresh_in_uhz = new_crtc_state->freesync_config.fixed_refresh_in_uhz;
|
||||
goto out;
|
||||
} else if (new_crtc_state->base.vrr_enabled) {
|
||||
config.state = VRR_STATE_ACTIVE_VARIABLE;
|
||||
} else {
|
||||
config.state = VRR_STATE_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
config.state = VRR_STATE_UNSUPPORTED;
|
||||
}
|
||||
out:
|
||||
new_crtc_state->freesync_config = config;
|
||||
}
|
||||
EXPORT_IF_KUNIT(amdgpu_dm_get_freesync_config_for_crtc);
|
||||
|
||||
void amdgpu_dm_update_freesync_state_on_stream(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state,
|
||||
struct dc_stream_state *new_stream,
|
||||
struct dc_plane_state *surface,
|
||||
u32 flip_timestamp_in_us)
|
||||
{
|
||||
struct mod_vrr_params vrr_params;
|
||||
struct dc_info_packet vrr_infopacket = {0};
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
|
||||
unsigned long flags;
|
||||
bool pack_sdp_v1_3 = false;
|
||||
struct amdgpu_dm_connector *aconn;
|
||||
enum vrr_packet_type packet_type = PACKET_TYPE_VRR;
|
||||
|
||||
if (!new_stream)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Determine why min/max totals and vrefresh can be 0 here.
|
||||
* For now it's sufficient to just guard against these conditions.
|
||||
*/
|
||||
|
||||
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
vrr_params = acrtc->dm_irq_params.vrr_params;
|
||||
|
||||
if (surface) {
|
||||
mod_freesync_handle_preflip(
|
||||
dm->freesync_module,
|
||||
surface,
|
||||
new_stream,
|
||||
flip_timestamp_in_us,
|
||||
&vrr_params);
|
||||
|
||||
if (adev->family < AMDGPU_FAMILY_AI &&
|
||||
amdgpu_dm_crtc_vrr_active(new_crtc_state)) {
|
||||
mod_freesync_handle_v_update(dm->freesync_module,
|
||||
new_stream, &vrr_params);
|
||||
|
||||
/* Need to call this before the frame ends. */
|
||||
dc_stream_adjust_vmin_vmax(dm->dc,
|
||||
new_crtc_state->stream,
|
||||
&vrr_params.adjust);
|
||||
}
|
||||
}
|
||||
|
||||
aconn = (struct amdgpu_dm_connector *)new_stream->dm_stream_context;
|
||||
|
||||
if (aconn && (aconn->as_type == FREESYNC_TYPE_PCON_IN_WHITELIST || aconn->vsdb_info.replay_mode)) {
|
||||
pack_sdp_v1_3 = aconn->pack_sdp_v1_3;
|
||||
|
||||
if (aconn->vsdb_info.amd_vsdb_version == 1)
|
||||
packet_type = PACKET_TYPE_FS_V1;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 2)
|
||||
packet_type = PACKET_TYPE_FS_V2;
|
||||
else if (aconn->vsdb_info.amd_vsdb_version == 3)
|
||||
packet_type = PACKET_TYPE_FS_V3;
|
||||
|
||||
mod_build_adaptive_sync_infopacket(new_stream, aconn->as_type, NULL,
|
||||
&new_stream->adaptive_sync_infopacket);
|
||||
}
|
||||
|
||||
mod_freesync_build_vrr_infopacket(
|
||||
dm->freesync_module,
|
||||
new_stream,
|
||||
&vrr_params,
|
||||
packet_type,
|
||||
TRANSFER_FUNC_UNKNOWN,
|
||||
&vrr_infopacket,
|
||||
pack_sdp_v1_3);
|
||||
|
||||
new_crtc_state->freesync_vrr_info_changed |=
|
||||
(memcmp(&new_crtc_state->vrr_infopacket,
|
||||
&vrr_infopacket,
|
||||
sizeof(vrr_infopacket)) != 0);
|
||||
|
||||
acrtc->dm_irq_params.vrr_params = vrr_params;
|
||||
new_crtc_state->vrr_infopacket = vrr_infopacket;
|
||||
|
||||
new_stream->vrr_infopacket = vrr_infopacket;
|
||||
new_stream->allow_freesync = mod_freesync_get_freesync_enabled(&vrr_params);
|
||||
|
||||
if (new_crtc_state->freesync_vrr_info_changed)
|
||||
drm_dbg_kms(adev_to_drm(adev), "VRR packet update: crtc=%u enabled=%d state=%d",
|
||||
new_crtc_state->base.crtc->base.id,
|
||||
(int)new_crtc_state->base.vrr_enabled,
|
||||
(int)vrr_params.state);
|
||||
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
|
||||
void amdgpu_dm_update_stream_irq_parameters(
|
||||
struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state)
|
||||
{
|
||||
struct dc_stream_state *new_stream = new_crtc_state->stream;
|
||||
struct mod_vrr_params vrr_params;
|
||||
struct mod_freesync_config config = new_crtc_state->freesync_config;
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
struct amdgpu_crtc *acrtc = to_amdgpu_crtc(new_crtc_state->base.crtc);
|
||||
unsigned long flags;
|
||||
|
||||
if (!new_stream)
|
||||
return;
|
||||
|
||||
/*
|
||||
* TODO: Determine why min/max totals and vrefresh can be 0 here.
|
||||
* For now it's sufficient to just guard against these conditions.
|
||||
*/
|
||||
if (!new_stream->timing.h_total || !new_stream->timing.v_total)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
|
||||
vrr_params = acrtc->dm_irq_params.vrr_params;
|
||||
|
||||
if (new_crtc_state->vrr_supported &&
|
||||
config.min_refresh_in_uhz &&
|
||||
config.max_refresh_in_uhz) {
|
||||
/*
|
||||
* if freesync compatible mode was set, config.state will be set
|
||||
* in atomic check
|
||||
*/
|
||||
if (config.state == VRR_STATE_ACTIVE_FIXED && config.fixed_refresh_in_uhz &&
|
||||
(!drm_atomic_crtc_needs_modeset(&new_crtc_state->base) ||
|
||||
new_crtc_state->freesync_config.state == VRR_STATE_ACTIVE_FIXED)) {
|
||||
vrr_params.max_refresh_in_uhz = config.max_refresh_in_uhz;
|
||||
vrr_params.min_refresh_in_uhz = config.min_refresh_in_uhz;
|
||||
vrr_params.fixed_refresh_in_uhz = config.fixed_refresh_in_uhz;
|
||||
vrr_params.state = VRR_STATE_ACTIVE_FIXED;
|
||||
} else {
|
||||
config.state = new_crtc_state->base.vrr_enabled ?
|
||||
VRR_STATE_ACTIVE_VARIABLE :
|
||||
VRR_STATE_INACTIVE;
|
||||
}
|
||||
} else {
|
||||
config.state = VRR_STATE_UNSUPPORTED;
|
||||
}
|
||||
|
||||
mod_freesync_build_vrr_params(dm->freesync_module,
|
||||
new_stream,
|
||||
&config, &vrr_params);
|
||||
|
||||
new_crtc_state->freesync_config = config;
|
||||
/* Copy state for access from DM IRQ handler */
|
||||
acrtc->dm_irq_params.freesync_config = config;
|
||||
acrtc->dm_irq_params.active_planes = new_crtc_state->active_planes;
|
||||
acrtc->dm_irq_params.vrr_params = vrr_params;
|
||||
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
|
||||
}
|
||||
|
||||
void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state)
|
||||
{
|
||||
struct amdgpu_device *adev = dm->adev;
|
||||
bool old_vrr_active = amdgpu_dm_crtc_vrr_active(old_state);
|
||||
bool new_vrr_active = amdgpu_dm_crtc_vrr_active(new_state);
|
||||
|
||||
/* Only DCE gates vupdate on VRR, keep it enabled for DCN */
|
||||
bool vrr_gates_vupdate = amdgpu_ip_version(adev, DCE_HWIP, 0) == 0;
|
||||
|
||||
if (!old_vrr_active && new_vrr_active) {
|
||||
/* Transition VRR inactive -> active:
|
||||
* While VRR is active, we must not disable vblank irq, as a
|
||||
* reenable after disable would compute bogus vblank/pflip
|
||||
* timestamps if it likely happened inside display front-porch.
|
||||
*
|
||||
* We also need vupdate irq for the actual core vblank handling
|
||||
* at end of vblank.
|
||||
*/
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, true) != 0);
|
||||
WARN_ON(drm_crtc_vblank_get(new_state->base.crtc) != 0);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR off->on: Get vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
|
||||
scoped_guard(mutex, &dm->dc_lock) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, new_state->stream, true,
|
||||
psr_event_vrr_transition, true);
|
||||
amdgpu_dm_replay_set_event(dm, new_state->stream, true,
|
||||
replay_event_vrr, true);
|
||||
}
|
||||
} else if (old_vrr_active && !new_vrr_active) {
|
||||
/* Transition VRR active -> inactive:
|
||||
* Allow vblank irq disable again for fixed refresh rate.
|
||||
*/
|
||||
if (vrr_gates_vupdate)
|
||||
WARN_ON(amdgpu_dm_crtc_set_vupdate_irq(new_state->base.crtc, false) != 0);
|
||||
drm_crtc_vblank_put(new_state->base.crtc);
|
||||
drm_dbg_driver(new_state->base.crtc->dev, "%s: crtc=%u VRR on->off: Drop vblank ref\n",
|
||||
__func__, new_state->base.crtc->base.id);
|
||||
|
||||
scoped_guard(mutex, &dm->dc_lock) {
|
||||
dc_exit_ips_for_hw_access(dm->dc);
|
||||
amdgpu_dm_psr_set_event(dm, new_state->stream, false,
|
||||
psr_event_vrr_transition, false);
|
||||
amdgpu_dm_replay_set_event(dm, new_state->stream, false,
|
||||
replay_event_vrr, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
65
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h
Normal file
65
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
/*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
* OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors: AMD
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __AMDGPU_DM_FREESYNC_H__
|
||||
#define __AMDGPU_DM_FREESYNC_H__
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
struct amdgpu_display_manager;
|
||||
struct dm_crtc_state;
|
||||
struct dm_connector_state;
|
||||
struct dc_stream_state;
|
||||
struct dc_plane_state;
|
||||
struct drm_crtc_state;
|
||||
|
||||
bool amdgpu_dm_is_dc_timing_adjust_needed(struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state);
|
||||
|
||||
bool amdgpu_dm_is_timing_unchanged_for_freesync(struct drm_crtc_state *old_crtc_state,
|
||||
struct drm_crtc_state *new_crtc_state);
|
||||
|
||||
void amdgpu_dm_set_freesync_fixed_config(struct dm_crtc_state *dm_new_crtc_state);
|
||||
|
||||
void amdgpu_dm_reset_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state);
|
||||
|
||||
void amdgpu_dm_get_freesync_config_for_crtc(struct dm_crtc_state *new_crtc_state,
|
||||
struct dm_connector_state *new_con_state);
|
||||
|
||||
void amdgpu_dm_update_freesync_state_on_stream(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state,
|
||||
struct dc_stream_state *new_stream,
|
||||
struct dc_plane_state *surface,
|
||||
u32 flip_timestamp_in_us);
|
||||
|
||||
void amdgpu_dm_update_stream_irq_parameters(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *new_crtc_state);
|
||||
|
||||
void amdgpu_dm_handle_vrr_transition(struct amdgpu_display_manager *dm,
|
||||
struct dm_crtc_state *old_state,
|
||||
struct dm_crtc_state *new_state);
|
||||
|
||||
#endif /* __AMDGPU_DM_FREESYNC_H__ */
|
||||
|
|
@ -29,6 +29,7 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_plane_test.o
|
|||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_mst_types_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_pp_smu_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_freesync_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_helpers_test.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,453 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_freesync.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <drm/drm_atomic.h>
|
||||
#include <drm/drm_connector.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_modes.h>
|
||||
|
||||
#include "dc.h"
|
||||
#include "inc/core_types.h"
|
||||
#include "amd_shared.h"
|
||||
#include "amdgpu.h"
|
||||
#include "amdgpu_mode.h"
|
||||
#include "amdgpu_dm.h"
|
||||
#include "amdgpu_dm_freesync.h"
|
||||
#include "amdgpu_dm_kunit_test_helpers.h"
|
||||
|
||||
/* Tests for amdgpu_dm_is_timing_unchanged_for_freesync() */
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_null_args - Test NULL crtc states return false
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_null_args(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state crtc_state = { 0 };
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(NULL, &crtc_state));
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(&crtc_state, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_identical_modes - Test identical modes are not "unchanged"
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* The helper only returns true when vtotal/vsync shift (vrr) while the rest
|
||||
* of the timing stays fixed, so identical modes must return false.
|
||||
*/
|
||||
static void dm_test_timing_unchanged_identical_modes(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.hdisplay = 1920;
|
||||
old_state.mode.vdisplay = 1080;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
new_state.mode = old_state.mode;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_vrr_shift - Test vrr-style vtotal/vsync shift is detected
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_vrr_shift(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.hdisplay = 1920;
|
||||
old_state.mode.vdisplay = 1080;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
old_state.mode.hsync_start = 2008;
|
||||
old_state.mode.vsync_start = 1084;
|
||||
old_state.mode.hsync_end = 2052;
|
||||
old_state.mode.vsync_end = 1089;
|
||||
|
||||
/* Same horizontal timing, vertical totals/sync shifted by 125 lines */
|
||||
new_state.mode = old_state.mode;
|
||||
new_state.mode.vtotal = 1250;
|
||||
new_state.mode.vsync_start = 1209;
|
||||
new_state.mode.vsync_end = 1214;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_clock_changed - Test pixel clock change returns false
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_clock_changed(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
old_state.mode.vsync_start = 1084;
|
||||
old_state.mode.vsync_end = 1089;
|
||||
|
||||
new_state.mode = old_state.mode;
|
||||
new_state.mode.clock = 297000;
|
||||
new_state.mode.vtotal = 1250;
|
||||
new_state.mode.vsync_start = 1209;
|
||||
new_state.mode.vsync_end = 1214;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
amdgpu_dm_is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_set_freesync_fixed_config() */
|
||||
|
||||
/**
|
||||
* dm_test_set_freesync_fixed_config_60hz - Test fixed refresh computed for 1080p60
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_set_freesync_fixed_config_60hz(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state dm_crtc_state = { 0 };
|
||||
|
||||
dm_crtc_state.base.mode.clock = 148500;
|
||||
dm_crtc_state.base.mode.htotal = 2200;
|
||||
dm_crtc_state.base.mode.vtotal = 1125;
|
||||
|
||||
amdgpu_dm_set_freesync_fixed_config(&dm_crtc_state);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)dm_crtc_state.freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_FIXED);
|
||||
/* 148500 kHz / (2200 * 1125) = 60 Hz = 60000000 uHz */
|
||||
KUNIT_EXPECT_EQ(test, dm_crtc_state.freesync_config.fixed_refresh_in_uhz,
|
||||
60000000U);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_is_dc_timing_adjust_needed() */
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_pending - Test a pending hw timing adjust forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_pending(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
stream->adjust.timing_adjust_pending = 1;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_active_fixed - Test VRR active-fixed forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_active_fixed(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
new_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_vrr_toggle - Test a change in vrr active state forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_vrr_toggle(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
old_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
|
||||
new_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, amdgpu_dm_is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_not_needed - Test steady-state timing needs no adjust
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_not_needed(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
old_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
new_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, amdgpu_dm_is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_get_freesync_config_for_crtc() */
|
||||
|
||||
struct dm_test_freesync_ctx {
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct dm_crtc_state *crtc_state;
|
||||
struct dm_connector_state *conn_state;
|
||||
struct dc_stream_state *stream;
|
||||
};
|
||||
|
||||
static struct dm_test_freesync_ctx *dm_test_freesync_ctx_alloc(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx;
|
||||
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx);
|
||||
|
||||
ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
|
||||
ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
|
||||
ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
|
||||
ctx->stream = dm_kunit_alloc_stream(test, NULL);
|
||||
|
||||
ctx->conn_state->base.connector = &ctx->aconnector->base;
|
||||
ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
ctx->crtc_state->stream = ctx->stream;
|
||||
|
||||
/* 1080p60 timing so drm_mode_vrefresh() == 60 */
|
||||
ctx->crtc_state->base.mode.clock = 148500;
|
||||
ctx->crtc_state->base.mode.htotal = 2200;
|
||||
ctx->crtc_state->base.mode.vtotal = 1125;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_writeback - Test writeback connector is left untouched
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_writeback(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK;
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->vrr_supported = true; /* sentinel: must stay set */
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
/* Writeback: early return leaves vrr_supported sentinel untouched */
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_not_capable - Test a non-freesync sink reports UNSUPPORTED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_not_capable(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = false;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_out_of_range - Test a refresh outside the range is UNSUPPORTED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_out_of_range(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 90; /* 60 < 90 -> out of range */
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_active_variable - Test vrr_enabled yields ACTIVE_VARIABLE
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_active_variable(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->base.vrr_enabled = true;
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->stream->ignore_msa_timing_param);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_VARIABLE);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.min_refresh_in_uhz,
|
||||
48000000U);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.max_refresh_in_uhz,
|
||||
120000000U);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.vsif_supported);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.btr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_inactive - Test supported-but-off yields INACTIVE
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_inactive(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->base.vrr_enabled = false;
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_INACTIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_active_fixed - Test freesync-video mode yields ACTIVE_FIXED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_active_fixed(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
/* Pre-set fixed state selects the freesync-video (fixed) path */
|
||||
ctx->crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
ctx->crtc_state->freesync_config.fixed_refresh_in_uhz = 60000000;
|
||||
ctx->crtc_state->base.vrr_enabled = true; /* ignored on the fixed path */
|
||||
|
||||
amdgpu_dm_get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_FIXED);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.fixed_refresh_in_uhz,
|
||||
60000000U);
|
||||
}
|
||||
|
||||
/* Tests for amdgpu_dm_reset_freesync_config_for_crtc() */
|
||||
|
||||
/**
|
||||
* dm_test_reset_freesync_config - Test reset clears vrr support and info packet
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_reset_freesync_config(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *crtc_state;
|
||||
|
||||
crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, crtc_state);
|
||||
|
||||
crtc_state->vrr_supported = true;
|
||||
crtc_state->vrr_infopacket.valid = true;
|
||||
|
||||
amdgpu_dm_reset_freesync_config_for_crtc(crtc_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_FALSE(test, crtc_state->vrr_infopacket.valid);
|
||||
}
|
||||
|
||||
static struct kunit_case amdgpu_dm_freesync_tests[] = {
|
||||
/* amdgpu_dm_is_timing_unchanged_for_freesync */
|
||||
KUNIT_CASE(dm_test_timing_unchanged_null_args),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_identical_modes),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_vrr_shift),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_clock_changed),
|
||||
/* amdgpu_dm_set_freesync_fixed_config */
|
||||
KUNIT_CASE(dm_test_set_freesync_fixed_config_60hz),
|
||||
/* amdgpu_dm_is_dc_timing_adjust_needed */
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_pending),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_active_fixed),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_vrr_toggle),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_not_needed),
|
||||
/* amdgpu_dm_get_freesync_config_for_crtc */
|
||||
KUNIT_CASE(dm_test_freesync_config_writeback),
|
||||
KUNIT_CASE(dm_test_freesync_config_not_capable),
|
||||
KUNIT_CASE(dm_test_freesync_config_out_of_range),
|
||||
KUNIT_CASE(dm_test_freesync_config_active_variable),
|
||||
KUNIT_CASE(dm_test_freesync_config_inactive),
|
||||
KUNIT_CASE(dm_test_freesync_config_active_fixed),
|
||||
/* amdgpu_dm_reset_freesync_config_for_crtc */
|
||||
KUNIT_CASE(dm_test_reset_freesync_config),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite amdgpu_dm_freesync_test_suite = {
|
||||
.name = "amdgpu_dm_freesync",
|
||||
.test_cases = amdgpu_dm_freesync_tests,
|
||||
};
|
||||
|
||||
kunit_test_suite(amdgpu_dm_freesync_test_suite);
|
||||
|
||||
MODULE_AUTHOR("AMD");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_freesync");
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
|
|
@ -860,214 +860,6 @@ static void dm_test_scaling_state_underscan_border_changed(struct kunit *test)
|
|||
KUNIT_EXPECT_TRUE(test, is_scaling_state_different(a, b));
|
||||
}
|
||||
|
||||
/* Tests for is_timing_unchanged_for_freesync() */
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_null_args - Test NULL crtc states return false
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_null_args(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state crtc_state = { 0 };
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
is_timing_unchanged_for_freesync(NULL, &crtc_state));
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
is_timing_unchanged_for_freesync(&crtc_state, NULL));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_identical_modes - Test identical modes are not "unchanged"
|
||||
* @test: The KUnit test context
|
||||
*
|
||||
* The helper only returns true when vtotal/vsync shift (vrr) while the rest
|
||||
* of the timing stays fixed, so identical modes must return false.
|
||||
*/
|
||||
static void dm_test_timing_unchanged_identical_modes(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.hdisplay = 1920;
|
||||
old_state.mode.vdisplay = 1080;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
new_state.mode = old_state.mode;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_vrr_shift - Test vrr-style vtotal/vsync shift is detected
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_vrr_shift(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.hdisplay = 1920;
|
||||
old_state.mode.vdisplay = 1080;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
old_state.mode.hsync_start = 2008;
|
||||
old_state.mode.vsync_start = 1084;
|
||||
old_state.mode.hsync_end = 2052;
|
||||
old_state.mode.vsync_end = 1089;
|
||||
|
||||
/* Same horizontal timing, vertical totals/sync shifted by 125 lines */
|
||||
new_state.mode = old_state.mode;
|
||||
new_state.mode.vtotal = 1250;
|
||||
new_state.mode.vsync_start = 1209;
|
||||
new_state.mode.vsync_end = 1214;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test,
|
||||
is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_timing_unchanged_clock_changed - Test pixel clock change returns false
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_timing_unchanged_clock_changed(struct kunit *test)
|
||||
{
|
||||
struct drm_crtc_state old_state = { 0 };
|
||||
struct drm_crtc_state new_state = { 0 };
|
||||
|
||||
old_state.mode.clock = 148500;
|
||||
old_state.mode.htotal = 2200;
|
||||
old_state.mode.vtotal = 1125;
|
||||
old_state.mode.vsync_start = 1084;
|
||||
old_state.mode.vsync_end = 1089;
|
||||
|
||||
new_state.mode = old_state.mode;
|
||||
new_state.mode.clock = 297000;
|
||||
new_state.mode.vtotal = 1250;
|
||||
new_state.mode.vsync_start = 1209;
|
||||
new_state.mode.vsync_end = 1214;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test,
|
||||
is_timing_unchanged_for_freesync(&old_state, &new_state));
|
||||
}
|
||||
|
||||
/* Tests for set_freesync_fixed_config() */
|
||||
|
||||
/**
|
||||
* dm_test_set_freesync_fixed_config_60hz - Test fixed refresh computed for 1080p60
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_set_freesync_fixed_config_60hz(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state dm_crtc_state = { 0 };
|
||||
|
||||
dm_crtc_state.base.mode.clock = 148500;
|
||||
dm_crtc_state.base.mode.htotal = 2200;
|
||||
dm_crtc_state.base.mode.vtotal = 1125;
|
||||
|
||||
set_freesync_fixed_config(&dm_crtc_state);
|
||||
|
||||
KUNIT_EXPECT_EQ(test, (int)dm_crtc_state.freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_FIXED);
|
||||
/* 148500 kHz / (2200 * 1125) = 60 Hz = 60000000 uHz */
|
||||
KUNIT_EXPECT_EQ(test, dm_crtc_state.freesync_config.fixed_refresh_in_uhz,
|
||||
60000000U);
|
||||
}
|
||||
|
||||
/* Tests for is_dc_timing_adjust_needed() */
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_pending - Test a pending hw timing adjust forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_pending(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
stream->adjust.timing_adjust_pending = 1;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_active_fixed - Test VRR active-fixed forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_active_fixed(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
new_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_vrr_toggle - Test a change in vrr active state forces true
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_vrr_toggle(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
old_state->freesync_config.state = VRR_STATE_ACTIVE_VARIABLE;
|
||||
new_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_dc_timing_adjust_not_needed - Test steady-state timing needs no adjust
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_dc_timing_adjust_not_needed(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *old_state, *new_state;
|
||||
struct dc_stream_state *stream;
|
||||
|
||||
old_state = kunit_kzalloc(test, sizeof(*old_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, old_state);
|
||||
new_state = kunit_kzalloc(test, sizeof(*new_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_state);
|
||||
stream = kunit_kzalloc(test, sizeof(*stream), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, stream);
|
||||
|
||||
new_state->stream = stream;
|
||||
old_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
new_state->freesync_config.state = VRR_STATE_INACTIVE;
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, is_dc_timing_adjust_needed(old_state, new_state));
|
||||
}
|
||||
|
||||
/* Tests for set_multisync_trigger_params() */
|
||||
|
||||
/**
|
||||
|
|
@ -1435,194 +1227,6 @@ static void dm_test_cp_diff_desired_to_undesired(struct kunit *test)
|
|||
KUNIT_EXPECT_TRUE(test, dm_test_cp_diff(ctx));
|
||||
}
|
||||
|
||||
/* Tests for get_freesync_config_for_crtc() */
|
||||
|
||||
struct dm_test_freesync_ctx {
|
||||
struct amdgpu_dm_connector *aconnector;
|
||||
struct dm_crtc_state *crtc_state;
|
||||
struct dm_connector_state *conn_state;
|
||||
struct dc_stream_state *stream;
|
||||
};
|
||||
|
||||
static struct dm_test_freesync_ctx *dm_test_freesync_ctx_alloc(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx;
|
||||
|
||||
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx);
|
||||
|
||||
ctx->aconnector = kunit_kzalloc(test, sizeof(*ctx->aconnector), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->aconnector);
|
||||
ctx->crtc_state = kunit_kzalloc(test, sizeof(*ctx->crtc_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->crtc_state);
|
||||
ctx->conn_state = kunit_kzalloc(test, sizeof(*ctx->conn_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, ctx->conn_state);
|
||||
ctx->stream = dm_kunit_alloc_stream(test, NULL);
|
||||
|
||||
ctx->conn_state->base.connector = &ctx->aconnector->base;
|
||||
ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_DisplayPort;
|
||||
ctx->crtc_state->stream = ctx->stream;
|
||||
|
||||
/* 1080p60 timing so drm_mode_vrefresh() == 60 */
|
||||
ctx->crtc_state->base.mode.clock = 148500;
|
||||
ctx->crtc_state->base.mode.htotal = 2200;
|
||||
ctx->crtc_state->base.mode.vtotal = 1125;
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_writeback - Test writeback connector is left untouched
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_writeback(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->aconnector->base.connector_type = DRM_MODE_CONNECTOR_WRITEBACK;
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->vrr_supported = true; /* sentinel: must stay set */
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
/* Writeback: early return leaves vrr_supported sentinel untouched */
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_not_capable - Test a non-freesync sink reports UNSUPPORTED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_not_capable(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = false;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_out_of_range - Test a refresh outside the range is UNSUPPORTED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_out_of_range(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 90; /* 60 < 90 -> out of range */
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_UNSUPPORTED);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_active_variable - Test vrr_enabled yields ACTIVE_VARIABLE
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_active_variable(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->base.vrr_enabled = true;
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->stream->ignore_msa_timing_param);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_VARIABLE);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.min_refresh_in_uhz,
|
||||
48000000U);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.max_refresh_in_uhz,
|
||||
120000000U);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.vsif_supported);
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->freesync_config.btr);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_inactive - Test supported-but-off yields INACTIVE
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_inactive(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
ctx->crtc_state->base.vrr_enabled = false;
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_INACTIVE);
|
||||
}
|
||||
|
||||
/**
|
||||
* dm_test_freesync_config_active_fixed - Test freesync-video mode yields ACTIVE_FIXED
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_freesync_config_active_fixed(struct kunit *test)
|
||||
{
|
||||
struct dm_test_freesync_ctx *ctx = dm_test_freesync_ctx_alloc(test);
|
||||
|
||||
ctx->conn_state->freesync_capable = true;
|
||||
ctx->aconnector->min_vfreq = 48;
|
||||
ctx->aconnector->max_vfreq = 120;
|
||||
/* Pre-set fixed state selects the freesync-video (fixed) path */
|
||||
ctx->crtc_state->freesync_config.state = VRR_STATE_ACTIVE_FIXED;
|
||||
ctx->crtc_state->freesync_config.fixed_refresh_in_uhz = 60000000;
|
||||
ctx->crtc_state->base.vrr_enabled = true; /* ignored on the fixed path */
|
||||
|
||||
get_freesync_config_for_crtc(ctx->crtc_state, ctx->conn_state);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, ctx->crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_EQ(test, (int)ctx->crtc_state->freesync_config.state,
|
||||
(int)VRR_STATE_ACTIVE_FIXED);
|
||||
KUNIT_EXPECT_EQ(test, ctx->crtc_state->freesync_config.fixed_refresh_in_uhz,
|
||||
60000000U);
|
||||
}
|
||||
|
||||
/* Tests for reset_freesync_config_for_crtc() */
|
||||
|
||||
/**
|
||||
* dm_test_reset_freesync_config - Test reset clears vrr support and info packet
|
||||
* @test: The KUnit test context
|
||||
*/
|
||||
static void dm_test_reset_freesync_config(struct kunit *test)
|
||||
{
|
||||
struct dm_crtc_state *crtc_state;
|
||||
|
||||
crtc_state = kunit_kzalloc(test, sizeof(*crtc_state), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, crtc_state);
|
||||
|
||||
crtc_state->vrr_supported = true;
|
||||
crtc_state->vrr_infopacket.valid = true;
|
||||
|
||||
reset_freesync_config_for_crtc(crtc_state);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, crtc_state->vrr_supported);
|
||||
KUNIT_EXPECT_FALSE(test, crtc_state->vrr_infopacket.valid);
|
||||
}
|
||||
|
||||
/* Tests for dm_enable_per_frame_crtc_master_sync() */
|
||||
|
||||
/**
|
||||
|
|
@ -1818,18 +1422,6 @@ static struct kunit_case amdgpu_dm_tests[] = {
|
|||
KUNIT_CASE(dm_test_scaling_state_underscan_enabled),
|
||||
KUNIT_CASE(dm_test_scaling_state_underscan_disabled),
|
||||
KUNIT_CASE(dm_test_scaling_state_underscan_border_changed),
|
||||
/* is_timing_unchanged_for_freesync */
|
||||
KUNIT_CASE(dm_test_timing_unchanged_null_args),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_identical_modes),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_vrr_shift),
|
||||
KUNIT_CASE(dm_test_timing_unchanged_clock_changed),
|
||||
/* set_freesync_fixed_config */
|
||||
KUNIT_CASE(dm_test_set_freesync_fixed_config_60hz),
|
||||
/* is_dc_timing_adjust_needed */
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_pending),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_active_fixed),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_vrr_toggle),
|
||||
KUNIT_CASE(dm_test_dc_timing_adjust_not_needed),
|
||||
/* set_multisync_trigger_params */
|
||||
KUNIT_CASE(dm_test_multisync_trigger_disabled),
|
||||
KUNIT_CASE(dm_test_multisync_trigger_rising),
|
||||
|
|
@ -1849,15 +1441,6 @@ static struct kunit_case amdgpu_dm_tests[] = {
|
|||
KUNIT_CASE(dm_test_cp_diff_s3_undesired_to_enabled),
|
||||
KUNIT_CASE(dm_test_cp_diff_desired_to_enabled),
|
||||
KUNIT_CASE(dm_test_cp_diff_desired_to_undesired),
|
||||
/* get_freesync_config_for_crtc */
|
||||
KUNIT_CASE(dm_test_freesync_config_writeback),
|
||||
KUNIT_CASE(dm_test_freesync_config_not_capable),
|
||||
KUNIT_CASE(dm_test_freesync_config_out_of_range),
|
||||
KUNIT_CASE(dm_test_freesync_config_active_variable),
|
||||
KUNIT_CASE(dm_test_freesync_config_inactive),
|
||||
KUNIT_CASE(dm_test_freesync_config_active_fixed),
|
||||
/* reset_freesync_config_for_crtc */
|
||||
KUNIT_CASE(dm_test_reset_freesync_config),
|
||||
/* dm_enable_per_frame_crtc_master_sync */
|
||||
KUNIT_CASE(dm_test_per_frame_master_sync_single_stream),
|
||||
KUNIT_CASE(dm_test_per_frame_master_sync_two_streams),
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user