0b00614ab8b23f2a9e0a89bb28b47383c9c9d335
[openwrt/staging/jow.git] / target / linux / bcm27xx / patches-5.10 / 950-0575-drm-vc4-hdmi-Enable-the-scrambler.patch
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
5
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.
8
9 Acked-by: Thomas Zimmermann <tzimmermann@suse.de>
10 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
11 ---
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(+)
15
16 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
17 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
18 @@ -35,6 +35,7 @@
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>
26 @@ -77,6 +78,8 @@
27 #define VC5_HDMI_VERTB_VSPO_SHIFT 16
28 #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16)
29
30 +#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0)
31 +
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)
34
35 @@ -517,6 +520,64 @@ static void vc4_hdmi_set_infoframes(stru
36 vc4_hdmi_set_hdr_infoframe(encoder);
37 }
38
39 +static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder,
40 + struct drm_display_mode *mode)
41 +{
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;
45 +
46 + if (!vc4_encoder->hdmi_monitor)
47 + return false;
48 +
49 + if (!display->hdmi.scdc.supported ||
50 + !display->hdmi.scdc.scrambling.supported)
51 + return false;
52 +
53 + return true;
54 +}
55 +
56 +static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
57 +{
58 + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
59 + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
60 +
61 + if (!vc4_hdmi_supports_scrambling(encoder, mode))
62 + return;
63 +
64 + if (!vc4_hdmi_mode_needs_scrambling(mode))
65 + return;
66 +
67 + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true);
68 + drm_scdc_set_scrambling(vc4_hdmi->ddc, true);
69 +
70 + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
71 + VC5_HDMI_SCRAMBLER_CTL_ENABLE);
72 +}
73 +
74 +static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
75 +{
76 + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
77 + struct drm_crtc *crtc = encoder->crtc;
78 +
79 + /*
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.
83 + */
84 + if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode))
85 + return;
86 +
87 + if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode))
88 + return;
89 +
90 + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
91 + ~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
92 +
93 + drm_scdc_set_scrambling(vc4_hdmi->ddc, false);
94 + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false);
95 +}
96 +
97 static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
98 struct drm_atomic_state *state)
99 {
100 @@ -529,6 +590,8 @@ static void vc4_hdmi_encoder_post_crtc_d
101
102 HDMI_WRITE(HDMI_VID_CTL,
103 HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX);
104 +
105 + vc4_hdmi_disable_scrambling(encoder);
106 }
107
108 static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder,
109 @@ -979,6 +1042,7 @@ static void vc4_hdmi_encoder_post_crtc_e
110 }
111
112 vc4_hdmi_recenter_fifo(vc4_hdmi);
113 + vc4_hdmi_enable_scrambling(encoder);
114 }
115
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 {
120 HDMI_RM_FORMAT,
121 HDMI_RM_OFFSET,
122 HDMI_SCHEDULER_CONTROL,
123 + HDMI_SCRAMBLER_CTL,
124 HDMI_SW_RESET_CONTROL,
125 HDMI_TX_PHY_CHANNEL_SWAP,
126 HDMI_TX_PHY_CLK_DIV,
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),
132
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),
140
141 VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc),
142 VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0),