]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/bridge: dw-hdmi-qp: Fix spurious IRQ on resume
authorSebastian Reichel <sebastian.reichel@collabora.com>
Tue, 14 Oct 2025 16:00:57 +0000 (18:00 +0200)
committerHeiko Stuebner <heiko@sntech.de>
Wed, 7 Jan 2026 12:20:13 +0000 (13:20 +0100)
After resume from suspend to RAM, the following splash is generated if
the HDMI driver is probed (independent of a connected cable):

[ 1194.484052] irq 80: nobody cared (try booting with the "irqpoll" option)
[ 1194.484074] CPU: 0 UID: 0 PID: 627 Comm: rtcwake Not tainted 6.17.0-rc7-g96f1a11414b3 #1 PREEMPT
[ 1194.484082] Hardware name: Rockchip RK3576 EVB V10 Board (DT)
[ 1194.484085] Call trace:
[ 1194.484087]  ... (stripped)
[ 1194.484283] handlers:
[ 1194.484285] [<00000000bc363dcb>] dw_hdmi_qp_main_hardirq [dw_hdmi_qp]
[ 1194.484302] Disabling IRQ #80

Apparently the HDMI IP is losing part of its state while the system
is suspended and generates spurious interrupts during resume. The
bug has not yet been noticed, as system suspend does not yet work
properly on upstream kernel with either the Rockchip RK3588 or RK3576
platform.

Fixes: 128a9bf8ace2 ("drm/rockchip: Add basic RK3588 HDMI output support")
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Reviewed-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Link: https://patch.msgid.link/20251014-rockchip-hdmi-suspend-fix-v1-1-983fcbf44839@collabora.com
drivers/gpu/drm/bridge/synopsys/dw-hdmi-qp.c
drivers/gpu/drm/rockchip/dw_hdmi_qp-rockchip.c
include/drm/bridge/dw_hdmi_qp.h

index fe4c026280f03465de178dfbefbdd3cf468988db..60166919c5b548239c5deb07a601e31519153d84 100644 (file)
@@ -163,6 +163,7 @@ struct dw_hdmi_qp {
 
        unsigned long ref_clk_rate;
        struct regmap *regm;
+       int main_irq;
 
        unsigned long tmds_char_rate;
 };
@@ -1271,6 +1272,7 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 
        dw_hdmi_qp_init_hw(hdmi);
 
+       hdmi->main_irq = plat_data->main_irq;
        ret = devm_request_threaded_irq(dev, plat_data->main_irq,
                                        dw_hdmi_qp_main_hardirq, NULL,
                                        IRQF_SHARED, dev_name(dev), hdmi);
@@ -1331,9 +1333,16 @@ struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_qp_bind);
 
+void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi)
+{
+       disable_irq(hdmi->main_irq);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_qp_suspend);
+
 void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi)
 {
        dw_hdmi_qp_init_hw(hdmi);
+       enable_irq(hdmi->main_irq);
 }
 EXPORT_SYMBOL_GPL(dw_hdmi_qp_resume);
 
index c9fe6aa3e3e3606086b1cedf38dc1318eb3daf26..6e39e8a007749d2853e7a852ae67ac317557ec35 100644 (file)
@@ -640,6 +640,15 @@ static void dw_hdmi_qp_rockchip_remove(struct platform_device *pdev)
        component_del(&pdev->dev, &dw_hdmi_qp_rockchip_ops);
 }
 
+static int __maybe_unused dw_hdmi_qp_rockchip_suspend(struct device *dev)
+{
+       struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
+
+       dw_hdmi_qp_suspend(dev, hdmi->hdmi);
+
+       return 0;
+}
+
 static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
 {
        struct rockchip_hdmi_qp *hdmi = dev_get_drvdata(dev);
@@ -655,7 +664,8 @@ static int __maybe_unused dw_hdmi_qp_rockchip_resume(struct device *dev)
 }
 
 static const struct dev_pm_ops dw_hdmi_qp_rockchip_pm = {
-       SET_SYSTEM_SLEEP_PM_OPS(NULL, dw_hdmi_qp_rockchip_resume)
+       SET_SYSTEM_SLEEP_PM_OPS(dw_hdmi_qp_rockchip_suspend,
+                               dw_hdmi_qp_rockchip_resume)
 };
 
 struct platform_driver dw_hdmi_qp_rockchip_pltfm_driver = {
index 3f461f6b9bbfbf67934bf642452d3c6f9253c4f9..3af12f82da2c1bd81968360bab965cb2810e7f0b 100644 (file)
@@ -34,5 +34,6 @@ struct dw_hdmi_qp_plat_data {
 struct dw_hdmi_qp *dw_hdmi_qp_bind(struct platform_device *pdev,
                                   struct drm_encoder *encoder,
                                   const struct dw_hdmi_qp_plat_data *plat_data);
+void dw_hdmi_qp_suspend(struct device *dev, struct dw_hdmi_qp *hdmi);
 void dw_hdmi_qp_resume(struct device *dev, struct dw_hdmi_qp *hdmi);
 #endif /* __DW_HDMI_QP__ */