|
|
|
@ -108,14 +108,12 @@ struct dp_display_private {
|
|
|
|
|
/* event related only access by event thread */
|
|
|
|
|
struct mutex event_mutex;
|
|
|
|
|
wait_queue_head_t event_q;
|
|
|
|
|
atomic_t hpd_state;
|
|
|
|
|
u32 hpd_state;
|
|
|
|
|
u32 event_pndx;
|
|
|
|
|
u32 event_gndx;
|
|
|
|
|
struct dp_event event_list[DP_EVENT_Q_MAX];
|
|
|
|
|
spinlock_t event_lock;
|
|
|
|
|
|
|
|
|
|
struct completion resume_comp;
|
|
|
|
|
|
|
|
|
|
struct dp_audio *audio;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
@ -367,6 +365,20 @@ static void dp_display_host_init(struct dp_display_private *dp)
|
|
|
|
|
dp->core_initialized = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void dp_display_host_deinit(struct dp_display_private *dp)
|
|
|
|
|
{
|
|
|
|
|
if (!dp->core_initialized) {
|
|
|
|
|
DRM_DEBUG_DP("DP core not initialized\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dp_ctrl_host_deinit(dp->ctrl);
|
|
|
|
|
dp_aux_deinit(dp->aux);
|
|
|
|
|
dp_power_deinit(dp->power);
|
|
|
|
|
|
|
|
|
|
dp->core_initialized = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dp_display_usbpd_configure_cb(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
@ -491,7 +503,7 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp->hpd_state);
|
|
|
|
|
state = dp->hpd_state;
|
|
|
|
|
if (state == ST_SUSPEND_PENDING) {
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
|
return 0;
|
|
|
|
@ -509,17 +521,14 @@ static int dp_hpd_plug_handle(struct dp_display_private *dp, u32 data)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (state == ST_SUSPENDED)
|
|
|
|
|
tout = DP_TIMEOUT_NONE;
|
|
|
|
|
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_CONNECT_PENDING);
|
|
|
|
|
dp->hpd_state = ST_CONNECT_PENDING;
|
|
|
|
|
|
|
|
|
|
hpd->hpd_high = 1;
|
|
|
|
|
|
|
|
|
|
ret = dp_display_usbpd_configure_cb(&dp->pdev->dev);
|
|
|
|
|
if (ret) { /* failed */
|
|
|
|
|
hpd->hpd_high = 0;
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_DISCONNECTED);
|
|
|
|
|
dp->hpd_state = ST_DISCONNECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* start sanity checking */
|
|
|
|
@ -540,10 +549,10 @@ static int dp_connect_pending_timeout(struct dp_display_private *dp, u32 data)
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp->hpd_state);
|
|
|
|
|
state = dp->hpd_state;
|
|
|
|
|
if (state == ST_CONNECT_PENDING) {
|
|
|
|
|
dp_display_enable(dp, 0);
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_CONNECTED);
|
|
|
|
|
dp->hpd_state = ST_CONNECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
@ -568,7 +577,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp->hpd_state);
|
|
|
|
|
state = dp->hpd_state;
|
|
|
|
|
if (state == ST_SUSPEND_PENDING) {
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
|
return 0;
|
|
|
|
@ -586,7 +595,7 @@ static int dp_hpd_unplug_handle(struct dp_display_private *dp, u32 data)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_DISCONNECT_PENDING);
|
|
|
|
|
dp->hpd_state = ST_DISCONNECT_PENDING;
|
|
|
|
|
|
|
|
|
|
/* disable HPD plug interrupt until disconnect is done */
|
|
|
|
|
dp_catalog_hpd_config_intr(dp->catalog, DP_DP_HPD_PLUG_INT_MASK
|
|
|
|
@ -621,10 +630,10 @@ static int dp_disconnect_pending_timeout(struct dp_display_private *dp, u32 data
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp->hpd_state);
|
|
|
|
|
state = dp->hpd_state;
|
|
|
|
|
if (state == ST_DISCONNECT_PENDING) {
|
|
|
|
|
dp_display_disable(dp, 0);
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_DISCONNECTED);
|
|
|
|
|
dp->hpd_state = ST_DISCONNECTED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
@ -639,7 +648,7 @@ static int dp_irq_hpd_handle(struct dp_display_private *dp, u32 data)
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
/* irq_hpd can happen at either connected or disconnected state */
|
|
|
|
|
state = atomic_read(&dp->hpd_state);
|
|
|
|
|
state = dp->hpd_state;
|
|
|
|
|
if (state == ST_SUSPEND_PENDING) {
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
|
return 0;
|
|
|
|
@ -790,17 +799,10 @@ static int dp_display_enable(struct dp_display_private *dp, u32 data)
|
|
|
|
|
|
|
|
|
|
dp_display = g_dp_display;
|
|
|
|
|
|
|
|
|
|
if (dp_display->power_on) {
|
|
|
|
|
DRM_DEBUG_DP("Link already setup, return\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = dp_ctrl_on_stream(dp->ctrl);
|
|
|
|
|
if (!rc)
|
|
|
|
|
dp_display->power_on = true;
|
|
|
|
|
|
|
|
|
|
/* complete resume_comp regardless it is armed or not */
|
|
|
|
|
complete(&dp->resume_comp);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -829,9 +831,6 @@ static int dp_display_disable(struct dp_display_private *dp, u32 data)
|
|
|
|
|
|
|
|
|
|
dp_display = g_dp_display;
|
|
|
|
|
|
|
|
|
|
if (!dp_display->power_on)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
/* wait only if audio was enabled */
|
|
|
|
|
if (dp_display->audio_enabled) {
|
|
|
|
|
if (!wait_for_completion_timeout(&dp->audio_comp,
|
|
|
|
@ -1152,9 +1151,6 @@ static int dp_display_probe(struct platform_device *pdev)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_init(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
init_completion(&dp->resume_comp);
|
|
|
|
|
|
|
|
|
|
g_dp_display = &dp->dp_display;
|
|
|
|
|
|
|
|
|
|
/* Store DP audio handle inside DP display */
|
|
|
|
@ -1190,20 +1186,54 @@ static int dp_display_remove(struct platform_device *pdev)
|
|
|
|
|
|
|
|
|
|
static int dp_pm_resume(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
|
|
struct msm_dp *dp_display = platform_get_drvdata(pdev);
|
|
|
|
|
struct dp_display_private *dp;
|
|
|
|
|
u32 status;
|
|
|
|
|
|
|
|
|
|
dp = container_of(dp_display, struct dp_display_private, dp_display);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
/* start from disconnected state */
|
|
|
|
|
dp->hpd_state = ST_DISCONNECTED;
|
|
|
|
|
|
|
|
|
|
/* turn on dp ctrl/phy */
|
|
|
|
|
dp_display_host_init(dp);
|
|
|
|
|
|
|
|
|
|
dp_catalog_ctrl_hpd_config(dp->catalog);
|
|
|
|
|
|
|
|
|
|
status = dp_catalog_hpd_get_state_status(dp->catalog);
|
|
|
|
|
|
|
|
|
|
if (status) {
|
|
|
|
|
dp->dp_display.is_connected = true;
|
|
|
|
|
} else {
|
|
|
|
|
dp->dp_display.is_connected = false;
|
|
|
|
|
/* make sure next resume host_init be called */
|
|
|
|
|
dp->core_initialized = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dp_pm_suspend(struct device *dev)
|
|
|
|
|
{
|
|
|
|
|
struct platform_device *pdev = to_platform_device(dev);
|
|
|
|
|
struct dp_display_private *dp = platform_get_drvdata(pdev);
|
|
|
|
|
struct msm_dp *dp_display = platform_get_drvdata(pdev);
|
|
|
|
|
struct dp_display_private *dp;
|
|
|
|
|
|
|
|
|
|
if (!dp) {
|
|
|
|
|
DRM_ERROR("DP driver bind failed. Invalid driver data\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
dp = container_of(dp_display, struct dp_display_private, dp_display);
|
|
|
|
|
|
|
|
|
|
atomic_set(&dp->hpd_state, ST_SUSPENDED);
|
|
|
|
|
mutex_lock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
if (dp->core_initialized == true)
|
|
|
|
|
dp_display_host_deinit(dp);
|
|
|
|
|
|
|
|
|
|
dp->hpd_state = ST_SUSPENDED;
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp->event_mutex);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -1318,19 +1348,6 @@ int msm_dp_modeset_init(struct msm_dp *dp_display, struct drm_device *dev,
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int dp_display_wait4resume_done(struct dp_display_private *dp)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
reinit_completion(&dp->resume_comp);
|
|
|
|
|
if (!wait_for_completion_timeout(&dp->resume_comp,
|
|
|
|
|
WAIT_FOR_RESUME_TIMEOUT_JIFFIES)) {
|
|
|
|
|
DRM_ERROR("wait4resume_done timedout\n");
|
|
|
|
|
ret = -ETIMEDOUT;
|
|
|
|
|
}
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
|
{
|
|
|
|
|
int rc = 0;
|
|
|
|
@ -1345,6 +1362,8 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp_display->event_mutex);
|
|
|
|
|
|
|
|
|
|
dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
rc = dp_display_set_mode(dp, &dp_display->dp_mode);
|
|
|
|
|
if (rc) {
|
|
|
|
|
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
|
|
|
|
@ -1359,15 +1378,10 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp_display->hpd_state);
|
|
|
|
|
if (state == ST_SUSPENDED) {
|
|
|
|
|
/* start link training */
|
|
|
|
|
dp_add_event(dp_display, EV_HPD_PLUG_INT, 0, 0);
|
|
|
|
|
mutex_unlock(&dp_display->event_mutex);
|
|
|
|
|
state = dp_display->hpd_state;
|
|
|
|
|
|
|
|
|
|
/* wait until dp interface is up */
|
|
|
|
|
goto resume_done;
|
|
|
|
|
}
|
|
|
|
|
if (state == ST_SUSPEND_PENDING)
|
|
|
|
|
dp_display_host_init(dp_display);
|
|
|
|
|
|
|
|
|
|
dp_display_enable(dp_display, 0);
|
|
|
|
|
|
|
|
|
@ -1378,21 +1392,15 @@ int msm_dp_display_enable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
|
dp_display_unprepare(dp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dp_del_event(dp_display, EV_CONNECT_PENDING_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
if (state == ST_SUSPEND_PENDING)
|
|
|
|
|
dp_add_event(dp_display, EV_IRQ_HPD_INT, 0, 0);
|
|
|
|
|
|
|
|
|
|
/* completed connection */
|
|
|
|
|
atomic_set(&dp_display->hpd_state, ST_CONNECTED);
|
|
|
|
|
dp_display->hpd_state = ST_CONNECTED;
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp_display->event_mutex);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
resume_done:
|
|
|
|
|
dp_display_wait4resume_done(dp_display);
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int msm_dp_display_pre_disable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
@ -1416,20 +1424,20 @@ int msm_dp_display_disable(struct msm_dp *dp, struct drm_encoder *encoder)
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dp_display->event_mutex);
|
|
|
|
|
|
|
|
|
|
dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
dp_display_disable(dp_display, 0);
|
|
|
|
|
|
|
|
|
|
rc = dp_display_unprepare(dp);
|
|
|
|
|
if (rc)
|
|
|
|
|
DRM_ERROR("DP display unprepare failed, rc=%d\n", rc);
|
|
|
|
|
|
|
|
|
|
dp_del_event(dp_display, EV_DISCONNECT_PENDING_TIMEOUT);
|
|
|
|
|
|
|
|
|
|
state = atomic_read(&dp_display->hpd_state);
|
|
|
|
|
state = dp_display->hpd_state;
|
|
|
|
|
if (state == ST_DISCONNECT_PENDING) {
|
|
|
|
|
/* completed disconnection */
|
|
|
|
|
atomic_set(&dp_display->hpd_state, ST_DISCONNECTED);
|
|
|
|
|
dp_display->hpd_state = ST_DISCONNECTED;
|
|
|
|
|
} else {
|
|
|
|
|
atomic_set(&dp_display->hpd_state, ST_SUSPEND_PENDING);
|
|
|
|
|
dp_display->hpd_state = ST_SUSPEND_PENDING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&dp_display->event_mutex);
|
|
|
|
|