[PATCH 20/22] drm/mediatek: add hpd debounce
flat view
STALE1664d
SUPERSEDED: 2 (0M)
From: Guillaume Ranquet <hidden>
Date: 2022-03-25 19:42:30
Also in:
dri-devel, linux-arm-kernel, linux-devicetree, linux-mediatek, linux-phy, lkml
Subsystem:
drm drivers, drm drivers for mediatek, the rest · Maintainers:
David Airlie, Simona Vetter, Chun-Kuang Hu, Philipp Zabel, Linus Torvalds
Revision v1 of 3 in this series; 2 review trailers.
Revisions (3)
- v1 current
- v1
- v10 [diff vs current]
From: Jitao Shi <redacted>
From the DP spec 1.4a chapter 3.3, upstream devices should implement
HPD signal de-bouncing on an external connection.
A period of 100ms should be used to detect an HPD connect event.
To cover these cases, HPD de-bounce should be implemented only after
HPD low has been detected for at least 100ms.
Therefore,
1. If HPD is low (which means plugging out) for longer than 100ms:
we need to do de-bouncing (which means we need to wait for 100ms).
2. If HPD low is for less than 100ms:
we don't need to care about the de-bouncing.
In this patch, we start a 100ms timer and use a need_debounce boolean
to implement the feature.
Two cases when HPD is high:
1. If the timer is expired (>100ms):
- need_debounce is true.
- When HPD high (plugging event comes), need_debounce will be true
and then we need to do de-bouncing (wait for 100ms).
2. If the timer is not expired (<100ms):
- need_debounce is false.
- When HPD high (plugging event comes), need_debounce will be false
and no need to do de-bouncing.
HPD_______ __________________
| |<- 100ms ->
|____________|
<- 100ms ->
Without HPD de-bouncing, USB-C to HDMI Adapaters will not be detected.
The change has been successfully tested with the following devices:
- Dell Adapter - USB-C to HDMI
- Acer 1in1 HDMI dongle
- Ugreen 1in1 HDMI dongle
- innowatt HDMI + USB3 hub
- Acer 2in1 HDMI dongle
- Apple 3in1 HDMI dongle (A2119)
- J5Create 3in1 HDMI dongle (JAC379)
Tested-by: Rex-BC Chen <redacted>
Reviewed-by: Rex-BC Chen <redacted>
Signed-off-by: Jitao Shi <redacted>
Signed-off-by: Guillaume Ranquet <redacted>
---
drivers/gpu/drm/mediatek/mtk_dp.c | 46 +++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index d9606c743a9e..4981a3a3b9ca 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c@@ -174,6 +174,33 @@ struct mtk_dp { struct device *codec_dev; u8 connector_eld[MAX_ELD_BYTES]; struct drm_connector *conn; + bool need_debounce; + struct timer_list debounce_timer; +}; + +enum mtk_dp_sdp_type { + MTK_DP_SDP_NONE = 0x00, + MTK_DP_SDP_ACM = 0x01, + MTK_DP_SDP_ISRC = 0x02, + MTK_DP_SDP_AVI = 0x03, + MTK_DP_SDP_AUI = 0x04, + MTK_DP_SDP_SPD = 0x05, + MTK_DP_SDP_MPEG = 0x06, + MTK_DP_SDP_NTSC = 0x07, + MTK_DP_SDP_VSP = 0x08, + MTK_DP_SDP_VSC = 0x09, + MTK_DP_SDP_EXT = 0x0A, + MTK_DP_SDP_PPS0 = 0x0B, + MTK_DP_SDP_PPS1 = 0x0C, + MTK_DP_SDP_PPS2 = 0x0D, + MTK_DP_SDP_PPS3 = 0x0E, + MTK_DP_SDP_DRM = 0x10, + MTK_DP_SDP_MAX_NUM +}; + +struct mtk_dp_sdp_packet { + enum mtk_dp_sdp_type type; + struct dp_sdp sdp; }; static bool mtk_dp_is_edp(struct mtk_dp *mtk_dp)
@@ -1814,6 +1841,9 @@ static irqreturn_t mtk_dp_hpd_event_thread(int hpd, void *dev) if (event < 0) return IRQ_HANDLED; + if (mtk_dp->need_debounce && mtk_dp->train_info.cable_plugged_in) + msleep(100); + if (mtk_dp->drm_dev) { dev_info(mtk_dp->dev, "drm_helper_hpd_irq_event\n"); drm_helper_hpd_irq_event(mtk_dp->bridge.dev);
@@ -1892,6 +1922,11 @@ static irqreturn_t mtk_dp_hpd_isr_handler(struct mtk_dp *mtk_dp) } train_info->cable_state_change = true; + if (!train_info->cable_plugged_in) { + mod_timer(&mtk_dp->debounce_timer, jiffies + msecs_to_jiffies(100) - 1); + mtk_dp->need_debounce = false; + } + return IRQ_WAKE_THREAD; }
@@ -2339,6 +2374,13 @@ static const struct drm_bridge_funcs mtk_dp_bridge_funcs = { .detect = mtk_dp_bdg_detect, }; +static void mtk_dp_debounce_timer(struct timer_list *t) +{ + struct mtk_dp *mtk_dp = from_timer(mtk_dp, t, debounce_timer); + + mtk_dp->need_debounce = true; +} + static int mtk_dp_probe(struct platform_device *pdev) { struct mtk_dp *mtk_dp;
@@ -2396,6 +2438,9 @@ static int mtk_dp_probe(struct platform_device *pdev) mtk_dp->bridge.of_node = dev->of_node; mtk_dp->bridge.type = DRM_MODE_CONNECTOR_eDP; + mtk_dp->need_debounce = true; + timer_setup(&mtk_dp->debounce_timer, mtk_dp_debounce_timer, 0); + mtk_dp->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_HPD; drm_bridge_add(&mtk_dp->bridge);
@@ -2415,6 +2460,7 @@ static int mtk_dp_remove(struct platform_device *pdev) struct mtk_dp *mtk_dp = platform_get_drvdata(pdev); mtk_dp_video_mute(mtk_dp, true); + del_timer_sync(&mtk_dp->debounce_timer); pm_runtime_disable(&pdev->dev);
--
2.34.1