diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch b/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch new file mode 100644 index 0000000000..4dba81b035 --- /dev/null +++ b/target/linux/bcm27xx/patches-5.4/950-0594-drm-vc4-hdmi-Adjust-HSM-clock-rate-depending-on-pixe.patch @@ -0,0 +1,163 @@ +From 3c33724058852d7c58d77d03e11ca545fb04256a Mon Sep 17 00:00:00 2001 +From: Maxime Ripard <maxime@cerno.tech> +Date: Mon, 10 Feb 2020 15:23:06 +0100 +Subject: [PATCH] drm/vc4: hdmi: Adjust HSM clock rate depending on + pixel rate + +The HSM clock needs to be setup at around 110% of the pixel rate. This +was done previously by setting the clock rate to 148.5MHz * 108% at +probe time and only check in mode_valid whether the mode pixel clock was +under 148.5MHz or not. + +However, with 4k we need to change that frequency to a higher frequency +than 148.5MHz. + +Let's change that logic a bit by setting the clock rate of the HSM clock +to the pixel rate at encoder_enable time. This would work for the +BCM2711 that support 4k resolutions and has a clock that can provide it, +but we still have to take care of a 4k panel plugged on a BCM283x SoCs +that wouldn't be able to use those modes, so let's define the limit in +the variant. + +Signed-off-by: Maxime Ripard <maxime@cerno.tech> +--- + drivers/gpu/drm/vc4/vc4_hdmi.c | 51 +++++++++++++++++----------------- + drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ++ + 2 files changed, 29 insertions(+), 25 deletions(-) + +--- a/drivers/gpu/drm/vc4/vc4_hdmi.c ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.c +@@ -52,7 +52,6 @@ + #include "vc4_hdmi_regs.h" + #include "vc4_regs.h" + +-#define HSM_CLOCK_FREQ 163682864 + #define CEC_CLOCK_FREQ 40000 + + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) +@@ -329,6 +328,7 @@ static void vc4_hdmi_encoder_disable(str + HDMI_WRITE(HDMI_VID_CTL, + HDMI_READ(HDMI_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE); + ++ clk_disable_unprepare(vc4_hdmi->hsm_clock); + clk_disable_unprepare(vc4_hdmi->pixel_clock); + + ret = pm_runtime_put(&vc4_hdmi->pdev->dev); +@@ -426,6 +426,7 @@ static void vc4_hdmi_encoder_enable(stru + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + bool debug_dump_regs = false; ++ unsigned long pixel_rate, hsm_rate; + int ret; + + ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); +@@ -434,9 +435,8 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + +- ret = clk_set_rate(vc4_hdmi->pixel_clock, +- mode->clock * 1000 * +- ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1)); ++ pixel_rate = mode->clock * 1000 * ((mode->flags & DRM_MODE_FLAG_DBLCLK) ? 2 : 1); ++ ret = clk_set_rate(vc4_hdmi->pixel_clock, pixel_rate); + if (ret) { + DRM_ERROR("Failed to set pixel clock rate: %d\n", ret); + return; +@@ -448,6 +448,24 @@ static void vc4_hdmi_encoder_enable(stru + return; + } + ++ /* ++ * The HSM rate needs to be at 108% of the pixel clock, with a ++ * minimum of 108MHz. ++ */ ++ hsm_rate = max_t(unsigned long, 108000000, (pixel_rate / 100) * 108); ++ ret = clk_set_rate(vc4_hdmi->hsm_clock, hsm_rate); ++ if (ret) { ++ DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); ++ return; ++ } ++ ++ ret = clk_prepare_enable(vc4_hdmi->hsm_clock); ++ if (ret) { ++ DRM_ERROR("Failed to turn on HSM clock: %d\n", ret); ++ clk_disable_unprepare(vc4_hdmi->pixel_clock); ++ return; ++ } ++ + if (vc4_hdmi->variant->reset) + vc4_hdmi->variant->reset(vc4_hdmi); + +@@ -578,7 +596,9 @@ vc4_hdmi_encoder_mode_valid(struct drm_e + * Additionally, the AXI clock needs to be at least 25% of + * pixel clock, but HSM ends up being the limiting factor. + */ +- if (mode->clock > HSM_CLOCK_FREQ / (1000 * 101 / 100)) ++ struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); ++ ++ if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) + return MODE_CLOCK_HIGH; + + return MODE_OK; +@@ -1353,23 +1373,6 @@ static int vc4_hdmi_bind(struct device * + return -EPROBE_DEFER; + } + +- /* This is the rate that is set by the firmware. The number +- * needs to be a bit higher than the pixel clock rate +- * (generally 148.5Mhz). +- */ +- ret = clk_set_rate(vc4_hdmi->hsm_clock, HSM_CLOCK_FREQ); +- if (ret) { +- DRM_ERROR("Failed to set HSM clock rate: %d\n", ret); +- goto err_put_i2c; +- } +- +- ret = clk_prepare_enable(vc4_hdmi->hsm_clock); +- if (ret) { +- DRM_ERROR("Failed to turn on HDMI state machine clock: %d\n", +- ret); +- goto err_put_i2c; +- } +- + /* Only use the GPIO HPD pin if present in the DT, otherwise + * we'll use the HDMI core's register. + */ +@@ -1427,9 +1430,7 @@ err_destroy_conn: + err_destroy_encoder: + vc4_hdmi_encoder_destroy(encoder); + err_unprepare_hsm: +- clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); +-err_put_i2c: + put_device(&vc4_hdmi->ddc->dev); + + return ret; +@@ -1452,7 +1453,6 @@ static void vc4_hdmi_unbind(struct devic + vc4_hdmi_connector_destroy(&vc4_hdmi->connector); + vc4_hdmi_encoder_destroy(&vc4_hdmi->encoder.base.base); + +- clk_disable_unprepare(vc4_hdmi->hsm_clock); + pm_runtime_disable(dev); + + put_device(&vc4_hdmi->ddc->dev); +@@ -1475,6 +1475,7 @@ static int vc4_hdmi_dev_remove(struct pl + } + + static const struct vc4_hdmi_variant bcm2835_variant = { ++ .max_pixel_clock = 148500000, + .audio_available = true, + .cec_available = true, + .registers = vc4_hdmi_fields, +--- a/drivers/gpu/drm/vc4/vc4_hdmi.h ++++ b/drivers/gpu/drm/vc4/vc4_hdmi.h +@@ -38,6 +38,9 @@ struct vc4_hdmi_variant { + /* Set to true when the CEC support is available */ + bool cec_available; + ++ /* Maximum pixel clock supported by the controller (in Hz) */ ++ unsigned long long max_pixel_clock; ++ + /* List of the registers available on that variant */ + const struct vc4_hdmi_register *registers; + |