diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0883-drm-amd-dal-add-logic-to-handle-hw-and-sw-state-inco.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0883-drm-amd-dal-add-logic-to-handle-hw-and-sw-state-inco.patch | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0883-drm-amd-dal-add-logic-to-handle-hw-and-sw-state-inco.patch b/common/recipes-kernel/linux/files/0883-drm-amd-dal-add-logic-to-handle-hw-and-sw-state-inco.patch new file mode 100644 index 00000000..98146592 --- /dev/null +++ b/common/recipes-kernel/linux/files/0883-drm-amd-dal-add-logic-to-handle-hw-and-sw-state-inco.patch @@ -0,0 +1,279 @@ +From 5a1c2aeefdef4941aedb5f719f159d6b16fb8b49 Mon Sep 17 00:00:00 2001 +From: Eric Yang <eric.yang2@amd.com> +Date: Fri, 4 Mar 2016 14:34:46 -0500 +Subject: [PATCH 0883/1110] drm/amd/dal: add logic to handle hw and sw state + inconsitency + +Signed-off-by: Eric Yang <eric.yang2@amd.com> +Acked-by: Harry Wentland <harry.wentland@amd.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm.c | 6 + + .../gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c | 162 ++++++++++++--------- + .../gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.h | 2 + + 3 files changed, 103 insertions(+), 67 deletions(-) + +diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm.c b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm.c +index c12ef99..a9973ed 100644 +--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm.c ++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm.c +@@ -697,8 +697,14 @@ static void handle_hpd_irq(void *param) + */ + if (dc_link_detect(aconnector->dc_link, false)) { + amdgpu_dm_update_connector_after_detect(aconnector); ++ ++ drm_modeset_lock_all(dev); ++ dm_restore_drm_connector_state(dev, connector); ++ drm_modeset_unlock_all(dev); ++ + drm_kms_helper_hotplug_event(dev); + } ++ + } + + static void handle_hpd_rx_irq(void *param) +diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c +index ca553ce..dcffffe 100644 +--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c ++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.c +@@ -884,15 +884,20 @@ static struct dc_target *create_target_for_sink( + &aconnector->base.modes, + struct drm_display_mode, + head); ++ + if (NULL == preferred_mode) { +- DRM_ERROR("No preferred mode found\n"); +- goto stream_create_fail; ++ /* This may not be an error, the use case is when we we have no ++ * usermode calls to reset and set mode upon hotplug. In this ++ * case, we call set mode ourselves to restore the previous mode ++ * and the modelist may not be filled in in time. ++ */ ++ DRM_INFO("No preferred mode found\n"); ++ } else { ++ decide_crtc_timing_for_drm_display_mode( ++ &mode, preferred_mode, ++ dm_state->scaling != RMX_OFF); + } + +- decide_crtc_timing_for_drm_display_mode( +- &mode, preferred_mode, +- dm_state->scaling != RMX_OFF); +- + dc_timing_from_drm_display_mode(&stream->timing, + &mode, &aconnector->base); + +@@ -2004,6 +2009,15 @@ static enum dm_commit_action get_dm_commit_action(struct drm_crtc_state *state) + { + /* mode changed means either actually mode changed or enabled changed */ + /* active changed means dpms changed */ ++ ++ DRM_DEBUG_KMS("crtc_state_flags: enable:%d, active:%d, planes_changed:%d, mode_changed:%d,active_changed:%d,connectors_changed:%d\n", ++ state->enable, ++ state->active, ++ state->planes_changed, ++ state->mode_changed, ++ state->active_changed, ++ state->connectors_changed); ++ + if (state->mode_changed) { + /* if it is got disabled - call reset mode */ + if (!state->enable) +@@ -2020,6 +2034,9 @@ static enum dm_commit_action get_dm_commit_action(struct drm_crtc_state *state) + if (!state->enable) + return DM_COMMIT_ACTION_NOTHING; + ++ if (state->active && state->connectors_changed) ++ return DM_COMMIT_ACTION_SET; ++ + if (state->active_changed) { + if (state->active) { + return DM_COMMIT_ACTION_DPMS_ON; +@@ -2089,64 +2106,6 @@ static void manage_dm_interrupts( + } + } + +-/* +- * Handle headless hotplug workaround +- * +- * In case of headless hotplug, if plugging the same monitor to the same +- * DDI, DRM consider it as mode unchanged. We should check whether the +- * sink pointer changed, and set mode_changed properly to +- * make sure commit is doing everything. +- */ +-static void handle_headless_hotplug( +- const struct amdgpu_crtc *acrtc, +- struct drm_crtc_state *state, +- struct amdgpu_connector **aconnector) +-{ +- struct amdgpu_connector *old_connector = +- aconnector_from_drm_crtc_id(&acrtc->base); +- +- /* +- * TODO Revisit this. This code is kinda hacky and might break things. +- */ +- +- if (!old_connector) +- return; +- +- if (!*aconnector) +- *aconnector = old_connector; +- +- if (acrtc->target && (*aconnector)->dc_sink) { +- if ((*aconnector)->dc_sink != +- acrtc->target->streams[0]->sink) { +- state->mode_changed = true; +- } +- } +- +- if (!acrtc->target) { +- /* In case of headless with DPMS on, when system waked up, +- * if no monitor connected, target is null and will not create +- * new target, on that condition, we should check +- * if any connector is connected, if connected, +- * it means a hot plug happened after wake up, +- * mode_changed should be set to true to make sure +- * commit targets will do everything. +- */ +- state->mode_changed = +- (*aconnector)->base.status == +- connector_status_connected; +- } else { +- /* In case of headless hotplug, if plug same monitor to same +- * DDI, DRM consider it as mode unchanged, we should check +- * sink pointer changed, and set mode changed properly to +- * make sure commit doing everything. +- */ +- /* check if sink has changed from last commit */ +- if ((*aconnector)->dc_sink && (*aconnector)->dc_sink != +- acrtc->target->streams[0]->sink) +- state->mode_changed = true; +- } +-} +- + int amdgpu_dm_atomic_commit( + struct drm_device *dev, + struct drm_atomic_state *state, +@@ -2217,7 +2176,6 @@ int amdgpu_dm_atomic_commit( + /* handles headless hotplug case, updating new_state and + * aconnector as needed + */ +- handle_headless_hotplug(acrtc, new_state, &aconnector); + + action = get_dm_commit_action(new_state); + +@@ -2229,7 +2187,7 @@ int amdgpu_dm_atomic_commit( + aconnector, + &crtc->state->mode); + +- DRM_DEBUG_KMS("Atomic commit: SET.\n"); ++ DRM_INFO("Atomic commit: SET.\n"); + + if (!new_target) { + /* +@@ -2275,11 +2233,12 @@ int amdgpu_dm_atomic_commit( + } + + case DM_COMMIT_ACTION_NOTHING: ++ DRM_DEBUG_KMS("Atomic commit: Nothing.\n"); + break; + + case DM_COMMIT_ACTION_DPMS_OFF: + case DM_COMMIT_ACTION_RESET: +- DRM_DEBUG_KMS("Atomic commit: RESET.\n"); ++ DRM_INFO("Atomic commit: RESET.\n"); + /* i.e. reset mode */ + if (acrtc->target) { + manage_dm_interrupts(adev, acrtc, false); +@@ -2399,6 +2358,75 @@ int amdgpu_dm_atomic_commit( + + return 0; + } ++/* ++ * This functions handle all cases when set mode does not come upon hotplug. ++ * This include when the same display is unplugged then plugged back into the ++ * same port and when we are running without usermode desktop manager supprot ++ */ ++void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector) ++{ ++ struct drm_crtc *crtc; ++ struct amdgpu_device *adev = dev->dev_private; ++ struct dc *dc = adev->dm.dc; ++ struct amdgpu_connector *aconnector = to_amdgpu_connector(connector); ++ struct amdgpu_crtc *disconnected_acrtc = to_amdgpu_crtc(connector->state->crtc); ++ const struct dc_sink *sink; ++ struct dc_target *commit_targets[6]; ++ uint32_t commit_targets_count = 0; ++ ++ if (!aconnector->dc_sink || !connector->state || !connector->state->crtc) ++ return; ++ ++ if (!disconnected_acrtc->target) ++ return; ++ ++ sink = disconnected_acrtc->target->streams[0]->sink; ++ ++ /* ++ * If the previous sink is not released and different from the current, ++ * we deduce we are in a state where we can not rely on usermode call ++ * to turn on the display, so we do it here ++ */ ++ if (sink != aconnector->dc_sink) { ++ struct dc_target *new_target = ++ create_target_for_sink( ++ aconnector, ++ &disconnected_acrtc->base.state->mode); ++ /* ++ * we evade vblanks and pflips on crtc that ++ * should be changed ++ */ ++ manage_dm_interrupts(adev, disconnected_acrtc, false); ++ /* this is the update mode case */ ++ dc_target_release(disconnected_acrtc->target); ++ ++ disconnected_acrtc->target = new_target; ++ disconnected_acrtc->enabled = true; ++ disconnected_acrtc->hw_mode = disconnected_acrtc->base.state->mode; ++ ++ commit_targets_count = 0; ++ ++ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) { ++ struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc); ++ ++ if (acrtc->target) { ++ commit_targets[commit_targets_count] = acrtc->target; ++ ++commit_targets_count; ++ } ++ } ++ ++ /* DC is optimized not to do anything if 'targets' didn't change. */ ++ dc_commit_targets(dc, commit_targets, commit_targets_count); ++ ++ dm_dc_surface_commit(dc, &disconnected_acrtc->base, ++ to_dm_connector_state( ++ connector->state)); ++ ++ manage_dm_interrupts(adev, disconnected_acrtc, true); ++ dm_crtc_cursor_reset(&disconnected_acrtc->base); ++ ++ } ++} + + static uint32_t add_val_sets_surface( + struct dc_validation_set *val_sets, +diff --git a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.h b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.h +index 2cf7cd2..8f65194 100644 +--- a/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.h ++++ b/drivers/gpu/drm/amd/dal/amdgpu_dm/amdgpu_dm_types.h +@@ -94,6 +94,8 @@ int amdgpu_dm_connector_mode_valid( + struct drm_connector *connector, + struct drm_display_mode *mode); + ++void dm_restore_drm_connector_state(struct drm_device *dev, struct drm_connector *connector); ++ + extern const struct drm_encoder_helper_funcs amdgpu_dm_encoder_helper_funcs; + + #endif /* __AMDGPU_DM_TYPES_H__ */ +-- +2.7.4 + |