From: Alex Hung <[email protected]> [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 <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: Fangzhi Zuo <[email protected]> Tested-by: Dan Wheeler <[email protected]> --- .../gpu/drm/amd/display/amdgpu_dm/Makefile | 3 +- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 349 +------------- .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 8 - .../display/amdgpu_dm/amdgpu_dm_freesync.c | 362 ++++++++++++++ .../display/amdgpu_dm/amdgpu_dm_freesync.h | 65 +++ .../drm/amd/display/amdgpu_dm/tests/Makefile | 1 + .../amdgpu_dm/tests/amdgpu_dm_freesync_test.c | 453 ++++++++++++++++++ .../display/amdgpu_dm/tests/amdgpu_dm_test.c | 417 ---------------- 8 files changed, 894 insertions(+), 764 deletions(-) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile index d83878e35b61..5cb8c143e72f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/Makefile @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c index dfc16f5e415a..c36eb8a1d2d1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c @@ -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, @@ -5344,7 +5119,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); @@ -5544,108 +5319,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, @@ -5742,7 +5415,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 && @@ -5784,14 +5457,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 && @@ -5801,7 +5474,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); @@ -5823,7 +5496,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; @@ -5911,7 +5584,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; diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h index 70220997cde9..1ef92a28e3e9 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h @@ -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, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c new file mode 100644 index 000000000000..7e484adb4120 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.c @@ -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); + } + } +} diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h new file mode 100644 index 000000000000..24c410306284 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_freesync.h @@ -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__ */ diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index 1592e8dae1a9..e58ffc4dcd84 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile @@ -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 diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c new file mode 100644 index 000000000000..0ae636dcbbe4 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_freesync_test.c @@ -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"); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c index 49a1d2ae5588..428d24259198 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_test.c @@ -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), -- 2.53.0
