]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/hisilicon/hibmc: fix no showing when no connectors connected
authorLin He <helin52@huawei.com>
Sat, 9 May 2026 03:23:00 +0000 (11:23 +0800)
committerThomas Zimmermann <tzimmermann@suse.de>
Wed, 13 May 2026 06:54:28 +0000 (08:54 +0200)
Our chip support KVM over IP feature, so hibmc driver need to support
displaying without any connectors plugged in. If no connectors are
connected, the vdac connector status should be set to 'connected' to
ensure proper KVM display functionality. Additionally, for
previous-generation products that may lack hardware link support and
thus cannot detect the monitor, the same approach should be applied
to ensure VGA display functionality.

* Add phys_state in the struct of dp and vdac to check physical outputs.

* The 'epoch_counter' of the vdac connector is incremented when the
physical status changes.

For get_modes: using BMC modes for connector if no display is attached to
phys VGA cable, otherwise use EDID modes by drm_connector_helper_get_modes,
because KVM doesn't provide EDID reads.

The polling mechanism for the KMS helper is enabled.

Fixes: 4c962bc929f1 ("drm/hisilicon/hibmc: Add vga connector detect functions")
Reported-by: Thomas Zimmermann <tzimmermann@suse.de>
Closes: https://lore.kernel.org/all/0eb5c509-2724-4c57-87ad-74e4270d5a5a@suse.de/
Signed-off-by: Lin He <helin52@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Tested-by: Thomas Zimmermann <tzimmermann@suse.de>
Signed-off-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patch.msgid.link/20260509032302.2057227-3-shiyongbang@huawei.com
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.c
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c

index 31316fe1ea8dbfea6fae0b8f3c6f18ac4ed1820d..0f3662d8737e994accfdd4bac0fa35464dc1b2ad 100644 (file)
@@ -55,6 +55,7 @@ struct hibmc_dp {
        struct drm_dp_aux aux;
        struct hibmc_dp_cbar_cfg cfg;
        u32 irq_status;
+       int phys_status;
 };
 
 int hibmc_dp_hw_init(struct hibmc_dp *dp);
index 5b9dedfbbdfc8e19650c90aac0e0d1bd70e492a2..2e9403b8bf3c8a66192ec6e70f75fd5781f3c1f9 100644 (file)
@@ -61,27 +61,38 @@ static int hibmc_dp_detect(struct drm_connector *connector,
 {
        struct hibmc_dp *dp = to_hibmc_dp(connector);
        struct hibmc_dp_dev *dp_dev = dp->dp_dev;
-       int ret;
+       int ret = connector_status_disconnected;
 
        if (dp->irq_status) {
-               if (dp_dev->hpd_status != HIBMC_HPD_IN)
-                       return connector_status_disconnected;
+               if (dp_dev->hpd_status != HIBMC_HPD_IN) {
+                       ret = connector_status_disconnected;
+                       goto exit;
+               }
        }
 
-       if (!hibmc_dp_get_dpcd(dp_dev))
-               return connector_status_disconnected;
+       if (!hibmc_dp_get_dpcd(dp_dev)) {
+               ret = connector_status_disconnected;
+               goto exit;
+       }
 
-       if (!dp_dev->is_branch)
-               return connector_status_connected;
+       if (!dp_dev->is_branch) {
+               ret = connector_status_connected;
+               goto exit;
+       }
 
        if (drm_dp_read_sink_count_cap(connector, dp_dev->dpcd, &dp_dev->desc) &&
            dp_dev->downstream_ports[0] & DP_DS_PORT_HPD) {
                ret = drm_dp_read_sink_count(dp_dev->aux);
-               if (ret > 0)
-                       return connector_status_connected;
+               if (ret > 0) {
+                       ret = connector_status_connected;
+                       goto exit;
+               }
        }
 
-       return connector_status_disconnected;
+exit:
+       dp->phys_status = ret;
+
+       return ret;
 }
 
 static int hibmc_dp_mode_valid(struct drm_connector *connector,
@@ -243,5 +254,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv)
 
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
+       dp->phys_status = connector_status_disconnected;
+
        return 0;
 }
