]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/hisilicon/hibmc: Enable this hot plug detect of irq feature
authorBaihan Li <libaihan@huawei.com>
Mon, 31 Mar 2025 07:42:10 +0000 (15:42 +0800)
committerDmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Fri, 11 Apr 2025 11:42:13 +0000 (14:42 +0300)
Add HPD interrupt enable functions in drm framework, and also add
detect_ctx functions. Because of the debouncing when HPD pulled out,
add 200 ms delay in detect. Add link reset process to reset link status
when a new connector pulgged in.

Signed-off-by: Baihan Li <libaihan@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Link: https://lore.kernel.org/r/20250331074212.3370287-8-shiyongbang@huawei.com
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
drivers/gpu/drm/hisilicon/hibmc/dp/dp_config.h
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h

index c5feef8dc27d1883efd24c064c143dc446dd1da1..08f9e1caf7fcbb16842a594498d8e94c2ae4781b 100644 (file)
@@ -16,5 +16,6 @@
 #define HIBMC_DP_SYNC_EN_MASK          0x3
 #define HIBMC_DP_LINK_RATE_CAL         27
 #define HIBMC_DP_SYNC_DELAY(lanes)     ((lanes) == 0x2 ? 86 : 46)
+#define HIBMC_DP_INT_ENABLE            0xc
 
 #endif
index ce7cb07815b22b654d85d76895dbd2819636e452..8f0daec7d174905ca7aa899e7f2201fc27846713 100644 (file)
@@ -189,6 +189,36 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp)
        return 0;
 }
 
+void hibmc_dp_enable_int(struct hibmc_dp *dp)
+{
+       struct hibmc_dp_dev *dp_dev = dp->dp_dev;
+
+       writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
+}
+
+void hibmc_dp_disable_int(struct hibmc_dp *dp)
+{
+       struct hibmc_dp_dev *dp_dev = dp->dp_dev;
+
+       writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
+       writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
+}
+
+void hibmc_dp_hpd_cfg(struct hibmc_dp *dp)
+{
+       struct hibmc_dp_dev *dp_dev = dp->dp_dev;
+
+       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_SYNC_LEN_SEL, 0x0);
+       hibmc_dp_reg_write_field(dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_TIMER_TIMEOUT, 0x1);
+       hibmc_dp_reg_write_field(dp->dp_dev, HIBMC_DP_AUX_REQ, HIBMC_DP_CFG_AUX_MIN_PULSE_NUM, 0x9);
+       writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
+       writel(0, dp_dev->base + HIBMC_DP_INTR_ENABLE);
+       writel(HIBMC_DP_INT_RST, dp_dev->base + HIBMC_DP_INTR_ORIGINAL_STATUS);
+       writel(HIBMC_DP_INT_ENABLE, dp_dev->base + HIBMC_DP_INTR_ENABLE);
+       writel(HIBMC_DP_DPTX_RST, dp_dev->base + HIBMC_DP_DPTX_RST_CTRL);
+       writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL);
+}
+
 void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable)
 {
        struct hibmc_dp_dev *dp_dev = dp->dp_dev;
@@ -227,6 +257,12 @@ int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode)
        return 0;
 }
 
+void hibmc_dp_reset_link(struct hibmc_dp *dp)
+{
+       dp->dp_dev->link.status.clock_recovered = false;
+       dp->dp_dev->link.status.channel_equalized = false;
+}
+
 static const struct hibmc_dp_color_raw g_rgb_raw[] = {
        {CBAR_COLOR_BAR, 0x000, 0x000, 0x000},
        {CBAR_WHITE,     0xfff, 0xfff, 0xfff},
index 83a53dae80120976540ccf033699fdf57226c019..665f5b166dfb5cf199e65cddc8d786d68d3b1d1a 100644 (file)
@@ -49,11 +49,16 @@ struct hibmc_dp {
        void __iomem *mmio;
        struct drm_dp_aux aux;
        struct hibmc_dp_cbar_cfg cfg;
+       u32 irq_status;
 };
 
 int hibmc_dp_hw_init(struct hibmc_dp *dp);
 int hibmc_dp_mode_set(struct hibmc_dp *dp, struct drm_display_mode *mode);
 void hibmc_dp_display_en(struct hibmc_dp *dp, bool enable);
 void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg);
