On 2018-10-11 04:56 PM, Kazlauskas, Nicholas wrote: > On 10/11/2018 04:39 PM, Harry Wentland wrote: >> On 2018-10-11 12:39 PM, Nicholas Kazlauskas wrote: >>> Support for AMDGPU specific FreeSync properties and ioctls are dropped >>> from amdgpu_dm in favor of supporting drm variable refresh rate >>> properties. >>> >>> The drm vrr_capable property is now attached to any DP/HDMI connector. >>> Its value is updated accordingly to the connector's FreeSync capabiltiy. >>> >>> The freesync_enable logic and ioctl control has has been dropped in >>> favor of utilizing the vrr_enabled on the drm CRTC. This allows for more >>> fine grained atomic control over which CRTCs should support variable >>> refresh rate. >>> >>> To handle state changes for vrr_enabled it was easiest to drop the >>> forced modeset on freesync_enabled change. This patch now performs the >>> required stream updates when planes are flipped. >>> >>> This is done for a few reasons: >>> >>> (1) VRR stream updates can be done in the fast update path >>> >>> (2) amdgpu_dm_atomic_check would need to be hacked apart to check >>> desired variable refresh state and capability before the CRTC >>> disable pass. >>> >>> (3) Performing VRR stream updates on-flip is needed for enabling BTR >>> support. >>> >>> VRR packets and timing adjustments are now tracked and compared to >>> previous values sent to the hardware. >>> >>> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@xxxxxxx> >>> --- >>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 255 +++++++++--------- >>> .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h | 7 +- >>> 2 files changed, 138 insertions(+), 124 deletions(-) >>> >>> 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 6a2342d72742..d5de4b91e144 100644 >>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c >>> @@ -1802,72 +1802,6 @@ static void dm_bandwidth_update(struct amdgpu_device *adev) >>> /* TODO: implement later */ >>> } >>> -static int amdgpu_notify_freesync(struct drm_device *dev, void *data, >>> - struct drm_file *filp) >>> -{ >>> - struct drm_atomic_state *state; >>> - struct drm_modeset_acquire_ctx ctx; >>> - struct drm_crtc *crtc; >>> - struct drm_connector *connector; >>> - struct drm_connector_state *old_con_state, *new_con_state; >>> - int ret = 0; >>> - uint8_t i; >>> - bool enable = false; >>> - >>> - drm_modeset_acquire_init(&ctx, 0); >>> - >>> - state = drm_atomic_state_alloc(dev); >>> - if (!state) { >>> - ret = -ENOMEM; >>> - goto out; >>> - } >>> - state->acquire_ctx = &ctx; >>> - >>> -retry: >>> - drm_for_each_crtc(crtc, dev) { >>> - ret = drm_atomic_add_affected_connectors(state, crtc); >>> - if (ret) >>> - goto fail; >>> - >>> - /* TODO rework amdgpu_dm_commit_planes so we don't need this */ >>> - ret = drm_atomic_add_affected_planes(state, crtc); >>> - if (ret) >>> - goto fail; >>> - } >>> - >>> - for_each_oldnew_connector_in_state(state, connector, old_con_state, new_con_state, i) { >>> - struct dm_connector_state *dm_new_con_state = to_dm_connector_state(new_con_state); >>> - struct drm_crtc_state *new_crtc_state; >>> - struct amdgpu_crtc *acrtc = to_amdgpu_crtc(dm_new_con_state->base.crtc); >>> - struct dm_crtc_state *dm_new_crtc_state; >>> - >>> - if (!acrtc) { >>> - ASSERT(0); >>> - continue; >>> - } >>> - >>> - new_crtc_state = drm_atomic_get_new_crtc_state(state, &acrtc->base); >>> - dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); >>> - >>> - dm_new_crtc_state->freesync_enabled = enable; >>> - } >>> - >>> - ret = drm_atomic_commit(state); >>> - >>> -fail: >>> - if (ret == -EDEADLK) { >>> - drm_atomic_state_clear(state); >>> - drm_modeset_backoff(&ctx); >>> - goto retry; >>> - } >>> - >>> - drm_atomic_state_put(state); >>> - >>> -out: >>> - drm_modeset_drop_locks(&ctx); >>> - drm_modeset_acquire_fini(&ctx); >>> - return ret; >>> -} >>> static const struct amdgpu_display_funcs dm_display_funcs = { >>> .bandwidth_update = dm_bandwidth_update, /* called unconditionally */ >>> @@ -1881,7 +1815,6 @@ static const struct amdgpu_display_funcs dm_display_funcs = { >>> dm_crtc_get_scanoutpos,/* called unconditionally */ >>> .add_encoder = NULL, /* VBIOS parsing. DAL does it. */ >>> .add_connector = NULL, /* VBIOS parsing. DAL does it. */ >>> - .notify_freesync = amdgpu_notify_freesync, >> >> Please also drop from amdgpu_display_funcs definition in amdgpu_mode.h. Might want to drop the set_freesync_property from there as well. > > Oh right, I forgot about those. Will do. > >> >>> }; >>> @@ -2834,7 +2767,8 @@ dm_crtc_duplicate_state(struct drm_crtc *crtc) >>> state->adjust = cur->adjust; >>> state->vrr_infopacket = cur->vrr_infopacket; >>> - state->freesync_enabled = cur->freesync_enabled; >>> + state->vrr_supported = cur->vrr_supported; >>> + state->freesync_config = cur->freesync_config; >>> /* TODO Duplicate dc_stream after objects are stream object is flattened */ >>> @@ -3053,8 +2987,6 @@ amdgpu_dm_connector_atomic_duplicate_state(struct drm_connector *connector) >>> __drm_atomic_helper_connector_duplicate_state(connector, &new_state->base); >>> new_state->freesync_capable = state->freesync_capable; >>> - new_state->freesync_enable = state->freesync_enable; >>> - >>> return &new_state->base; >>> } >>> @@ -3800,6 +3732,11 @@ void amdgpu_dm_connector_init_helper(struct amdgpu_display_manager *dm, >>> adev->mode_info.underscan_vborder_property, >>> 0); >>> + if (connector_type == DRM_MODE_CONNECTOR_HDMIA || >>> + connector_type == DRM_MODE_CONNECTOR_DisplayPort) { >>> + drm_connector_attach_vrr_capable_property( >>> + &aconnector->base); >>> + } >>> } >>> static int amdgpu_dm_i2c_xfer(struct i2c_adapter *i2c_adap, >>> @@ -4176,6 +4113,77 @@ 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 mod_vrr_params vrr = {0}; >>> + struct dc_info_packet vrr_infopacket = {0}; >>> + struct mod_freesync_config config = new_crtc_state->freesync_config; >>> + >>> + 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; >>> + >>> + if (new_crtc_state->vrr_supported && >>> + config.min_refresh_in_uhz && >>> + config.max_refresh_in_uhz) { >>> + 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); >>> + >>> + mod_freesync_build_vrr_infopacket( >>> + dm->freesync_module, >>> + new_stream, >>> + &vrr, >>> + packet_type_vrr, >>> + transfer_func_unknown, >>> + &vrr_infopacket); >>> + >>> + new_crtc_state->freesync_timing_changed = >>> + (memcmp(&new_crtc_state->adjust, >>> + &vrr.adjust, >>> + sizeof(vrr.adjust)) != 0); >>> + >>> + new_crtc_state->freesync_vrr_info_changed = >>> + (memcmp(&new_crtc_state->vrr_infopacket, >>> + &vrr_infopacket, >>> + sizeof(vrr_infopacket)) != 0); >>> + >>> + new_crtc_state->adjust = vrr.adjust; >>> + new_crtc_state->vrr_infopacket = vrr_infopacket; >>> + >>> + new_stream->adjust = new_crtc_state->adjust; >>> + new_stream->vrr_infopacket = vrr_infopacket; >>> + >>> + if (new_crtc_state->freesync_vrr_info_changed) >>> + DRM_DEBUG_KMS("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.state); >>> + >>> + if (new_crtc_state->freesync_timing_changed) >>> + DRM_DEBUG_KMS("VRR timing update: crtc=%u min=%u max=%u\n", >>> + new_crtc_state->base.crtc->base.id, >>> + vrr.adjust.v_total_min, >>> + vrr.adjust.v_total_max); >>> +} >>> + >>> /* >>> * Executes flip >>> * >>> @@ -4197,6 +4205,7 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, >>> struct dc_flip_addrs addr = { {0} }; >>> /* TODO eliminate or rename surface_update */ >>> struct dc_surface_update surface_updates[1] = { {0} }; >>> + struct dc_stream_update stream_update = {0}; >>> struct dm_crtc_state *acrtc_state = to_dm_crtc_state(crtc->state); >>> struct dc_stream_status *stream_status; >>> @@ -4269,11 +4278,26 @@ static void amdgpu_dm_do_flip(struct drm_crtc *crtc, >>> } >>> surface_updates->flip_addr = &addr; >>> + if (acrtc_state->stream) { >>> + update_freesync_state_on_stream( >>> + &adev->dm, >>> + acrtc_state, >>> + acrtc_state->stream); >>> + >>> + if (acrtc_state->freesync_timing_changed) >>> + stream_update.adjust = >>> + &acrtc_state->stream->adjust; >>> + >>> + if (acrtc_state->freesync_vrr_info_changed) >>> + stream_update.vrr_infopacket = >>> + &acrtc_state->stream->vrr_infopacket; >>> + } >>> + >> >> For consistency we might also want to do this in commit_planes_to_stream before the call to dc_commit_updates_for_stream. >> >> We should really merge the two codepaths for dc_commit_updates_for_stream one of these days. > > In a prior revision to this patch I actually did do this on both but reduced it to just the flip - the reason being that there's no point in enabling this when we're *not* flipping since it's needed for this to function properly. > > The merge is probably a good idea down the line to cut down on code duplication even further. > Sounds good. Harry >> >>> dc_commit_updates_for_stream(adev->dm.dc, >>> surface_updates, >>> 1, >>> acrtc_state->stream, >>> - NULL, >>> + &stream_update, >>> &surface_updates->surface, >>> state); >>> @@ -4333,11 +4357,6 @@ static bool commit_planes_to_stream( >>> stream_update->dst = dc_stream->dst; >>> stream_update->out_transfer_func = dc_stream->out_transfer_func; >>> - if (dm_new_crtc_state->freesync_enabled != dm_old_crtc_state->freesync_enabled) { >>> - stream_update->vrr_infopacket = &dc_stream->vrr_infopacket; >>> - stream_update->adjust = &dc_stream->adjust; >>> - } >>> - >>> for (i = 0; i < new_plane_count; i++) { >>> updates[i].surface = plane_states[i]; >>> updates[i].gamma = >>> @@ -4473,9 +4492,6 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state, >>> spin_unlock_irqrestore(&pcrtc->dev->event_lock, flags); >>> } >>> - dc_stream_attach->adjust = acrtc_state->adjust; >>> - dc_stream_attach->vrr_infopacket = acrtc_state->vrr_infopacket; >>> - >>> if (false == commit_planes_to_stream(dm->dc, >>> plane_states_constructed, >>> planes_count, >>> @@ -4679,9 +4695,6 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state) >>> WARN_ON(!status); >>> WARN_ON(!status->plane_count); >>> - dm_new_crtc_state->stream->adjust = dm_new_crtc_state->adjust; >>> - dm_new_crtc_state->stream->vrr_infopacket = dm_new_crtc_state->vrr_infopacket; >>> - >>> /*TODO How it works with MPO ?*/ >>> if (!commit_planes_to_stream( >>> dm->dc, >>> @@ -4899,20 +4912,18 @@ static int do_aquire_global_lock(struct drm_device *dev, >>> return ret < 0 ? ret : 0; >>> } >>> -void set_freesync_on_stream(struct amdgpu_display_manager *dm, >>> - struct dm_crtc_state *new_crtc_state, >>> - struct dm_connector_state *new_con_state, >>> - struct dc_stream_state *new_stream) >>> +static 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 mod_vrr_params vrr = {0}; >>> - struct dc_info_packet vrr_infopacket = {0}; >>> struct amdgpu_dm_connector *aconnector = >>> to_amdgpu_dm_connector(new_con_state->base.connector); >>> - if (new_con_state->freesync_capable && >>> - new_con_state->freesync_enable) { >>> - config.state = new_crtc_state->freesync_enabled ? >>> + new_crtc_state->vrr_supported = new_con_state->freesync_capable; >>> + >>> + if (new_con_state->freesync_capable) { >>> + config.state = new_crtc_state->base.vrr_enabled ? >>> VRR_STATE_ACTIVE_VARIABLE : >>> VRR_STATE_INACTIVE; >>> config.min_refresh_in_uhz = >>> @@ -4922,19 +4933,18 @@ void set_freesync_on_stream(struct amdgpu_display_manager *dm, >>> config.vsif_supported = true; >>> } >>> - mod_freesync_build_vrr_params(dm->freesync_module, >>> - new_stream, >>> - &config, &vrr); >>> + new_crtc_state->freesync_config = config; >>> +} >>> - mod_freesync_build_vrr_infopacket(dm->freesync_module, >>> - new_stream, >>> - &vrr, >>> - packet_type_fs1, >>> - NULL, >>> - &vrr_infopacket); >>> +static void reset_freesync_config_for_crtc( >>> + struct dm_crtc_state *new_crtc_state) >>> +{ >>> + new_crtc_state->vrr_supported = false; >>> - new_crtc_state->adjust = vrr.adjust; >>> - new_crtc_state->vrr_infopacket = vrr_infopacket; >>> + memset(&new_crtc_state->adjust, 0, >>> + sizeof(new_crtc_state->adjust)); >>> + memset(&new_crtc_state->vrr_infopacket, 0, >>> + sizeof(new_crtc_state->vrr_infopacket)); >>> } >>> static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, >>> @@ -5009,9 +5019,6 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, >>> break; >>> } >>> - set_freesync_on_stream(dm, dm_new_crtc_state, >>> - dm_new_conn_state, new_stream); >>> - >>> if (dc_is_stream_unchanged(new_stream, dm_old_crtc_state->stream) && >>> dc_is_stream_scaling_unchanged(new_stream, dm_old_crtc_state->stream)) { >>> new_crtc_state->mode_changed = false; >>> @@ -5020,9 +5027,6 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, >>> } >>> } >>> - if (dm_old_crtc_state->freesync_enabled != dm_new_crtc_state->freesync_enabled) >>> - new_crtc_state->mode_changed = true; >>> - >>> if (!drm_atomic_crtc_needs_modeset(new_crtc_state)) >>> goto next_crtc; >>> @@ -5059,6 +5063,8 @@ static int dm_update_crtcs_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); >>> + >>> *lock_and_validation_needed = true; >>> } else {/* Add stream for any updated/enabled CRTC */ >>> @@ -5136,7 +5142,9 @@ static int dm_update_crtcs_state(struct amdgpu_display_manager *dm, >>> amdgpu_dm_set_ctm(dm_new_crtc_state); >>> } >>> - >>> + /* Update Freesync settings. */ >>> + get_freesync_config_for_crtc(dm_new_crtc_state, >>> + dm_new_conn_state); >>> } >>> return ret; >>> @@ -5401,12 +5409,9 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev, >>> goto fail; >>> for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) { >>> - struct dm_crtc_state *dm_new_crtc_state = to_dm_crtc_state(new_crtc_state); >>> - struct dm_crtc_state *dm_old_crtc_state = to_dm_crtc_state(old_crtc_state); >>> - >>> if (!drm_atomic_crtc_needs_modeset(new_crtc_state) && >>> !new_crtc_state->color_mgmt_changed && >>> - (dm_old_crtc_state->freesync_enabled == dm_new_crtc_state->freesync_enabled)) >>> + !new_crtc_state->vrr_enabled) >>> continue; >>> if (!new_crtc_state->enable) >>> @@ -5558,14 +5563,15 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, >>> struct detailed_data_monitor_range *range; >>> struct amdgpu_dm_connector *amdgpu_dm_connector = >>> to_amdgpu_dm_connector(connector); >>> - struct dm_connector_state *dm_con_state; >>> + struct dm_connector_state *dm_con_state = NULL; >>> struct drm_device *dev = connector->dev; >>> struct amdgpu_device *adev = dev->dev_private; >>> + bool freesync_capable = false; >>> if (!connector->state) { >>> DRM_ERROR("%s - Connector has no state", __func__); >>> - return; >>> + goto update; >>> } >>> if (!edid) { >>> @@ -5575,9 +5581,7 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, >>> amdgpu_dm_connector->max_vfreq = 0; >>> amdgpu_dm_connector->pixel_clock_mhz = 0; >>> - dm_con_state->freesync_capable = false; >>> - dm_con_state->freesync_enable = false; >>> - return; >>> + goto update; >>> } >>> dm_con_state = to_dm_connector_state(connector->state); >>> @@ -5585,10 +5589,10 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, >>> edid_check_required = false; >>> if (!amdgpu_dm_connector->dc_sink) { >>> DRM_ERROR("dc_sink NULL, could not add free_sync module.\n"); >>> - return; >>> + goto update; >>> } >>> if (!adev->dm.freesync_module) >>> - return; >>> + goto update; >>> /* >>> * if edid non zero restrict freesync only for dp and edp >>> */ >>> @@ -5600,7 +5604,6 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, >>> amdgpu_dm_connector); >>> } >>> } >>> - dm_con_state->freesync_capable = false; >>> if (edid_check_required == true && (edid->version > 1 || >>> (edid->version == 1 && edid->revision > 1))) { >>> for (i = 0; i < 4; i++) { >>> @@ -5632,8 +5635,16 @@ void amdgpu_dm_update_freesync_caps(struct drm_connector *connector, >>> if (amdgpu_dm_connector->max_vfreq - >>> amdgpu_dm_connector->min_vfreq > 10) { >>> - dm_con_state->freesync_capable = true; >>> + freesync_capable = true; >>> } >>> } >>> + >>> +update: >>> + if (dm_con_state) >>> + dm_con_state->freesync_capable = freesync_capable; >>> + >> >> Interesting. Looks like we could just grab this from the drm_connector property as this isn't something that changes with the state but DRM forces us to track it on the connector state as drm_object_property_get_value() throws a WARN_ON for atomic drivers. Not sure I like it but it's what we got, I guess. >> >> Harry > > That was my original plan, but I think I understand the reasoning behind the separation of state and property. > > I don't mind this approach too much because the value really feels like an implementation detail specific to our driver in this case. > > It's not really describing whether the connector is actually capable or not, but whether it's fine to perform vrr updates later when we're updating the planes. > >> >>> + if (connector->vrr_capable_property) >>> + drm_connector_set_vrr_capable_property(connector, >>> + freesync_capable); >>> } >>> 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 978b34a5011c..a5aaf8b08968 100644 >>> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h >>> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.h >>> @@ -185,7 +185,11 @@ struct dm_crtc_state { >>> int crc_skip_count; >>> bool crc_enabled; >>> - bool freesync_enabled; >>> + bool freesync_timing_changed; >>> + bool freesync_vrr_info_changed; >>> + >>> + bool vrr_supported; >>> + struct mod_freesync_config freesync_config; >>> struct dc_crtc_timing_adjust adjust; >>> struct dc_info_packet vrr_infopacket; >>> }; >>> @@ -207,7 +211,6 @@ struct dm_connector_state { >>> uint8_t underscan_vborder; >>> uint8_t underscan_hborder; >>> bool underscan_enable; >>> - bool freesync_enable; >>> bool freesync_capable; >>> }; >>> > > Nicholas Kazlauskas _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel