141 lines
5.6 KiB
Diff
141 lines
5.6 KiB
Diff
From 0e0118339ce920d988c550d9013333c5d948ab08 Mon Sep 17 00:00:00 2001
|
|
From: Dom Cobley <popcornmix@gmail.com>
|
|
Date: Mon, 28 Jun 2021 16:07:16 +0200
|
|
Subject: [PATCH] drm/vc4: hdmi: Use a fixed rate for the HSM clock on
|
|
BCM2835
|
|
|
|
Before the introduction of the BCM2711 support, the HSM clock rate was
|
|
fixed, and was the CEC and audio clock source on the SoCs previously
|
|
supported.
|
|
|
|
The HSM clock is also the source of the internal state machine of the
|
|
controller and needs to run faster than the pixel clock. All these
|
|
requirements were met by running at 101% of the maximum pixel rate,
|
|
meeting the fixed clock requirement for audio and CEC, while remaining
|
|
faster than any pixel clock we might need.
|
|
|
|
However, the BCM2711 brought support for 4k and therefore increased
|
|
significantly the rate needed for the HSM, and new, independant, clocks
|
|
to feed the audio and CEC clocks. Since the HSM clock can also run much
|
|
higher, we also need to lower its rate if possible to reduce its power
|
|
consumption.
|
|
|
|
The CEC support code changes its clock divider when the HSM clock rate
|
|
is changed, but the audio support never had a similar feature and will
|
|
glitch out if audio is played back during a mode set.
|
|
|
|
Since the HSM rate was meant to be fixed on the SoCs prior to the
|
|
BCM2711 anyway, let's introduce back a fixed HSM rate and fix audio.
|
|
|
|
Fixes: cd4cb49dc5bb ("drm/vc4: hdmi: Adjust HSM clock rate depending on pixel rate")
|
|
Signed-off-by: Dom Cobley <popcornmix@gmail.com>
|
|
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
|
|
---
|
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 54 +++++++++++++++++++++++-----------
|
|
drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ++
|
|
2 files changed, 40 insertions(+), 17 deletions(-)
|
|
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
|
@@ -908,23 +908,7 @@ static void vc4_hdmi_encoder_pre_crtc_co
|
|
return;
|
|
}
|
|
|
|
- /*
|
|
- * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
|
- * be faster than pixel clock, infinitesimally faster, tested in
|
|
- * simulation. Otherwise, exact value is unimportant for HDMI
|
|
- * operation." This conflicts with bcm2835's vc4 documentation, which
|
|
- * states HSM's clock has to be at least 108% of the pixel clock.
|
|
- *
|
|
- * Real life tests reveal that vc4's firmware statement holds up, and
|
|
- * users are able to use pixel clocks closer to HSM's, namely for
|
|
- * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
|
|
- * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
|
|
- * 162MHz.
|
|
- *
|
|
- * Additionally, the AXI clock needs to be at least 25% of
|
|
- * pixel clock, but HSM ends up being the limiting factor.
|
|
- */
|
|
- hsm_rate = max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
|
|
+ hsm_rate = vc4_hdmi->variant->calc_hsm_clock(vc4_hdmi, pixel_rate);
|
|
vc4_hdmi->hsm_req = clk_request_start(vc4_hdmi->hsm_clock, hsm_rate);
|
|
if (IS_ERR(vc4_hdmi->hsm_req)) {
|
|
DRM_ERROR("Failed to set HSM clock rate: %ld\n", PTR_ERR(vc4_hdmi->hsm_req));
|
|
@@ -1140,6 +1124,39 @@ static const struct drm_encoder_helper_f
|
|
.enable = vc4_hdmi_encoder_enable,
|
|
};
|
|
|
|
+static u32 vc4_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
|
|
+{
|
|
+ /*
|
|
+ * Whilst this can vary, all the CEC timings are derived from this
|
|
+ * clock, so make it constant to avoid having to reconfigure CEC on
|
|
+ * every mode change.
|
|
+ */
|
|
+
|
|
+ return 163682864;
|
|
+}
|
|
+
|
|
+static u32 vc5_hdmi_calc_hsm_clock(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate)
|
|
+{
|
|
+ /*
|
|
+ * As stated in RPi's vc4 firmware "HDMI state machine (HSM) clock must
|
|
+ * be faster than pixel clock, infinitesimally faster, tested in
|
|
+ * simulation. Otherwise, exact value is unimportant for HDMI
|
|
+ * operation." This conflicts with bcm2835's vc4 documentation, which
|
|
+ * states HSM's clock has to be at least 108% of the pixel clock.
|
|
+ *
|
|
+ * Real life tests reveal that vc4's firmware statement holds up, and
|
|
+ * users are able to use pixel clocks closer to HSM's, namely for
|
|
+ * 1920x1200@60Hz. So it was decided to have leave a 1% margin between
|
|
+ * both clocks. Which, for RPi0-3 implies a maximum pixel clock of
|
|
+ * 162MHz.
|
|
+ *
|
|
+ * Additionally, the AXI clock needs to be at least 25% of
|
|
+ * pixel clock, but HSM ends up being the limiting factor.
|
|
+ */
|
|
+
|
|
+ return max_t(unsigned long, 120000000, (pixel_rate / 100) * 101);
|
|
+}
|
|
+
|
|
static u32 vc4_hdmi_channel_map(struct vc4_hdmi *vc4_hdmi, u32 channel_mask)
|
|
{
|
|
int i;
|
|
@@ -2322,6 +2339,7 @@ static const struct vc4_hdmi_variant bcm
|
|
.phy_disable = vc4_hdmi_phy_disable,
|
|
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
|
|
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
|
|
+ .calc_hsm_clock = vc4_hdmi_calc_hsm_clock,
|
|
.channel_map = vc4_hdmi_channel_map,
|
|
.supports_hdr = false,
|
|
};
|
|
@@ -2350,6 +2368,7 @@ static const struct vc4_hdmi_variant bcm
|
|
.phy_disable = vc5_hdmi_phy_disable,
|
|
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
|
|
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
|
|
+ .calc_hsm_clock = vc5_hdmi_calc_hsm_clock,
|
|
.channel_map = vc5_hdmi_channel_map,
|
|
.supports_hdr = true,
|
|
};
|
|
@@ -2378,6 +2397,7 @@ static const struct vc4_hdmi_variant bcm
|
|
.phy_disable = vc5_hdmi_phy_disable,
|
|
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
|
|
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
|
|
+ .calc_hsm_clock = vc5_hdmi_calc_hsm_clock,
|
|
.channel_map = vc5_hdmi_channel_map,
|
|
.supports_hdr = true,
|
|
};
|
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
|
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
|
|
@@ -97,6 +97,9 @@ struct vc4_hdmi_variant {
|
|
/* Callback to disable the RNG in the PHY */
|
|
void (*phy_rng_disable)(struct vc4_hdmi *vc4_hdmi);
|
|
|
|
+ /* Callback to calculate hsm clock */
|
|
+ u32 (*calc_hsm_clock)(struct vc4_hdmi *vc4_hdmi, unsigned long pixel_rate);
|
|
+
|
|
/* Callback to get channel map */
|
|
u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
|
|
|