+void hibmc_dp_reset_link(struct hibmc_dp *dp);
+void hibmc_dp_hpd_cfg(struct hibmc_dp *dp);
+void hibmc_dp_enable_int(struct hibmc_dp *dp);
+void hibmc_dp_disable_int(struct hibmc_dp *dp);
 
 #endif
index a86ecce4b3c14dc4563a932c00458631b91ccaef..d06832e62e966ef90059f357d5e8c854cb9346d1 100644 (file)
@@ -13,6 +13,8 @@
 #include "hibmc_drm_drv.h"
 #include "dp/dp_hw.h"
 
+#define DP_MASKED_SINK_HPD_PLUG_INT    BIT(2)
+
 static int hibmc_dp_connector_get_modes(struct drm_connector *connector)
 {
        const struct drm_edid *drm_edid;
@@ -29,14 +31,25 @@ static int hibmc_dp_connector_get_modes(struct drm_connector *connector)
        return count;
 }
 
+static int hibmc_dp_detect(struct drm_connector *connector,
+                          struct drm_modeset_acquire_ctx *ctx, bool force)
+{
+       mdelay(200);
+
+       return drm_connector_helper_detect_from_ddc(connector, ctx, force);
+}
+
 static const struct drm_connector_helper_funcs hibmc_dp_conn_helper_funcs = {
        .get_modes = hibmc_dp_connector_get_modes,
+       .detect_ctx = hibmc_dp_detect,
 };
 
 static int hibmc_dp_late_register(struct drm_connector *connector)
 {
        struct hibmc_dp *dp = to_hibmc_dp(connector);
 
+       hibmc_dp_enable_int(dp);
+
        return drm_dp_aux_register(&dp->aux);
 }
 
@@ -45,6 +58,8 @@ static void hibmc_dp_early_unregister(struct drm_connector *connector)
        struct hibmc_dp *dp = to_hibmc_dp(connector);
 
        drm_dp_aux_unregister(&dp->aux);
+
+       hibmc_dp_disable_int(dp);
 }
 
 static const struct drm_connector_funcs hibmc_dp_conn_funcs = {
@@ -96,6 +111,31 @@ static const struct drm_encoder_helper_funcs hibmc_dp_encoder_helper_funcs = {
        .atomic_disable = hibmc_dp_encoder_disable,
 };
 
+irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg)
+{
+       struct drm_device *dev = (struct drm_device *)arg;
+       struct hibmc_drm_private *priv = to_hibmc_drm_private(dev);
+       int idx;
+
+       if (!drm_dev_enter(dev, &idx))
+               return -ENODEV;
+
+       if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) {
+               drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n");
+               hibmc_dp_hpd_cfg(&priv->dp);
+       } else {
+               drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n");
+               hibmc_dp_reset_link(&priv->dp);
+       }
+
+       if (dev->registered)
+               drm_connector_helper_hpd_irq_event(&priv->dp.connector);
+
+       drm_dev_exit(idx);
+
+       return IRQ_HANDLED;
+}
+
 int hibmc_dp_init(struct hibmc_drm_private *priv)
 {
        struct drm_device *dev = &priv->dev;
@@ -136,5 +176,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv)
 
        drm_connector_attach_encoder(connector, encoder);
 
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
        return 0;
 }
index bc89e4b9f4e3ca45d1e3eb30a95555af1d5196b8..daed1330b961be0e4710f49a14ebab32905b73ea 100644 (file)
@@ -71,4 +71,6 @@ int hibmc_dp_init(struct hibmc_drm_private *priv);
 
 void hibmc_debugfs_init(struct drm_connector *connector, struct dentry *root);
 
+irqreturn_t hibmc_dp_hpd_isr(int irq, void *arg);
+
 #endif