index 289304500ab097bc9e53917dcde3328bfc6da7c1..481e5e62c30bf116608806176ec8ee9b8ed80978 100644 (file)
@@ -24,6 +24,7 @@
 #include <drm/drm_managed.h>
 #include <drm/drm_module.h>
 #include <drm/drm_vblank.h>
+#include <drm/drm_probe_helper.h>
 
 #include "hibmc_drm_drv.h"
 #include "hibmc_drm_regs.h"
@@ -355,6 +356,8 @@ static int hibmc_load(struct drm_device *dev)
        /* reset all the states of crtc/plane/encoder/connector */
        drm_mode_config_reset(dev);
 
+       drmm_kms_helper_poll_init(dev);
+
        return 0;
 
 err:
index ca8502e2760c1222faf82fa77975c5dddcf40efc..cd3a3fca1fe60a247b985ada8dd6029d60b146b6 100644 (file)
@@ -31,6 +31,7 @@ struct hibmc_vdac {
        struct drm_connector connector;
        struct i2c_adapter adapter;
        struct i2c_algo_bit_data bit_data;
+       int phys_status;
 };
 
 struct hibmc_drm_private {
index 841e81f47b68620d63fa7a33ce2d908129d74bab..2fcfa3246fd1247b1fad5ff83575d59c7fd1d6b1 100644 (file)
 
 static int hibmc_connector_get_modes(struct drm_connector *connector)
 {
+       struct drm_mode_config *mode_config = &connector->dev->mode_config;
        struct hibmc_vdac *vdac = to_hibmc_vdac(connector);
-       const struct drm_edid *drm_edid;
        int count;
 
-       drm_edid = drm_edid_read_ddc(connector, &vdac->adapter);
-
-       drm_edid_connector_update(connector, drm_edid);
-
-       if (drm_edid) {
-               count = drm_edid_connector_add_modes(connector);
+       if (vdac->phys_status == connector_status_connected) {
+               count = drm_connector_helper_get_modes(connector);
+       } else {
+               drm_edid_connector_update(connector, NULL);
+               count = drm_add_modes_noedid(connector,
+                                            mode_config->max_width,
+                                            mode_config->max_height);
                if (count)
-                       goto out;
+                       drm_set_preferred_mode(connector, 1024, 768);
        }
 
-       count = drm_add_modes_noedid(connector,
-                                    connector->dev->mode_config.max_width,
-                                    connector->dev->mode_config.max_height);
-       drm_set_preferred_mode(connector, 1024, 768);
-
-out:
-       drm_edid_free(drm_edid);
-
        return count;
 }
 
@@ -57,10 +50,34 @@ static void hibmc_connector_destroy(struct drm_connector *connector)
        drm_connector_cleanup(connector);
 }
 
+static int hibmc_vdac_detect(struct drm_connector *connector,
+                            struct drm_modeset_acquire_ctx *ctx,
+                            bool force)
+{
+       struct hibmc_drm_private *priv = to_hibmc_drm_private(connector->dev);
+       int status = drm_connector_helper_detect_from_ddc(connector, ctx,
+                                                        force);
+       struct hibmc_vdac *vdac = to_hibmc_vdac(connector);
+
+       if (priv->dp.phys_status == connector_status_connected) {
+               vdac->phys_status = status;
+               return status;
+       }
+
+       if (status != vdac->phys_status)
+               ++connector->epoch_counter;
+       vdac->phys_status = status;
+
+       /* When both the DP and VDAC physical status are disconnected,
+        * the "connected" status is returned to support KVM display.
+        */
+       return connector_status_connected;
+}
+
 static const struct drm_connector_helper_funcs
        hibmc_connector_helper_funcs = {
        .get_modes = hibmc_connector_get_modes,
-       .detect_ctx = drm_connector_helper_detect_from_ddc,
+       .detect_ctx = hibmc_vdac_detect,
 };
 
 static const struct drm_connector_funcs hibmc_connector_funcs = {
@@ -130,6 +147,8 @@ int hibmc_vdac_init(struct hibmc_drm_private *priv)
 
        connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
 
+       vdac->phys_status = connector_status_disconnected;
+
        return 0;
 
 err: