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 | 26 +++++++++++++++++-----
 drivers/gpu/drm/msm/dp/dp_mst_drm.c | 44 +++++++++++++++++++++++++++++++++++++
 drivers/gpu/drm/msm/dp/dp_mst_drm.h |  1 +
 3 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index c015af868801..22b925277462 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -416,6 +416,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);
@@ -506,12 +509,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) {
@@ -1056,10 +1065,16 @@ static irqreturn_t msm_dp_display_irq_thread(int irq, 
void *dev_id)
                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);
+       /* Temporary until DRM IRQ support is finalized, then switch to
+        * drm_bridge_hpd_notify().
+        */
+       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;
 
@@ -1717,7 +1732,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 03f9c95ca686..2e625a7db981 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -35,6 +35,8 @@ struct msm_dp_mst {
        u32 max_streams;
        /* Serializes concurrent stream link-state access across 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;
 };
 
@@ -326,6 +328,39 @@ int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, 
unsigned int stream_id,
        return 0;
 }
 
+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 HPD IRQ: esi=%*ph\n", 4, esi);
+
+       rc = drm_dp_mst_hpd_irq_handle_event(&mst->mst_mgr, esi, ack, &handled);
+
+       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);
+}
+
 static struct drm_encoder *
 msm_dp_mst_atomic_best_encoder(struct drm_connector *connector, struct 
drm_atomic_commit *state)
 {
@@ -441,8 +476,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_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct 
drm_dp_aux *drm_aux)
@@ -471,6 +514,7 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 
max_streams, struct drm_d
        }
 
        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 89f73b1db2e7..8546214cbca1 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -10,5 +10,6 @@
 int msm_dp_mst_mgr_init(struct msm_dp *dp_display, u32 max_streams, struct 
drm_dp_aux *drm_aux);
 int msm_dp_mst_attach_encoder(struct msm_dp *dp_display, unsigned int 
stream_id,
                              struct drm_encoder *encoder);
+void msm_dp_mst_display_hpd_irq(struct msm_dp *dp_display);
 
 #endif /* _DP_MST_DRM_H_ */

-- 
2.43.0

Reply via email to