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

diff --git a/drivers/gpu/drm/msm/dp/dp_display.c 
b/drivers/gpu/drm/msm/dp/dp_display.c
index 4a3ca1bf05a0..71c5e6bef02f 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -417,6 +417,8 @@ static int msm_dp_hpd_plug_handle(struct 
msm_dp_display_private *dp)
                        dp->link->sink_count);
 
        guard(mutex)(&dp->plugged_lock);
+       if (dp->plugged && dp->msm_dp_display.mst_active)
+               return 0;
 
        ret = pm_runtime_resume_and_get(&pdev->dev);
        if (ret) {
@@ -516,12 +518,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) {
@@ -1069,10 +1077,10 @@ 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);
+               drm_bridge_hpd_notify_extra(dp->msm_dp_display.bridge,
+                                           connector_status_connected,
+                                           DRM_CONNECTOR_DP_IRQ_HPD);
 
        ret = IRQ_HANDLED;
 
@@ -1309,9 +1317,15 @@ int msm_dp_mst_register(struct msm_dp *msm_dp_display)
 
 void msm_dp_mst_unregister(struct msm_dp *msm_dp_display)
 {
+       struct msm_dp_display_private *dp;
+
        if (!msm_dp_display->msm_dp_mst)
                return;
 
+       dp = container_of(msm_dp_display, struct msm_dp_display_private, 
msm_dp_display);
+
+       /* HPD is disabled by drm_kms_helper_poll_fini() before KMS teardown. */
+       synchronize_irq(dp->irq);
        msm_dp_mst_mgr_destroy(msm_dp_display);
 }
 
@@ -1737,7 +1751,7 @@ 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;
+       u32 hpd_link_status;
 
        if (pm_runtime_resume_and_get(&msm_dp_display->pdev->dev)) {
                DRM_ERROR("failed to pm_runtime_resume\n");
@@ -1759,7 +1773,7 @@ void msm_dp_bridge_hpd_notify(struct drm_bridge *bridge,
                } else {
                        msm_dp_hpd_plug_handle(dp);
                }
-       } else {
+       } else if (status == connector_status_disconnected) {
                msm_dp_hpd_unplug_handle(dp);
        }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.c 
b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
index fd8fd6fd10bd..4c0ad3dc5793 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.c
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.c
@@ -15,6 +15,8 @@
 #define to_dp_mst_connector(x) \
                container_of((x), struct msm_dp_mst_connector, connector)
 
+#define MSM_DP_MST_HPD_IRQ_MAX_TRIES 30
+
 struct msm_dp_mst_connector {
        struct drm_connector connector;
        struct drm_dp_mst_port *mst_port;
@@ -36,6 +38,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;
 };
 
 static void dp_mst_connector_destroy(struct drm_connector *connector)
@@ -357,6 +361,40 @@ 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;
+       unsigned int esi_res = DP_SINK_COUNT_ESI + 1;
+       int i;
+
+       guard(mutex)(&mst->hpd_irq_lock);
+
+       for (i = 0; i < MSM_DP_MST_HPD_IRQ_MAX_TRIES; i++) {
+               u8 ack[8] = {};
+               u8 esi[4];
+               bool handled;
+
+               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;
+               }
+
+               rc = drm_dp_mst_hpd_irq_handle_event(&mst->mst_mgr, esi, ack, 
&handled);
+               if (!handled)
+                       break;
+
+               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);
+       }
+}
+
 static struct drm_encoder *
 msm_dp_mst_atomic_best_encoder(struct drm_connector *connector, struct 
drm_atomic_commit *state)
 {
@@ -472,8 +510,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, struct msm_dp_link *link,
@@ -505,6 +551,7 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, struct 
msm_dp_link *link,
        }
 
        mutex_init(&mst->mst_lock);
+       mutex_init(&mst->hpd_irq_lock);
        dp_display->msm_dp_mst = mst;
        return 0;
 }
@@ -517,6 +564,7 @@ void msm_dp_mst_mgr_destroy(struct msm_dp *dp_display)
                return;
 
        drm_dp_mst_topology_mgr_destroy(&mst->mst_mgr);
+       mutex_destroy(&mst->hpd_irq_lock);
        mutex_destroy(&mst->mst_lock);
        dp_display->msm_dp_mst = NULL;
        kfree(mst);
diff --git a/drivers/gpu/drm/msm/dp/dp_mst_drm.h 
b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
index 822d34cd6ff5..3bd3e66b4eac 100644
--- a/drivers/gpu/drm/msm/dp/dp_mst_drm.h
+++ b/drivers/gpu/drm/msm/dp/dp_mst_drm.h
@@ -12,5 +12,6 @@ int msm_dp_mst_mgr_init(struct msm_dp *dp_display, struct 
msm_dp_link *link,
 void msm_dp_mst_mgr_destroy(struct msm_dp *dp_display);
 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