ISR_HPD_REPLUG_COUNT,
};
-/* event thread connection state */
-enum {
- ST_DISCONNECTED,
- ST_MAINLINK_READY,
- ST_CONNECTED,
- ST_DISCONNECT_PENDING,
- ST_DISPLAY_OFF,
-};
-
-enum {
- EV_NO_EVENT,
- /* hpd events */
- EV_HPD_PLUG_INT,
- EV_IRQ_HPD_INT,
- EV_HPD_UNPLUG_INT,
-};
-
-#define EVENT_TIMEOUT (HZ/10) /* 100ms */
-#define DP_EVENT_Q_MAX 8
-
-#define DP_TIMEOUT_NONE 0
-
-#define WAIT_FOR_RESUME_TIMEOUT_JIFFIES (HZ / 2)
-
-struct msm_dp_event {
- u32 event_id;
- u32 delay;
-};
-
struct msm_dp_display_private {
int irq;
/* wait for audio signaling */
struct completion audio_comp;
- /* event related only access by event thread */
- struct mutex event_mutex;
- wait_queue_head_t event_q;
- u32 hpd_state;
- u32 event_pndx;
- u32 event_gndx;
- struct task_struct *ev_tsk;
- struct msm_dp_event event_list[DP_EVENT_Q_MAX];
- spinlock_t event_lock;
+ /* HPD IRQ handling */
+ spinlock_t irq_thread_lock;
+ u32 hpd_isr_status;
bool wide_bus_supported;
return container_of(dp, struct msm_dp_display_private, msm_dp_display);
}
-static int msm_dp_add_event(struct msm_dp_display_private *msm_dp_priv, u32 event,
- u32 delay)
-{
- unsigned long flag;
- struct msm_dp_event *todo;
- int pndx;
-
- spin_lock_irqsave(&msm_dp_priv->event_lock, flag);
- pndx = msm_dp_priv->event_pndx + 1;
- pndx %= DP_EVENT_Q_MAX;
- if (pndx == msm_dp_priv->event_gndx) {
- pr_err("event_q is full: pndx=%d gndx=%d\n",
- msm_dp_priv->event_pndx, msm_dp_priv->event_gndx);
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
- return -EPERM;
- }
- todo = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++];
- msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX;
- todo->event_id = event;
- todo->delay = delay;
- wake_up(&msm_dp_priv->event_q);
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
-
- return 0;
-}
-
-static int msm_dp_del_event(struct msm_dp_display_private *msm_dp_priv, u32 event)
-{
- unsigned long flag;
- struct msm_dp_event *todo;
- u32 gndx;
-
- spin_lock_irqsave(&msm_dp_priv->event_lock, flag);
- if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) {
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
- return -ENOENT;
- }
-
- gndx = msm_dp_priv->event_gndx;
- while (msm_dp_priv->event_pndx != gndx) {
- todo = &msm_dp_priv->event_list[gndx];
- if (todo->event_id == event) {
- todo->event_id = EV_NO_EVENT; /* deleted */
- todo->delay = 0;
- }
- gndx++;
- gndx %= DP_EVENT_Q_MAX;
- }
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
-
- return 0;
-}
-
void msm_dp_display_signal_audio_start(struct msm_dp *msm_dp_display)
{
struct msm_dp_display_private *dp;
complete_all(&dp->audio_comp);
}
-static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv);
-
static int msm_dp_display_bind(struct device *dev, struct device *master,
void *data)
{
goto end;
}
- rc = msm_dp_hpd_event_thread_start(dp);
- if (rc) {
- DRM_ERROR("Event thread create failed\n");
- goto end;
- }
-
return 0;
end:
return rc;
struct msm_dp_display_private *dp = dev_get_dp_display_private(dev);
struct msm_drm_private *priv = dev_get_drvdata(master);
- kthread_stop(dp->ev_tsk);
-
of_dp_aux_depopulate_bus(dp->aux);
msm_dp_aux_unregister(dp->aux);
.unbind = msm_dp_display_unbind,
};
-static int msm_dp_display_send_hpd_notification(struct msm_dp_display_private *dp,
- bool hpd)
-{
- if ((hpd && dp->msm_dp_display.link_ready) ||
- (!hpd && !dp->msm_dp_display.link_ready)) {
- drm_dbg_dp(dp->drm_dev, "HPD already %s\n", str_on_off(hpd));
- return 0;
- }
-
- /* reset video pattern flag on disconnect */
- if (!hpd) {
- dp->panel->video_test = false;
- if (!dp->msm_dp_display.is_edp)
- drm_dp_set_subconnector_property(dp->msm_dp_display.connector,
- connector_status_disconnected,
- dp->panel->dpcd,
- dp->panel->downstream_ports);
- }
-
- dp->msm_dp_display.link_ready = hpd;
-
- drm_dbg_dp(dp->drm_dev, "type=%d hpd=%d\n",
- dp->msm_dp_display.connector_type, hpd);
-
- drm_bridge_hpd_notify(dp->msm_dp_display.bridge,
- hpd ?
- connector_status_connected :
- connector_status_disconnected);
-
- return 0;
-}
-
static int msm_dp_display_lttpr_init(struct msm_dp_display_private *dp, u8 *dpcd)
{
int rc, lttpr_count;
dp->panel->dpcd,
dp->panel->downstream_ports);
+ dp->msm_dp_display.link_ready = true;
+
dp->msm_dp_display.psr_supported = dp->panel->psr_cap.version && psr_enabled;
dp->audio_supported = info->has_audio;
msm_dp_link_reset_phy_params_vx_px(dp->link);
- msm_dp_display_send_hpd_notification(dp, true);
-
end:
return rc;
}
dp->core_initialized = false;
}
-static int msm_dp_display_usbpd_configure_cb(struct device *dev)
-{
- struct msm_dp_display_private *dp = dev_get_dp_display_private(dev);
-
- msm_dp_display_host_phy_init(dp);
-
- return msm_dp_display_process_hpd_high(dp);
-}
-
-static int msm_dp_display_notify_disconnect(struct device *dev)
-{
- struct msm_dp_display_private *dp = dev_get_dp_display_private(dev);
-
- msm_dp_display_send_hpd_notification(dp, false);
-
- return 0;
-}
-
static void msm_dp_display_handle_video_request(struct msm_dp_display_private *dp)
{
if (dp->link->sink_request & DP_TEST_LINK_VIDEO_PATTERN) {
}
}
-static int msm_dp_display_handle_port_status_changed(struct msm_dp_display_private *dp)
-{
- int rc = 0;
-
- if (drm_dp_is_branch(dp->panel->dpcd) && dp->link->sink_count == 0) {
- drm_dbg_dp(dp->drm_dev, "sink count is zero, nothing to do\n");
- if (dp->hpd_state != ST_DISCONNECTED) {
- dp->hpd_state = ST_DISCONNECT_PENDING;
- msm_dp_display_send_hpd_notification(dp, false);
- }
- } else {
- if (dp->hpd_state == ST_DISCONNECTED) {
- dp->hpd_state = ST_MAINLINK_READY;
- rc = msm_dp_display_process_hpd_high(dp);
- if (rc)
- dp->hpd_state = ST_DISCONNECTED;
- }
- }
-
- return rc;
-}
-
static int msm_dp_display_handle_irq_hpd(struct msm_dp_display_private *dp)
{
u32 sink_request = dp->link->sink_request;
drm_dbg_dp(dp->drm_dev, "%d\n", sink_request);
- if (dp->hpd_state == ST_DISCONNECTED) {
+ if (!dp->msm_dp_display.link_ready) {
if (sink_request & DP_LINK_STATUS_UPDATED) {
drm_dbg_dp(dp->drm_dev, "Disconnected sink_request: %d\n",
sink_request);
return 0;
}
-static int msm_dp_display_usbpd_attention_cb(struct device *dev)
-{
- int rc = 0;
- u32 sink_request;
- struct msm_dp_display_private *dp = dev_get_dp_display_private(dev);
-
- /* check for any test request issued by sink */
- rc = msm_dp_link_process_request(dp->link);
- if (!rc) {
- sink_request = dp->link->sink_request;
- drm_dbg_dp(dp->drm_dev, "hpd_state=%d sink_request=%d\n",
- dp->hpd_state, sink_request);
- if (sink_request & DS_PORT_STATUS_CHANGED)
- rc = msm_dp_display_handle_port_status_changed(dp);
- else
- rc = msm_dp_display_handle_irq_hpd(dp);
- }
-
- return rc;
-}
-
static int msm_dp_hpd_plug_handle(struct msm_dp_display_private *dp)
{
- u32 state;
int ret;
struct platform_device *pdev = dp->msm_dp_display.pdev;
- msm_dp_aux_enable_xfers(dp->aux, true);
-
- mutex_lock(&dp->event_mutex);
-
- state = dp->hpd_state;
- drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
-
- if (state == ST_DISPLAY_OFF) {
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
-
- if (state == ST_MAINLINK_READY || state == ST_CONNECTED) {
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d\n",
+ dp->msm_dp_display.connector_type);
- if (state == ST_DISCONNECT_PENDING) {
- /* wait until ST_DISCONNECTED */
- msm_dp_add_event(dp, EV_HPD_PLUG_INT, 1);
- mutex_unlock(&dp->event_mutex);
+ if (dp->msm_dp_display.link_ready)
return 0;
- }
ret = pm_runtime_resume_and_get(&pdev->dev);
if (ret) {
DRM_ERROR("failed to pm_runtime_resume\n");
- mutex_unlock(&dp->event_mutex);
return ret;
}
- ret = msm_dp_display_usbpd_configure_cb(&pdev->dev);
+ msm_dp_aux_enable_xfers(dp->aux, true);
+
+ msm_dp_display_host_phy_init(dp);
+
+ ret = msm_dp_display_process_hpd_high(dp);
if (ret) { /* link train failed */
- dp->hpd_state = ST_DISCONNECTED;
+ dp->msm_dp_display.link_ready = false;
+ msm_dp_aux_enable_xfers(dp->aux, false);
pm_runtime_put_sync(&pdev->dev);
- } else {
- dp->hpd_state = ST_MAINLINK_READY;
}
- drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
- mutex_unlock(&dp->event_mutex);
+ drm_dbg_dp(dp->drm_dev, "After, type=%d\n",
+ dp->msm_dp_display.connector_type);
/* uevent will complete connection part */
return 0;
static int msm_dp_hpd_unplug_handle(struct msm_dp_display_private *dp)
{
- u32 state;
struct platform_device *pdev = dp->msm_dp_display.pdev;
- msm_dp_aux_enable_xfers(dp->aux, false);
-
- mutex_lock(&dp->event_mutex);
-
- state = dp->hpd_state;
+ dp->panel->video_test = false;
- drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
+ msm_dp_aux_enable_xfers(dp->aux, false);
- /* unplugged, no more irq_hpd handle */
- msm_dp_del_event(dp, EV_IRQ_HPD_INT);
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d\n",
+ dp->msm_dp_display.connector_type);
- if (state == ST_DISCONNECTED) {
- /* triggered by irq_hdp with sink_count = 0 */
- if (dp->link->sink_count == 0) {
- msm_dp_display_host_phy_exit(dp);
- }
- msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev);
- mutex_unlock(&dp->event_mutex);
+ if (!dp->msm_dp_display.link_ready)
return 0;
- } else if (state == ST_DISCONNECT_PENDING) {
- mutex_unlock(&dp->event_mutex);
- return 0;
- } else if (state == ST_MAINLINK_READY) {
- msm_dp_ctrl_off_link(dp->ctrl);
+
+ /* triggered by irq_hdp with sink_count = 0 */
+ if (dp->link->sink_count == 0)
msm_dp_display_host_phy_exit(dp);
- dp->hpd_state = ST_DISCONNECTED;
- msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev);
- pm_runtime_put_sync(&pdev->dev);
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
/*
* We don't need separate work for disconnect as
* connect/attention interrupts are disabled
*/
- msm_dp_display_notify_disconnect(&dp->msm_dp_display.pdev->dev);
+ if (!dp->msm_dp_display.is_edp)
+ drm_dp_set_subconnector_property(dp->msm_dp_display.connector,
+ connector_status_disconnected,
+ dp->panel->dpcd,
+ dp->panel->downstream_ports);
- if (state == ST_DISPLAY_OFF) {
- dp->hpd_state = ST_DISCONNECTED;
- } else {
- dp->hpd_state = ST_DISCONNECT_PENDING;
- }
+ dp->msm_dp_display.link_ready = false;
/* signal the disconnect event early to ensure proper teardown */
msm_dp_display_handle_plugged_change(&dp->msm_dp_display, false);
- drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
+ drm_dbg_dp(dp->drm_dev, "After, type=%d\n",
+ dp->msm_dp_display.connector_type);
/* uevent will complete disconnection part */
pm_runtime_put_sync(&pdev->dev);
- mutex_unlock(&dp->event_mutex);
return 0;
}
static int msm_dp_irq_hpd_handle(struct msm_dp_display_private *dp)
{
- u32 state;
-
- mutex_lock(&dp->event_mutex);
+ u32 sink_request;
+ int rc = 0;
/* irq_hpd can happen at either connected or disconnected state */
- state = dp->hpd_state;
- drm_dbg_dp(dp->drm_dev, "Before, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
+ drm_dbg_dp(dp->drm_dev, "Before, type=%d\n",
+ dp->msm_dp_display.connector_type);
- if (state == ST_DISPLAY_OFF) {
- mutex_unlock(&dp->event_mutex);
- return 0;
- }
-
- if (state == ST_MAINLINK_READY || state == ST_DISCONNECT_PENDING) {
- /* wait until ST_CONNECTED */
- msm_dp_add_event(dp, EV_IRQ_HPD_INT, 1);
- mutex_unlock(&dp->event_mutex);
- return 0;
+ /* check for any test request issued by sink */
+ rc = msm_dp_link_process_request(dp->link);
+ if (!rc) {
+ sink_request = dp->link->sink_request;
+ drm_dbg_dp(dp->drm_dev, "sink_request=%d\n", sink_request);
+ if (sink_request & DS_PORT_STATUS_CHANGED)
+ rc = msm_dp_display_process_hpd_high(dp);
+ else
+ rc = msm_dp_display_handle_irq_hpd(dp);
}
- msm_dp_display_usbpd_attention_cb(&dp->msm_dp_display.pdev->dev);
+ drm_dbg_dp(dp->drm_dev, "After, type=%d\n",
+ dp->msm_dp_display.connector_type);
- drm_dbg_dp(dp->drm_dev, "After, type=%d hpd_state=%d\n",
- dp->msm_dp_display.connector_type, state);
-
- mutex_unlock(&dp->event_mutex);
-
- return 0;
+ return rc;
}
static void msm_dp_display_deinit_sub_modules(struct msm_dp_display_private *dp)
* power_on status before dumping DP registers to avoid crash due
* to unclocked access
*/
- mutex_lock(&msm_dp_display->event_mutex);
-
- if (!dp->power_on) {
- mutex_unlock(&msm_dp_display->event_mutex);
+ if (!dp->power_on)
return;
- }
msm_disp_snapshot_add_block(disp_state, msm_dp_display->ahb_len,
msm_dp_display->ahb_base, "dp_ahb");
msm_dp_display->link_base, "dp_link");
msm_disp_snapshot_add_block(disp_state, msm_dp_display->p0_len,
msm_dp_display->p0_base, "dp_p0");
-
- mutex_unlock(&msm_dp_display->event_mutex);
}
void msm_dp_display_set_psr(struct msm_dp *msm_dp_display, bool enter)
msm_dp_ctrl_set_psr(dp->ctrl, enter);
}
-static int hpd_event_thread(void *data)
-{
- struct msm_dp_display_private *msm_dp_priv;
- unsigned long flag;
- struct msm_dp_event *todo;
- int timeout_mode = 0;
-
- msm_dp_priv = (struct msm_dp_display_private *)data;
-
- while (1) {
- if (timeout_mode) {
- wait_event_timeout(msm_dp_priv->event_q,
- (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) ||
- kthread_should_stop(), EVENT_TIMEOUT);
- } else {
- wait_event_interruptible(msm_dp_priv->event_q,
- (msm_dp_priv->event_pndx != msm_dp_priv->event_gndx) ||
- kthread_should_stop());
- }
-
- if (kthread_should_stop())
- break;
-
- spin_lock_irqsave(&msm_dp_priv->event_lock, flag);
- todo = &msm_dp_priv->event_list[msm_dp_priv->event_gndx];
- if (todo->delay) {
- struct msm_dp_event *todo_next;
-
- msm_dp_priv->event_gndx++;
- msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX;
-
- /* re enter delay event into q */
- todo_next = &msm_dp_priv->event_list[msm_dp_priv->event_pndx++];
- msm_dp_priv->event_pndx %= DP_EVENT_Q_MAX;
- todo_next->event_id = todo->event_id;
- todo_next->delay = todo->delay - 1;
-
- /* clean up older event */
- todo->event_id = EV_NO_EVENT;
- todo->delay = 0;
-
- /* switch to timeout mode */
- timeout_mode = 1;
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
- continue;
- }
-
- /* timeout with no events in q */
- if (msm_dp_priv->event_pndx == msm_dp_priv->event_gndx) {
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
- continue;
- }
-
- msm_dp_priv->event_gndx++;
- msm_dp_priv->event_gndx %= DP_EVENT_Q_MAX;
- timeout_mode = 0;
- spin_unlock_irqrestore(&msm_dp_priv->event_lock, flag);
-
- switch (todo->event_id) {
- case EV_HPD_PLUG_INT:
- msm_dp_hpd_plug_handle(msm_dp_priv);
- break;
- case EV_HPD_UNPLUG_INT:
- msm_dp_hpd_unplug_handle(msm_dp_priv);
- break;
- case EV_IRQ_HPD_INT:
- msm_dp_irq_hpd_handle(msm_dp_priv);
- break;
- default:
- break;
- }
- }
-
- return 0;
-}
-
-static int msm_dp_hpd_event_thread_start(struct msm_dp_display_private *msm_dp_priv)
-{
- /* set event q to empty */
- msm_dp_priv->event_gndx = 0;
- msm_dp_priv->event_pndx = 0;
-
- msm_dp_priv->ev_tsk = kthread_run(hpd_event_thread, msm_dp_priv, "dp_hpd_handler");
- if (IS_ERR(msm_dp_priv->ev_tsk))
- return PTR_ERR(msm_dp_priv->ev_tsk);
-
- return 0;
-}
-
/**
* msm_dp_bridge_detect - callback to determine if connector is connected
*
if (!dp->link_ready)
return status;
- msm_dp_aux_enable_xfers(priv->aux, true);
-
ret = pm_runtime_resume_and_get(&dp->pdev->dev);
if (ret) {
DRM_ERROR("failed to pm_runtime_resume\n");
- msm_dp_aux_enable_xfers(priv->aux, false);
return status;
}
+ msm_dp_aux_enable_xfers(priv->aux, true);
+
ret = msm_dp_aux_is_link_connected(priv->aux);
- if (dp->internal_hpd && !ret)
+ if (!ret) {
+ DRM_DEBUG_DP("aux not connected\n");
goto end;
+ }
ret = drm_dp_read_dpcd_caps(priv->aux, dpcd);
- if (ret)
+ if (ret) {
+ DRM_DEBUG_DP("failed to read caps\n");
goto end;
+ }
ret = drm_dp_read_desc(priv->aux, &desc, drm_dp_is_branch(dpcd));
- if (ret)
+ if (ret) {
+ DRM_DEBUG_DP("failed to read desc\n");
goto end;
+ }
status = connector_status_connected;
if (drm_dp_read_sink_count_cap(connector, dpcd, &desc)) {
static irqreturn_t msm_dp_display_irq_handler(int irq, void *dev_id)
{
struct msm_dp_display_private *dp = dev_id;
- irqreturn_t ret = IRQ_NONE;
u32 hpd_isr_status;
-
- if (!dp) {
- DRM_ERROR("invalid data\n");
- return IRQ_NONE;
- }
+ unsigned long flags;
+ irqreturn_t ret = IRQ_HANDLED;
hpd_isr_status = msm_dp_aux_get_hpd_intr_status(dp->aux);
if (hpd_isr_status & 0x0F) {
drm_dbg_dp(dp->drm_dev, "type=%d isr=0x%x\n",
dp->msm_dp_display.connector_type, hpd_isr_status);
- /* hpd related interrupts */
- if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK)
- msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0);
-
- if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
- msm_dp_add_event(dp, EV_IRQ_HPD_INT, 0);
- }
- if (hpd_isr_status & DP_DP_HPD_REPLUG_INT_MASK) {
- msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0);
- msm_dp_add_event(dp, EV_HPD_PLUG_INT, 3);
- }
-
- if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK)
- msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0);
-
- ret = IRQ_HANDLED;
+ spin_lock_irqsave(&dp->irq_thread_lock, flags);
+ dp->hpd_isr_status |= hpd_isr_status;
+ ret = IRQ_WAKE_THREAD;
+ spin_unlock_irqrestore(&dp->irq_thread_lock, flags);
}
/* DP controller isr */
return ret;
}
+static irqreturn_t msm_dp_display_irq_thread(int irq, void *dev_id)
+{
+ struct msm_dp_display_private *dp = dev_id;
+ irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
+ u32 hpd_isr_status;
+
+ spin_lock_irqsave(&dp->irq_thread_lock, flags);
+ hpd_isr_status = dp->hpd_isr_status;
+ dp->hpd_isr_status = 0;
+ spin_unlock_irqrestore(&dp->irq_thread_lock, flags);
+
+ if (hpd_isr_status & DP_DP_HPD_UNPLUG_INT_MASK)
+ drm_bridge_hpd_notify(dp->msm_dp_display.bridge,
+ connector_status_disconnected);
+
+ if (hpd_isr_status & DP_DP_HPD_PLUG_INT_MASK)
+ drm_bridge_hpd_notify(dp->msm_dp_display.bridge,
+ connector_status_connected);
+
+ /* Send HPD as connected and distinguish it in the notifier */
+ if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK)
+ drm_bridge_hpd_notify(dp->msm_dp_display.bridge,
+ connector_status_connected);
+
+ ret = IRQ_HANDLED;
+
+ return ret;
+}
+
static int msm_dp_display_request_irq(struct msm_dp_display_private *dp)
{
int rc = 0;
return dp->irq;
}
- rc = devm_request_irq(&pdev->dev, dp->irq, msm_dp_display_irq_handler,
- IRQF_TRIGGER_HIGH|IRQF_NO_AUTOEN,
- "dp_display_isr", dp);
+ spin_lock_init(&dp->irq_thread_lock);
+ irq_set_status_flags(dp->irq, IRQ_NOAUTOEN);
+ rc = devm_request_threaded_irq(&pdev->dev, dp->irq,
+ msm_dp_display_irq_handler,
+ msm_dp_display_irq_thread,
+ IRQ_TYPE_LEVEL_HIGH,
+ "dp_display_isr", dp);
if (rc < 0) {
DRM_ERROR("failed to request IRQ%u: %d\n",
dp->wide_bus_supported = desc->wide_bus_supported;
dp->msm_dp_display.is_edp =
(dp->msm_dp_display.connector_type == DRM_MODE_CONNECTOR_eDP);
+ dp->hpd_isr_status = 0;
rc = msm_dp_display_get_io(dp);
if (rc)
return -EPROBE_DEFER;
}
- /* setup event q */
- mutex_init(&dp->event_mutex);
- init_waitqueue_head(&dp->event_q);
- spin_lock_init(&dp->event_lock);
-
/* Store DP audio handle inside DP display */
dp->msm_dp_display.msm_dp_audio = dp->audio;
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
int rc = 0;
struct msm_dp_display_private *msm_dp_display;
- u32 hpd_state;
bool force_link_train = false;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
if (dp->is_edp)
msm_dp_hpd_plug_handle(msm_dp_display);
- mutex_lock(&msm_dp_display->event_mutex);
if (pm_runtime_resume_and_get(&dp->pdev->dev)) {
DRM_ERROR("failed to pm_runtime_resume\n");
- mutex_unlock(&msm_dp_display->event_mutex);
return;
}
- hpd_state = msm_dp_display->hpd_state;
- if (hpd_state != ST_DISPLAY_OFF && hpd_state != ST_MAINLINK_READY) {
- mutex_unlock(&msm_dp_display->event_mutex);
+ if (msm_dp_display->link->sink_count == 0)
return;
- }
rc = msm_dp_display_set_mode(dp, &msm_dp_display->msm_dp_mode);
if (rc) {
DRM_ERROR("Failed to perform a mode set, rc=%d\n", rc);
- mutex_unlock(&msm_dp_display->event_mutex);
return;
}
- hpd_state = msm_dp_display->hpd_state;
-
- if (hpd_state == ST_DISPLAY_OFF) {
+ if (dp->link_ready && !dp->power_on) {
msm_dp_display_host_phy_init(msm_dp_display);
force_link_train = true;
}
msm_dp_display_disable(msm_dp_display);
}
- /* completed connection */
- msm_dp_display->hpd_state = ST_CONNECTED;
-
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
- mutex_unlock(&msm_dp_display->event_mutex);
}
void msm_dp_bridge_atomic_disable(struct drm_bridge *drm_bridge,
{
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(drm_bridge);
struct msm_dp *dp = msm_dp_bridge->msm_dp_display;
- u32 hpd_state;
struct msm_dp_display_private *msm_dp_display;
msm_dp_display = container_of(dp, struct msm_dp_display_private, msm_dp_display);
if (dp->is_edp)
msm_dp_hpd_unplug_handle(msm_dp_display);
- mutex_lock(&msm_dp_display->event_mutex);
-
- hpd_state = msm_dp_display->hpd_state;
- if (hpd_state != ST_DISCONNECT_PENDING && hpd_state != ST_CONNECTED)
- drm_dbg_dp(dp->drm_dev, "type=%d wrong hpd_state=%d\n",
- dp->connector_type, hpd_state);
+ if (!dp->link_ready)
+ drm_dbg_dp(dp->drm_dev, "type=%d is disconnected\n", dp->connector_type);
msm_dp_display_disable(msm_dp_display);
- hpd_state = msm_dp_display->hpd_state;
- if (hpd_state == ST_DISCONNECT_PENDING) {
- /* completed disconnection */
- msm_dp_display->hpd_state = ST_DISCONNECTED;
- } else {
- msm_dp_display->hpd_state = ST_DISPLAY_OFF;
- }
-
drm_dbg_dp(dp->drm_dev, "type=%d Done\n", dp->connector_type);
pm_runtime_put_sync(&dp->pdev->dev);
- mutex_unlock(&msm_dp_display->event_mutex);
}
void msm_dp_bridge_mode_set(struct drm_bridge *drm_bridge,
* step-4: DP PHY is initialized at plugin handler before link training
*
*/
- mutex_lock(&dp->event_mutex);
if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) {
DRM_ERROR("failed to resume power\n");
- mutex_unlock(&dp->event_mutex);
return;
}
msm_dp_aux_hpd_enable(dp->aux);
msm_dp_aux_hpd_intr_enable(dp->aux);
-
- msm_dp_display->internal_hpd = true;
- mutex_unlock(&dp->event_mutex);
}
void msm_dp_bridge_hpd_disable(struct drm_bridge *bridge)
struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display;
struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
- mutex_lock(&dp->event_mutex);
-
msm_dp_aux_hpd_intr_disable(dp->aux);
msm_dp_aux_hpd_disable(dp->aux);
- msm_dp_display->internal_hpd = false;
-
pm_runtime_put_sync(&msm_dp_display->pdev->dev);
- mutex_unlock(&dp->event_mutex);
}
void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
struct msm_dp_bridge *msm_dp_bridge = to_dp_bridge(bridge);
struct msm_dp *msm_dp_display = msm_dp_bridge->msm_dp_display;
struct msm_dp_display_private *dp = container_of(msm_dp_display, struct msm_dp_display_private, msm_dp_display);
+ u32 hpd_link_status = 0;
- /* Without next_bridge interrupts are handled by the DP core directly */
- if (msm_dp_display->internal_hpd)
+ if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) {
+ DRM_ERROR("failed to pm_runtime_resume\n");
return;
+ }
+
+ hpd_link_status = msm_dp_aux_is_link_connected(dp->aux);
- if (!msm_dp_display->link_ready && status == connector_status_connected)
- msm_dp_add_event(dp, EV_HPD_PLUG_INT, 0);
- else if (msm_dp_display->link_ready && status == connector_status_disconnected)
- msm_dp_add_event(dp, EV_HPD_UNPLUG_INT, 0);
+ drm_dbg_dp(dp->drm_dev, "type=%d link hpd_link_status=0x%x, link_ready=%d, status=%d\n",
+ msm_dp_display->connector_type, hpd_link_status,
+ msm_dp_display->link_ready, status);
+
+ if (status == connector_status_connected) {
+ if (hpd_link_status == ISR_HPD_REPLUG_COUNT) {
+ msm_dp_hpd_unplug_handle(dp);
+ msm_dp_hpd_plug_handle(dp);
+ } else if (hpd_link_status == ISR_IRQ_HPD_PULSE_COUNT) {
+ msm_dp_irq_hpd_handle(dp);
+ } else {
+ msm_dp_hpd_plug_handle(dp);
+ }
+ } else {
+ msm_dp_hpd_unplug_handle(dp);
+ }
+
+ pm_runtime_put_sync(&msm_dp_display->pdev->dev);
}