* [PATCH for drm-misc-fixes v3 0/2] Fix some bugs in the hibmc DP
@ 2026-09-24 8:06 Yongbang Shi
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status Yongbang Shi
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 2/2] drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver has been loaded Yongbang Shi
0 siblings, 2 replies; 4+ messages in thread
From: Yongbang Shi @ 2026-09-24 8:06 UTC (permalink / raw)
To: tzimmermann, dmitry.baryshkov, tiantao6, maarten.lankhorst,
mripard, airlied, daniel, kong.kongxinwei
Cc: liangjian010, shuliubin, chenjianmin, fengsheng5, shiyongbang,
helin52, shenjian15, shaojijie, dri-devel, linux-kernel
From: Lin He <helin52@huawei.com>
Fix some bugs in the hibmc DP driver.
---
ChangeLog:
v2 -> v3:
- Delete irq_status and use hpd_status directly for hotplug
detection. (sashiko-bot)
- Add debug logs when hpd_status is not HPD_IN in detect and
encoder_enable.
- Move hibmc_set_enable_flag() before drm_dev_register() and
hibmc_set_disable_flag() after drm_dev_unregister() to narrow the
race window. (sashiko-bot)
- Add spinlock_t gpio_lock to hibmc_drm_private to protect all
operations on 0x0802A4. (sashiko-bot)
v1 -> v2:
- More states in HIBMC_DP_HPD_STATUS are added to the
'hibmc_dp_get_hpd_status'.
- The call to `hibmc_set_enable_flag()` has been moved before
`drm_client_setup()`, specifically before the connector detection
triggers the I2C bit operation. (sashiko-bot)
- A read-modify-write operation has been implemented instead of directly
writing to prevent clearing the I2C mask bits. (sashiko-bot)
---
Lin He (2):
drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status
drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver
has been loaded
drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 1 -
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 32 +++++++++++------
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 5 +--
.../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 34 +++++++++++--------
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 32 ++++++++++++++++-
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 2 ++
.../gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c | 19 +++++++++--
.../gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 3 ++
8 files changed, 96 insertions(+), 32 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status
2026-09-24 8:06 [PATCH for drm-misc-fixes v3 0/2] Fix some bugs in the hibmc DP Yongbang Shi
@ 2026-09-24 8:06 ` Yongbang Shi
2026-09-24 8:30 ` sashiko-bot
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 2/2] drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver has been loaded Yongbang Shi
1 sibling, 1 reply; 4+ messages in thread
From: Yongbang Shi @ 2026-09-24 8:06 UTC (permalink / raw)
To: tzimmermann, dmitry.baryshkov, tiantao6, maarten.lankhorst,
mripard, airlied, daniel, kong.kongxinwei
Cc: liangjian010, shuliubin, chenjianmin, fengsheng5, shiyongbang,
helin52, shenjian15, shaojijie, dri-devel, linux-kernel
From: Lin He <helin52@huawei.com>
To more accurately determine whether the current HPD status matches the
interrupt status, the polling mechanism in the lower half of the HPD
interrupt (via hibmc_dp_check_hpd_status) has been replaced with directly
retrieving the interrupt status in the upper half of the interrupt (via
hibmc_dp_get_hpd_status).
* Detection and training are not performed if hpd_status is not HPD_IN.
* Set the initial status of hpd_status to HPD_OUT.
Fixes: 3906e7a3b26d ("drm/hisilicon/hibmc: fix dp probabilistical detect errors after HPD irq")
Signed-off-by: Lin He <helin52@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
---
ChangeLog:
v2 -> v3:
- Delete irq_status and use hpd_status directly for hotplug
detection. (sashiko-bot)
- Add debug logs when hpd_status is not HPD_IN in detect and
encoder_enable.
v1 -> v2:
- More states in HIBMC_DP_HPD_STATUS are added to the
'hibmc_dp_get_hpd_status'.
---
drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h | 1 -
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c | 32 +++++++++++------
drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h | 5 +--
.../gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c | 34 +++++++++++--------
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 2 +-
5 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h
index f53dac256ee0..b0e258b9265e 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_comm.h
@@ -43,7 +43,6 @@ struct hibmc_dp_dev {
u8 downstream_ports[DP_MAX_DOWNSTREAM_PORTS];
struct drm_dp_desc desc;
bool is_branch;
- int hpd_status;
void __iomem *serdes_base;
};
diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
index d5bd3c45649b..a4cd4cd8cc75 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
@@ -191,6 +191,10 @@ int hibmc_dp_hw_init(struct hibmc_dp *dp)
writel(HIBMC_DP_HDCP, dp_dev->base + HIBMC_DP_HDCP_CFG);
/* clock enable */
writel(HIBMC_DP_CLK_EN, dp_dev->base + HIBMC_DP_DPTX_CLK_CTRL);
+ /* To latch the HPD interrupt, ensuring that DP can support more modes
+ * within the fbcon framework when connected alone.
+ */
+ msleep(100);
return 0;
}
@@ -322,20 +326,26 @@ void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg)
writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
}
-bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status)
+int hibmc_dp_get_hpd_status(struct hibmc_dp *dp)
{
+ int hpd_status = HIBMC_HPD_UNKNOWN;
u32 status;
- int ret;
- ret = readl_poll_timeout(dp->dp_dev->base + HIBMC_DP_HPD_STATUS, status,
- FIELD_GET(HIBMC_DP_HPD_CUR_STATE, status) == exp_status,
- 1000, 100000); /* DP spec says 100ms */
- if (ret) {
- drm_dbg_dp(dp->drm_dev, "wait hpd status timeout");
- return false;
+ status = FIELD_GET(HIBMC_DP_HPD_CUR_STATE,
+ readl(dp->dp_dev->base + HIBMC_DP_HPD_STATUS));
+ switch (status) {
+ case 0: /* idle */
+ case 3: /* unplug */
+ case 4: /* unplug intermediate */
+ hpd_status = HIBMC_HPD_OUT;
+ break;
+ case 1: /* plug */
+ case 2: /* plug intermediate */
+ hpd_status = HIBMC_HPD_IN;
+ break;
+ default:
+ break;
}
- dp->dp_dev->hpd_status = exp_status;
-
- return true;
+ return hpd_status;
}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h
index 0f3662d8737e..959bf95f6fe5 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.h
@@ -15,6 +15,7 @@
struct hibmc_dp_dev;
enum hibmc_hpd_status {
+ HIBMC_HPD_UNKNOWN,
HIBMC_HPD_OUT,
HIBMC_HPD_IN,
};
@@ -54,7 +55,7 @@ struct hibmc_dp {
void __iomem *mmio;
struct drm_dp_aux aux;
struct hibmc_dp_cbar_cfg cfg;
- u32 irq_status;
+ int hpd_status;
int phys_status;
};
@@ -66,7 +67,7 @@ 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);
-bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status);
+int hibmc_dp_get_hpd_status(struct hibmc_dp *dp);
u8 hibmc_dp_get_link_rate(struct hibmc_dp *dp);
u8 hibmc_dp_get_lanes(struct hibmc_dp *dp);
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
index 2e9403b8bf3c..1f8ea0b09253 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
@@ -15,8 +15,6 @@
#include "dp/dp_comm.h"
#include "dp/dp_config.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;
@@ -63,11 +61,10 @@ static int hibmc_dp_detect(struct drm_connector *connector,
struct hibmc_dp_dev *dp_dev = dp->dp_dev;
int ret = connector_status_disconnected;
- if (dp->irq_status) {
- if (dp_dev->hpd_status != HIBMC_HPD_IN) {
- ret = connector_status_disconnected;
- goto exit;
- }
+ if (dp->hpd_status != HIBMC_HPD_IN) {
+ drm_dbg_dp(dp->drm_dev, "dp detect skipped, hpd (%d)\n",
+ dp->hpd_status);
+ goto exit;
}
if (!hibmc_dp_get_dpcd(dp_dev)) {
@@ -166,6 +163,12 @@ static void hibmc_dp_encoder_enable(struct drm_encoder *drm_encoder,
struct hibmc_dp *dp = container_of(drm_encoder, struct hibmc_dp, encoder);
struct drm_display_mode *mode = &drm_encoder->crtc->state->mode;
+ if (dp->hpd_status != HIBMC_HPD_IN) {
+ drm_dbg_dp(dp->drm_dev, "dp encoder enable skipped, hpd (%d)\n",
+ dp->hpd_status);
+ return;
+ }
+
if (hibmc_dp_prepare(dp, mode))
return;
@@ -189,24 +192,26 @@ 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, exp_status;
+ int status = priv->dp.hpd_status;
+ int idx;
if (!drm_dev_enter(dev, &idx))
return -ENODEV;
- if (priv->dp.irq_status & DP_MASKED_SINK_HPD_PLUG_INT) {
+ if (status == HIBMC_HPD_IN) {
drm_dbg_dp(&priv->dev, "HPD IN isr occur!\n");
hibmc_dp_hpd_cfg(&priv->dp);
- exp_status = HIBMC_HPD_IN;
- } else {
+ } else if (status == HIBMC_HPD_OUT) {
drm_dbg_dp(&priv->dev, "HPD OUT isr occur!\n");
hibmc_dp_reset_link(&priv->dp);
- exp_status = HIBMC_HPD_OUT;
+ } else {
+ drm_err(&priv->dev, "HPD status (%d) error\n", status);
+ goto exit;
}
- if (hibmc_dp_check_hpd_status(&priv->dp, exp_status))
- drm_connector_helper_hpd_irq_event(&priv->dp.connector);
+ drm_connector_helper_hpd_irq_event(&priv->dp.connector);
+exit:
drm_dev_exit(idx);
return IRQ_HANDLED;
@@ -223,6 +228,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv)
dp->mmio = priv->mmio;
dp->drm_dev = dev;
+ dp->hpd_status = HIBMC_HPD_OUT;
ret = hibmc_dp_hw_init(&priv->dp);
if (ret) {
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4d85c89f3f88..4ab0e565cb13 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -62,7 +62,7 @@ static irqreturn_t hibmc_dp_interrupt(int irq, void *arg)
status = readl(priv->mmio + HIBMC_DP_INTSTAT);
if (status) {
- priv->dp.irq_status = status;
+ priv->dp.hpd_status = hibmc_dp_get_hpd_status(&priv->dp);
writel(status, priv->mmio + HIBMC_DP_INTCLR);
return IRQ_WAKE_THREAD;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH for drm-misc-fixes v3 2/2] drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver has been loaded
2026-09-24 8:06 [PATCH for drm-misc-fixes v3 0/2] Fix some bugs in the hibmc DP Yongbang Shi
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status Yongbang Shi
@ 2026-09-24 8:06 ` Yongbang Shi
1 sibling, 0 replies; 4+ messages in thread
From: Yongbang Shi @ 2026-09-24 8:06 UTC (permalink / raw)
To: tzimmermann, dmitry.baryshkov, tiantao6, maarten.lankhorst,
mripard, airlied, daniel, kong.kongxinwei
Cc: liangjian010, shuliubin, chenjianmin, fengsheng5, shiyongbang,
helin52, shenjian15, shaojijie, dri-devel, linux-kernel
From: Lin He <helin52@huawei.com>
Add a flag to indicate whether the OS-side driver has been loaded to
prevent the BMC from enabling DP if the driver is not loaded, which could
lead to system failure in handling interrupts and generate error messages
like:
irq xx: nobody cared (try booting with the "irqpoll" option)
...
Call Trace:
<TRQ>
...
Fixes: 0ab6ea261c1f ("drm/hisilicon/hibmc: add dp module in hibmc")
Signed-off-by: Lin He <helin52@huawei.com>
Signed-off-by: Yongbang Shi <shiyongbang@huawei.com>
---
ChangeLog:
v2 -> v3:
- Move hibmc_set_enable_flag() before drm_dev_register() and
hibmc_set_disable_flag() after drm_dev_unregister() to narrow the
race window. (sashiko-bot)
- Add spinlock_t gpio_lock to hibmc_drm_private to protect all
operations on 0x0802A4. (sashiko-bot)
v1 -> v2:
- The call to `hibmc_set_enable_flag()` has been moved before
`drm_client_setup()`, specifically before the connector detection
triggers the I2C bit operation. (sashiko-bot)
- A read-modify-write operation has been implemented instead of directly
writing to prevent clearing the I2C mask bits. (sashiko-bot)
---
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 30 +++++++++++++++++++
.../gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 2 ++
.../gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c | 19 ++++++++++--
.../gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 3 ++
4 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
index 4ab0e565cb13..9859492da5fa 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
@@ -167,6 +167,8 @@ static int hibmc_kms_init(struct hibmc_drm_private *priv)
if (ret)
return ret;
+ spin_lock_init(&priv->gpio_lock);
+
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
dev->mode_config.max_width = 1920;
@@ -423,6 +425,30 @@ static int hibmc_load(struct drm_device *dev)
return ret;
}
+static inline void hibmc_set_enable_flag(struct hibmc_drm_private *priv)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ value = readl(priv->mmio + HIBMC_ENABLE_FLAG);
+ value |= HIBMC_ENABLE_STATE;
+ writel(value, priv->mmio + HIBMC_ENABLE_FLAG);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
+static inline void hibmc_set_disable_flag(struct hibmc_drm_private *priv)
+{
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ value = readl(priv->mmio + HIBMC_ENABLE_FLAG);
+ value &= ~HIBMC_ENABLE_STATE;
+ writel(value, priv->mmio + HIBMC_ENABLE_FLAG);
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+}
+
static int hibmc_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
@@ -458,6 +484,8 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
goto err_return;
}
+ hibmc_set_enable_flag(priv);
+
ret = drm_dev_register(dev, 0);
if (ret) {
drm_err(dev, "failed to register drv for userspace access: %d\n",
@@ -470,6 +498,7 @@ static int hibmc_pci_probe(struct pci_dev *pdev,
return 0;
err_unload:
+ hibmc_set_disable_flag(to_hibmc_drm_private(dev));
hibmc_unload(dev);
err_return:
return ret;
@@ -480,6 +509,7 @@ static void hibmc_pci_remove(struct pci_dev *pdev)
struct drm_device *dev = pci_get_drvdata(pdev);
drm_dev_unregister(dev);
+ hibmc_set_disable_flag(to_hibmc_drm_private(dev));
hibmc_unload(dev);
}
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
index dce8572bf63e..c2a82000ea7f 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
@@ -49,6 +49,8 @@ struct hibmc_drm_private {
struct drm_crtc crtc;
struct hibmc_vdac vdac;
struct hibmc_dp dp;
+
+ spinlock_t gpio_lock; /* protects RMW on I2C/ENABLE_FLAG (0x0802A4) */
};
static inline struct hibmc_vdac *to_hibmc_vdac(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
index 44860011855e..4ceb87efec05 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_i2c.c
@@ -27,7 +27,11 @@ static void hibmc_set_i2c_signal(void *data, u32 mask, int value)
{
struct hibmc_vdac *vdac = data;
struct hibmc_drm_private *priv = to_hibmc_drm_private(vdac->connector.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
+ unsigned long flags;
+ u32 tmp_dir;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
if (value) {
tmp_dir &= ~mask;
@@ -41,20 +45,29 @@ static void hibmc_set_i2c_signal(void *data, u32 mask, int value)
tmp_dir |= mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
}
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
}
static int hibmc_get_i2c_signal(void *data, u32 mask)
{
struct hibmc_vdac *vdac = data;
struct hibmc_drm_private *priv = to_hibmc_drm_private(vdac->connector.dev);
- u32 tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
+ unsigned long flags;
+ u32 tmp_dir;
+ int ret;
+
+ spin_lock_irqsave(&priv->gpio_lock, flags);
+ tmp_dir = readl(priv->mmio + GPIO_DATA_DIRECTION);
if ((tmp_dir & mask) != mask) {
tmp_dir &= ~mask;
writel(tmp_dir, priv->mmio + GPIO_DATA_DIRECTION);
}
- return (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
+ ret = (readl(priv->mmio + GPIO_DATA) & mask) ? 1 : 0;
+ spin_unlock_irqrestore(&priv->gpio_lock, flags);
+
+ return ret;
}
static void hibmc_ddc_setsda(void *data, int state)
diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
index 17b30c393b10..b95add5b253c 100644
--- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
+++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
@@ -200,5 +200,8 @@
#define HIBMC_CRT_PALETTE 0x80C00
+#define HIBMC_ENABLE_FLAG 0x802A4
+#define HIBMC_ENABLE_STATE BIT(2)
+
#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
#endif
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status Yongbang Shi
@ 2026-09-24 8:30 ` sashiko-bot
0 siblings, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-09-24 8:30 UTC (permalink / raw)
To: Yongbang Shi; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] drm/hisilicon: Hardcoded initial HPD_OUT state breaks boot display detection
- [High] drm/hisilicon: Removal of HPD debounce causes DPCD read failures on hotplug
- [Medium] drm/hisilicon: Early exit in encoder_enable breaks KMS forced modesets
- [Low] drm/hisilicon: Data race on dp->hpd_status between hardirq and process contexts
--
commit 19dc442443127128a0c2f9bcb0ceca722bb81f14
Author: Lin He <helin52@huawei.com>
drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status
This commit replaces the polling mechanism in the lower half of the HPD
interrupt with a direct read of the interrupt status in the upper half.
It also skips detection and training if the status is not HPD_IN, and
initializes the state to HPD_OUT.
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
> index d5bd3c45649b2..a4cd4cd8cc75e 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/dp/dp_hw.c
[ ... ]
> @@ -322,20 +326,26 @@ void hibmc_dp_set_cbar(struct hibmc_dp *dp, const struct hibmc_dp_cbar_cfg *cfg)
> writel(HIBMC_DP_SYNC_EN_MASK, dp_dev->base + HIBMC_DP_TIMING_SYNC_CTRL);
> }
>
> -bool hibmc_dp_check_hpd_status(struct hibmc_dp *dp, int exp_status)
> +int hibmc_dp_get_hpd_status(struct hibmc_dp *dp)
> {
> + int hpd_status = HIBMC_HPD_UNKNOWN;
> u32 status;
> - int ret;
>
> - ret = readl_poll_timeout(dp->dp_dev->base + HIBMC_DP_HPD_STATUS, status,
> - FIELD_GET(HIBMC_DP_HPD_CUR_STATE, status) == exp_status,
> - 1000, 100000); /* DP spec says 100ms */
> - if (ret) {
> - drm_dbg_dp(dp->drm_dev, "wait hpd status timeout");
> - return false;
> + status = FIELD_GET(HIBMC_DP_HPD_CUR_STATE,
> + readl(dp->dp_dev->base + HIBMC_DP_HPD_STATUS));
> + switch (status) {
> + case 0: /* idle */
> + case 3: /* unplug */
> + case 4: /* unplug intermediate */
> + hpd_status = HIBMC_HPD_OUT;
> + break;
> + case 1: /* plug */
> + case 2: /* plug intermediate */
> + hpd_status = HIBMC_HPD_IN;
[Severity: High]
Does mapping the 'plug intermediate' state (value 2) directly to HIBMC_HPD_IN
without the previous 100ms debounce loop cause DPCD read failures?
When the link is physically bouncing during a hotplug event, returning
HIBMC_HPD_IN immediately schedules hibmc_dp_detect(). The immediate AUX
transaction in hibmc_dp_get_dpcd() can then fail because the connection has
not stabilized, causing the hotplug event to be dropped.
> + break;
> + default:
> + break;
> }
>
> - dp->dp_dev->hpd_status = exp_status;
> -
> - return true;
> }
> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
> index 2e9403b8bf3c8..1f8ea0b092537 100644
> --- a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_dp.c
[ ... ]
> @@ -63,11 +61,10 @@ static int hibmc_dp_detect(struct drm_connector *connector,
> struct hibmc_dp_dev *dp_dev = dp->dp_dev;
> int ret = connector_status_disconnected;
>
> - if (dp->irq_status) {
> - if (dp_dev->hpd_status != HIBMC_HPD_IN) {
> - ret = connector_status_disconnected;
> - goto exit;
> - }
> + if (dp->hpd_status != HIBMC_HPD_IN) {
[Severity: Low]
Is there a theoretical data race here when reading dp->hpd_status?
It appears to be modified in hardirq context by hibmc_dp_interrupt() and read
here in process context without WRITE_ONCE()/READ_ONCE() annotations or
locking.
> + drm_dbg_dp(dp->drm_dev, "dp detect skipped, hpd (%d)\n",
> + dp->hpd_status);
> + goto exit;
> }
>
> if (!hibmc_dp_get_dpcd(dp_dev)) {
[ ... ]
> @@ -166,6 +163,12 @@ static void hibmc_dp_encoder_enable(struct drm_encoder *drm_encoder,
> struct hibmc_dp *dp = container_of(drm_encoder, struct hibmc_dp, encoder);
> struct drm_display_mode *mode = &drm_encoder->crtc->state->mode;
>
> + if (dp->hpd_status != HIBMC_HPD_IN) {
[Severity: Medium]
Does this early exit break KMS forced modesets?
If a user overrides the connector to 'connected' (e.g., via sysfs or kernel
command line) and the DRM core attempts an atomic commit, this check will
refuse to program the hardware. This would desynchronize the KMS software
state from the actual hardware state.
> + drm_dbg_dp(dp->drm_dev, "dp encoder enable skipped, hpd (%d)\n",
> + dp->hpd_status);
> + return;
> + }
> +
> if (hibmc_dp_prepare(dp, mode))
> return;
[ ... ]
> @@ -223,6 +228,7 @@ int hibmc_dp_init(struct hibmc_drm_private *priv)
>
> dp->mmio = priv->mmio;
> dp->drm_dev = dev;
> + dp->hpd_status = HIBMC_HPD_OUT;
[Severity: High]
Will hardcoding the initial state to HIBMC_HPD_OUT break display detection
at boot?
During boot, drm_client_setup() runs detect() before or immediately after
interrupts are enabled in late_register(). Because detect() no longer queries
the live hardware register and relies only on this cached value, it will read
HPD_OUT and silently force a disconnected state even if a monitor is already
connected.
>
> ret = hibmc_dp_hw_init(&priv->dp);
> if (ret) {
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260924080609.3681795-1-shiyongbang@huawei.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-24 8:30 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-24 8:06 [PATCH for drm-misc-fixes v3 0/2] Fix some bugs in the hibmc DP Yongbang Shi
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 1/2] drm/hisilicon/hibmc: Modify the method of obtaining the hpd_status Yongbang Shi
2026-09-24 8:30 ` sashiko-bot
2026-09-24 8:06 ` [PATCH for drm-misc-fixes v3 2/2] drm/hisilicon/hibmc: Add a flag to indicate whether the OS-side driver has been loaded Yongbang Shi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox