|
@@ -1155,8 +1155,8 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
|
|
rc = dp_display_process_hpd_low(dp);
|
|
rc = dp_display_process_hpd_low(dp);
|
|
if (rc) {
|
|
if (rc) {
|
|
/* cancel any pending request */
|
|
/* cancel any pending request */
|
|
- dp->ctrl->abort(dp->ctrl);
|
|
|
|
- dp->aux->abort(dp->aux);
|
|
|
|
|
|
+ dp->ctrl->abort(dp->ctrl, true);
|
|
|
|
+ dp->aux->abort(dp->aux, true);
|
|
}
|
|
}
|
|
|
|
|
|
mutex_lock(&dp->session_lock);
|
|
mutex_lock(&dp->session_lock);
|
|
@@ -1177,8 +1177,8 @@ static void dp_display_disconnect_sync(struct dp_display_private *dp)
|
|
/* cancel any pending request */
|
|
/* cancel any pending request */
|
|
dp_display_state_add(DP_STATE_ABORTED);
|
|
dp_display_state_add(DP_STATE_ABORTED);
|
|
|
|
|
|
- dp->ctrl->abort(dp->ctrl);
|
|
|
|
- dp->aux->abort(dp->aux);
|
|
|
|
|
|
+ dp->ctrl->abort(dp->ctrl, true);
|
|
|
|
+ dp->aux->abort(dp->aux, true);
|
|
|
|
|
|
/* wait for idle state */
|
|
/* wait for idle state */
|
|
cancel_work_sync(&dp->connect_work);
|
|
cancel_work_sync(&dp->connect_work);
|
|
@@ -3104,9 +3104,25 @@ static int dp_pm_prepare(struct device *dev)
|
|
struct dp_display_private *dp = container_of(g_dp_display,
|
|
struct dp_display_private *dp = container_of(g_dp_display,
|
|
struct dp_display_private, dp_display);
|
|
struct dp_display_private, dp_display);
|
|
|
|
|
|
|
|
+ mutex_lock(&dp->session_lock);
|
|
dp_display_set_mst_state(g_dp_display, PM_SUSPEND);
|
|
dp_display_set_mst_state(g_dp_display, PM_SUSPEND);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * There are a few instances where the DP is hotplugged when the device
|
|
|
|
+ * is in PM suspend state. After hotplug, it is observed the device
|
|
|
|
+ * enters and exits the PM suspend multiple times while aux transactions
|
|
|
|
+ * are taking place. This may sometimes cause an unclocked register
|
|
|
|
+ * access error. So, abort aux transactions when such a situation
|
|
|
|
+ * arises i.e. when DP is connected but display not enabled yet.
|
|
|
|
+ */
|
|
|
|
+ if (dp_display_state_is(DP_STATE_CONNECTED) &&
|
|
|
|
+ !dp_display_state_is(DP_STATE_ENABLED)) {
|
|
|
|
+ dp->aux->abort(dp->aux, true);
|
|
|
|
+ dp->ctrl->abort(dp->ctrl, true);
|
|
|
|
+ }
|
|
|
|
+
|
|
dp_display_state_add(DP_STATE_SUSPENDED);
|
|
dp_display_state_add(DP_STATE_SUSPENDED);
|
|
|
|
+ mutex_unlock(&dp->session_lock);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -3116,9 +3132,25 @@ static void dp_pm_complete(struct device *dev)
|
|
struct dp_display_private *dp = container_of(g_dp_display,
|
|
struct dp_display_private *dp = container_of(g_dp_display,
|
|
struct dp_display_private, dp_display);
|
|
struct dp_display_private, dp_display);
|
|
|
|
|
|
|
|
+ mutex_lock(&dp->session_lock);
|
|
dp_display_set_mst_state(g_dp_display, PM_DEFAULT);
|
|
dp_display_set_mst_state(g_dp_display, PM_DEFAULT);
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * There are multiple PM suspend entry and exits observed before
|
|
|
|
+ * the connect uevent is issued to userspace. The aux transactions are
|
|
|
|
+ * aborted during PM suspend entry in dp_pm_prepare to prevent unclocked
|
|
|
|
+ * register access. On PM suspend exit, there will be no host_init call
|
|
|
|
+ * to reset the abort flags for ctrl and aux incase DP is connected
|
|
|
|
+ * but display not enabled. So, resetting abort flags for aux and ctrl.
|
|
|
|
+ */
|
|
|
|
+ if (dp_display_state_is(DP_STATE_CONNECTED) &&
|
|
|
|
+ !dp_display_state_is(DP_STATE_ENABLED)) {
|
|
|
|
+ dp->aux->abort(dp->aux, false);
|
|
|
|
+ dp->ctrl->abort(dp->ctrl, false);
|
|
|
|
+ }
|
|
|
|
+
|
|
dp_display_state_remove(DP_STATE_SUSPENDED);
|
|
dp_display_state_remove(DP_STATE_SUSPENDED);
|
|
|
|
+ mutex_unlock(&dp->session_lock);
|
|
}
|
|
}
|
|
|
|
|
|
static const struct dev_pm_ops dp_pm_ops = {
|
|
static const struct dev_pm_ops dp_pm_ops = {
|