e08ad7d32081b0c46d2275300e2516d72179364f
[openwrt/staging/xback.git] /
1 From 0e0118339ce920d988c550d9013333c5d948ab08 Mon Sep 17 00:00:00 2001
2 From: Dom Cobley <popcornmix@gmail.com>
3 Date: Mon, 28 Jun 2021 16:07:16 +0200
4 Subject: [PATCH] drm/vc4: hdmi: Use a fixed rate for the HSM clock on
5 BCM2835
6
7 Before the introduction of the BCM2711 support, the HSM clock rate was
8 fixed, and was the CEC and audio clock source on the SoCs previously
9 supported.
10
11 The HSM clock is also the source of the internal state machine of the
12 controller and needs to run faster than the pixel clock. All these
13 requirements were met by running at 101% of the maximum pixel rate,
14 meeting the fixed clock requirement for audio and CEC, while remaining
15 faster than any pixel clock we might need.
16
17 However, the BCM2711 brought support for 4k and therefore increased
18 significantly the rate needed for the HSM, and new, independant, clocks
19 to feed the audio and CEC clocks. Since the HSM clock can also run much
20 higher, we also need to lower its rate if possible to reduce its power
21 consumption.
22
23 The CEC support code changes its clock divider when the HSM clock rate
24 is changed, but the audio support never had a similar feature and will
25 glitch out if audio is played back during a mode set.
26
27 Since the HSM rate was meant to be fixed on the SoCs prior to the
28 BCM2711 anyway, let's introduce back a fixed HSM rate and fix audio.
29
30 Fixes: cd4cb49dc5bb ("drm/vc4: hdmi: Adjust HSM clock rate depending on pixel rate")
31 Signed-off-by: Dom Cobley <popcornmix@gmail.com>
32 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
33 ---
34 drivers/gpu/drm/vc4/vc4_hdmi.c | 54 +++++++++++++++++++++++-----------
35 drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ++
36 2 files changed, 40 insertions(+), 17 deletions(-)
37
38 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
39 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
40 @@ -909,23 +909,7 @@ static void vc4_hdmi_encoder_pre_crtc_co
41 return;
42 }
43
44 - /*
45 - * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
46 - * be faster than pixel clock, infinitesimally faster, tested in
47 - * simulation. Otherwise, exact value is unimportant for HDMI
48 - * operation." This conflicts with bcm2835's vc4 documentation, which
49 - * states HSM's clock has to be at least 108% of the pixel clock.
50 - *
51 - * Real life tests reveal that vc4's firmware statement holds up, and
52 - * users are able to use pixel clocks closer to HSM's, namely for
53 - * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
54 - * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
55 - * 162MHz.
56 - *
57 - * Additionally, the AXI clock needs to be at least 25% of
58 - * pixel clock, but HSM ends up being the limiting factor.
59 - */
60 - hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
61 + hsm_rate = vc4_hdmi->variant->calc_hsm_clock(vc4_hdmi, pixel_rate);
62 vc4_hdmi->hsm_req = clk_request_start(vc4_hdmi->hsm_clock, hsm_rate);
63 if (IS_ERR(vc4_hdmi->hsm_req)) {
64 DRM_ERROR("Failed to set HSM clock rate: %ld\n", PTR_ERR(vc4_hdmi->hsm_req));
65 @@ -1141,6 +1125,39 @@ static const struct drm_encoder_helper_f
66 .enable = vc4_hdmi_encoder_enable,
67 };
68
69 +static u32 vc4_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
70 +{
71 + /*
72 + * Whilst this can vary, all the CEC timings are derived from this
73 + * clock, so make it constant to avoid having to reconfigure CEC on
74 + * every mode change.
75 + */
76 +
77 + return 163682864;
78 +}
79 +
80 +static u32 vc5_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
81 +{
82 + /*
83 + * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
84 + * be faster than pixel clock, infinitesimally faster, tested in
85 + * simulation. Otherwise, exact value is unimportant for HDMI
86 + * operation." This conflicts with bcm2835's vc4 documentation, which
87 + * states HSM's clock has to be at least 108% of the pixel clock.
88 + *
89 + * Real life tests reveal that vc4's firmware statement holds up, and
90 + * users are able to use pixel clocks closer to HSM's, namely for
91 + * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
92 + * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
93 + * 162MHz.
94 + *
95 + * Additionally, the AXI clock needs to be at least 25% of
96 + * pixel clock, but HSM ends up being the limiting factor.
97 + */
98 +
99 + return max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
100 +}
101 +
102 static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
103 {
104 int i;
105 @@ -2344,6 +2361,7 @@ static const struct vc4_hdmi_variant bcm
106 .phy_disable = vc4_hdmi_phy_disable,
107 .phy_rng_enable = vc4_hdmi_phy_rng_enable,
108 .phy_rng_disable = vc4_hdmi_phy_rng_disable,
109 + .calc_hsm_clock = vc4_hdmi_calc_hsm_clock,
110 .channel_map = vc4_hdmi_channel_map,
111 .supports_hdr = false,
112 };
113 @@ -2372,6 +2390,7 @@ static const struct vc4_hdmi_variant bcm
114 .phy_disable = vc5_hdmi_phy_disable,
115 .phy_rng_enable = vc5_hdmi_phy_rng_enable,
116 .phy_rng_disable = vc5_hdmi_phy_rng_disable,
117 + .calc_hsm_clock = vc5_hdmi_calc_hsm_clock,
118 .channel_map = vc5_hdmi_channel_map,
119 .supports_hdr = true,
120 };
121 @@ -2400,6 +2419,7 @@ static const struct vc4_hdmi_variant bcm
122 .phy_disable = vc5_hdmi_phy_disable,
123 .phy_rng_enable = vc5_hdmi_phy_rng_enable,
124 .phy_rng_disable = vc5_hdmi_phy_rng_disable,
125 + .calc_hsm_clock = vc5_hdmi_calc_hsm_clock,
126 .channel_map = vc5_hdmi_channel_map,
127 .supports_hdr = true,
128 };
129 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h
130 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
131 @@ -97,6 +97,9 @@ struct vc4_hdmi_variant {
132 /* Callback to disable the RNG in the PHY */
133 void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi);
134
135 + /* Callback to calculate hsm clock */
136 + u32 (*calc_hsm_clock)(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate);
137 +
138 /* Callback to get channel map */
139 u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
140