]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
drm/vc4: hdmi: Add a workqueue to set scrambling
authorMaxime Ripard <maxime@cerno.tech>
Fri, 7 May 2021 15:05:14 +0000 (17:05 +0200)
committerMaxime Ripard <maxime@cerno.tech>
Mon, 24 May 2021 12:44:04 +0000 (14:44 +0200)
It looks like some displays (like the LG 27UL850-W) don't enable the
scrambling when the HDMI driver enables it. However, if we set later the
scrambler enable bit, the display will work as expected.

Let's create delayed work queue to periodically look at the display
scrambling status, and if it's not set yet try to enable it again.

Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210507150515.257424-12-maxime@cerno.tech
drivers/gpu/drm/vc4/vc4_hdmi.c
drivers/gpu/drm/vc4/vc4_hdmi.h

index f67c6f69fa281c380f0850cd37b887349f188040..015d1e9d4ffb81ff6e3c0d415d122b9feb088de9 100644 (file)
@@ -538,6 +538,8 @@ static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
        return true;
 }
 
+#define SCRAMBLING_POLLING_DELAY_MS    1000
+
 static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
 {
        struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
@@ -554,6 +556,9 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
 
        HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
                   VC5_HDMI_SCRAMBLER_CTL_ENABLE);
+
+       queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+                          msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
 }
 
 static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
@@ -572,6 +577,9 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
        if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
                return;
 
+       if (delayed_work_pending(&vc4_hdmi->scrambling_work))
+               cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
+
        HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
                   ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
 
@@ -579,6 +587,22 @@ static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
        drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
 }
 
+static void vc4_hdmi_scrambling_wq(struct work_struct *work)
+{
+       struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
+                                                struct vc4_hdmi,
+                                                scrambling_work);
+
+       if (drm_scdc_get_scrambling_status(vc4_hdmi->ddc))
+               return;
+
+       drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
+       drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
+
+       queue_delayed_work(system_wq, &vc4_hdmi->scrambling_work,
+                          msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+}
+
 static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
                                               struct drm_atomic_state *state)
 {
@@ -2087,6 +2111,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
        vc4_hdmi = devm_kzalloc(dev, sizeof(*vc4_hdmi), GFP_KERNEL);
        if (!vc4_hdmi)
                return -ENOMEM;
+       INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
 
        dev_set_drvdata(dev, vc4_hdmi);
        encoder = &vc4_hdmi->encoder.base.base;
index 089c91b3e14f8b841076d0e6861950f54e7bc325..39bd2c413ec043dc36cec25613ac761d018b4117 100644 (file)
@@ -129,6 +129,8 @@ struct vc4_hdmi {
        struct vc4_hdmi_encoder encoder;
        struct drm_connector connector;
 
+       struct delayed_work scrambling_work;
+
        struct i2c_adapter *ddc;
        void __iomem *hdmicore_regs;
        void __iomem *hd_regs;