From: Abhinav Kumar <[email protected]>

Add HPD callback for the MST module which shall be invoked from the
dp_display's HPD handler to perform MST specific operations in case
of HPD. In MST case, route the HPD messages to MST module.

Signed-off-by: Abhinav Kumar <[email protected]>
Signed-off-by: Yongxing Mou <[email protected]>
---
 drivers/gpu/drm/msm/dp/dp_display.c | 22 ++++++++++++++----
 drivers/gpu/drm/msm/dp/dp_mst_drm.c | 46 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_mst_drm.h |  1 +
 3 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 6eac390af2e0..49a7bc5e031e 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -455,6 +455,9 @@ static int msm_dp_hpd_plug_handle(struct 
msm_dp_display_private *dp)
                        dp->msm_dp_display.connector_type,
                        dp->link->sink_count);
 
+       if (dp->plugged && dp->msm_dp_display.mst_active)
+               return 0;
+
        guard(mutex)(&dp->plugged_lock);
 
        ret = pm_runtime_resume_and_get(&pdev->dev);
@@ -550,12 +553,18 @@ static int msm_dp_irq_hpd_handle(struct 
msm_dp_display_private *dp)
 {
        u32 sink_request;
        int rc = 0;
+       struct msm_dp *msm_dp_display = &dp->msm_dp_display;
 
        /* irq_hpd can happen at either connected or disconnected state */
        drm_dbg_dp(dp->drm_dev, "Before, type=%d, sink_count=%d\n",
                        dp->msm_dp_display.connector_type,
                        dp->link->sink_count);
 
+       if (msm_dp_display->mst_active) {
+               msm_dp_mst_display_hpd_irq(&dp->msm_dp_display);
+               return 0;
+       }
+
        /* check for any test request issued by sink */
        rc = msm_dp_link_process_request(dp->link);
        if (!rc) {
@@ -1111,9 +1120,13 @@ static irqreturn_t msm_dp_display_irq_thread(int irq, 
void *dev_id)
                                      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);
+       if (hpd_isr_status & DP_DP_IRQ_HPD_INT_MASK) {
+               if (dp->msm_dp_display.mst_active)
+                       msm_dp_irq_hpd_handle(dp);
+               else
+                       drm_bridge_hpd_notify(dp->msm_dp_display.bridge,
+                                             connector_status_connected);
+       }
 
        ret = IRQ_HANDLED;
 
@@ -1776,7 +1789,8 @@ void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
                        msm_dp_hpd_plug_handle(dp);
                }
        } else {
-               msm_dp_hpd_unplug_handle(dp);
+               if (hpd_link_status == ISR_DISCONNECTED)
+                       msm_dp_hpd_unplug_handle(dp);
        }
 
        pm_runtime_put_sync(&msm_dp_display->pdev->dev);
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c 
b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
index 12b47a413793..56f7a84e77d1 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -36,6 +36,8 @@ struct msm_dp_mst {
        struct drm_dp_aux *dp_aux;
        u32 max_streams;
        struct mutex mst_lock;
+       /* Serializes HPD IRQ handling between IRQ handler and poll_hpd_irq. */
+       struct mutex hpd_irq_lock;
        struct msm_dp_link_info link_info;
 };
 
@@ -288,6 +290,41 @@ int msm_dp_mst_display_set_mgr_state(struct msm_dp 
*dp_display, bool state)
        return rc;
 }
 
+void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display)
+{
+       int rc;
+       struct msm_dp_mst *mst = dp_display->msm_dp_mst;
+       u8 ack[8] = {};
+       u8 esi[4];
+       unsigned int esi_res = DP_SINK_COUNT_ESI + 1;
+       bool handled;
+
+       guard(mutex)(&mst->hpd_irq_lock);
+
+       rc = drm_dp_dpcd_read_data(mst->dp_aux, DP_SINK_COUNT_ESI, esi, 4);
+       if (rc < 0) {
+               DRM_ERROR("DPCD sink status read failed, rlen=%d\n", rc);
+               return;
+       }
+
+       drm_dbg_dp(dp_display->drm_dev, "MST irq: esi1[0x%x] esi2[0x%x] 
esi3[%x]\n",
+                  esi[1], esi[2], esi[3]);
+
+       rc = drm_dp_mst_hpd_irq_handle_event(&mst->mst_mgr, esi, ack, &handled);
+
+       /* ack the request */
+       if (handled) {
+               rc = drm_dp_dpcd_write_byte(mst->dp_aux, esi_res, ack[1]);
+               if (rc < 0) {
+                       DRM_ERROR("DPCD esi_res failed. rc=%d\n", rc);
+                       return;
+               }
+
+               drm_dp_mst_hpd_irq_send_new_request(&mst->mst_mgr);
+       }
+       drm_dbg_dp(dp_display->drm_dev, "MST display hpd_irq handled:%d 
rc:%d\n", handled, rc);
+}
+
 /* DP MST Connector OPs */
 static int
 msm_dp_mst_connector_detect(struct drm_connector *connector,
@@ -502,8 +539,16 @@ msm_dp_mst_add_connector(struct drm_dp_mst_topology_mgr 
*mgr,
        return NULL;
 }
 
+static void msm_dp_mst_poll_hpd_irq(struct drm_dp_mst_topology_mgr *mgr)
+{
+       struct msm_dp_mst *mst = container_of(mgr, struct msm_dp_mst, mst_mgr);
+
+       msm_dp_mst_display_hpd_irq(mst->msm_dp);
+}
+
 static const struct drm_dp_mst_topology_cbs msm_dp_mst_drm_cbs = {
        .add_connector = msm_dp_mst_add_connector,
+       .poll_hpd_irq  = msm_dp_mst_poll_hpd_irq,
 };
 
 int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct 
drm_dp_aux *drm_aux)
@@ -532,6 +577,7 @@ int msm_dp_mst_init(struct msm_dp *dp_display, u32 
max_streams, struct drm_dp_au
        }
 
        mutex_init(&mst->mst_lock);
+       mutex_init(&mst->hpd_irq_lock);
        dp_display->msm_dp_mst = mst;
        return 0;
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h 
b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
index 5d411529f681..08e145399cfc 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -9,5 +9,6 @@
 
 int msm_dp_mst_init(struct msm_dp *dp_display, u32 max_streams, struct 
drm_dp_aux *drm_aux);
 int msm_dp_mst_display_set_mgr_state(struct msm_dp *dp_display, bool state);
+void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display);
 
 #endif /* _DP_MST_DRM_H_ */

-- 
2.43.0

Reply via email to