1 From b1388530046be8a912979594f9c43b47d6f242fe Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Thu, 8 Oct 2020 16:06:58 +0200
4 Subject: [PATCH] drm/vc4: hdmi: Enable the scrambler
6 The HDMI controller on the BCM2711 includes a scrambler in order to
7 reach the HDMI 2.0 modes that require it. Let's add the support for it.
9 Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
10 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
12 drivers/gpu/drm/vc4/vc4_hdmi.c | 64 +++++++++++++++++++++++++++++
13 drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 3 ++
14 2 files changed, 67 insertions(+)
16 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
17 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
19 #include <drm/drm_edid.h>
20 #include <drm/drm_probe_helper.h>
21 #include <drm/drm_simple_kms_helper.h>
22 +#include <drm/drm_scdc_helper.h>
23 #include <linux/clk.h>
24 #include <linux/component.h>
25 #include <linux/i2c.h>
27 #define VC5_HDMI_VERTB_VSPO_SHIFT 16
28 #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
30 +#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0)
32 #define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8
33 #define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8)
35 @@ -518,6 +521,64 @@ static void vc4_hdmi_set_infoframes(stru
36 vc4_hdmi_set_hdr_infoframe(encoder);
39 +static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
40 + struct drm_display_mode *mode)
42 + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
43 + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
44 + struct drm_display_info *display = &vc4_hdmi->connector.display_info;
46 + if (!vc4_encoder->hdmi_monitor)
49 + if (!display->hdmi.scdc.supported ||
50 + !display->hdmi.scdc.scrambling.supported)
56 +static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
58 + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
59 + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
61 + if (!vc4_hdmi_supports_scrambling(encoder, mode))
64 + if (!vc4_hdmi_mode_needs_scrambling(mode))
67 + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
68 + drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
70 + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
71 + VC5_HDMI_SCRAMBLER_CTL_ENABLE);
74 +static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
76 + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
77 + struct drm_crtc *crtc = encoder->crtc;
80 + * At boot, encoder->crtc will be NULL. Since we don't know the
81 + * state of the scrambler and in order to avoid any
82 + * inconsistency, let's disable it all the time.
84 + if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
87 + if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
90 + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
91 + ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
93 + drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
94 + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
97 static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
98 struct drm_atomic_state *state)
100 @@ -530,6 +591,8 @@ static void vc4_hdmi_encoder_post_crtc_d
102 HDMI_WRITE(HDMI_VID_CTL,
103 HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
105 + vc4_hdmi_disable_scrambling(encoder);
108 static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
109 @@ -980,6 +1043,7 @@ static void vc4_hdmi_encoder_post_crtc_e
112 vc4_hdmi_recenter_fifo(vc4_hdmi);
113 + vc4_hdmi_enable_scrambling(encoder);
116 static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
117 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
118 +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
119 @@ -100,6 +100,7 @@ enum vc4_hdmi_field {
122 HDMI_SCHEDULER_CONTROL,
123 + HDMI_SCRAMBLER_CTL,
124 HDMI_SW_RESET_CONTROL,
125 HDMI_TX_PHY_CHANNEL_SWAP,
127 @@ -238,6 +239,7 @@ static const struct vc4_hdmi_register vc
128 VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
129 VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
130 VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
131 + VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
133 VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
134 VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),
135 @@ -317,6 +319,7 @@ static const struct vc4_hdmi_register vc
136 VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178),
137 VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c),
138 VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8),
139 + VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4),
141 VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
142 VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),