From 58b9c17d8b2df68f823ece73b5c77a82e466533e Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 21 Apr 2021 12:14:44 +0200 Subject: [PATCH 01/10] clk: requests: Ignore if the pointer is null Signed-off-by: Maxime Ripard --- drivers/clk/clk.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 031627757b11be..af0f638d1769fa 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2498,6 +2498,9 @@ void clk_request_done(struct clk_request *req) { struct clk_core *core = req->clk->core; + if (!req) + return; + clk_prepare_lock(); list_del(&req->list); From 514e193e052bc72afbf0ae17300bca73e84c54ca Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Mar 2021 13:42:01 +0100 Subject: [PATCH 02/10] drm/vc4: txp: Properly set the possible_crtcs mask The current code does a binary OR on the possible_crtcs variable of the TXP encoder, while we want to set it to that value instead. Cc: # v5.9+ Fixes: 39fcb2808376 ("drm/vc4: txp: Turn the TXP into a CRTC of its own") Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_txp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c index 4a26750b5e933c..22430640786fa0 100644 --- a/drivers/gpu/drm/vc4/vc4_txp.c +++ b/drivers/gpu/drm/vc4/vc4_txp.c @@ -506,7 +506,7 @@ static int vc4_txp_bind(struct device *dev, struct device *master, void *data) return ret; encoder = &txp->connector.encoder; - encoder->possible_crtcs |= drm_crtc_mask(crtc); + encoder->possible_crtcs = drm_crtc_mask(crtc); ret = devm_request_irq(dev, irq, vc4_txp_interrupt, 0, dev_name(dev), txp); From 12200fa67ffce0892e186114ec5a3700a8201d83 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Mar 2021 13:42:19 +0100 Subject: [PATCH 03/10] drm/vc4: crtc: Skip the TXP The vc4_set_crtc_possible_masks is meant to run over all the encoders and then set their possible_crtcs mask to their associated pixelvalve. However, since the commit 39fcb2808376 ("drm/vc4: txp: Turn the TXP into a CRTC of its own"), the TXP has been turned to a CRTC and encoder of its own, and while it does indeed register an encoder, it no longer has an associated pixelvalve. The code will thus run over the TXP encoder and set a bogus possible_crtcs mask, overriding the one set in the TXP bind function. In order to fix this, let's skip any virtual encoder. Cc: # v5.9+ Fixes: 39fcb2808376 ("drm/vc4: txp: Turn the TXP into a CRTC of its own") Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 339567dd015c09..7a43c14a2d45c5 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -1049,6 +1049,9 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm, struct vc4_encoder *vc4_encoder; int i; + if (encoder->encoder_type == DRM_MODE_ENCODER_VIRTUAL) + continue; + vc4_encoder = to_vc4_encoder(encoder); for (i = 0; i < ARRAY_SIZE(pv_data->encoder_types); i++) { if (vc4_encoder->type == encoder_types[i]) { From 784058ffd0ad41ff5958c54f5249a61bdf26eb54 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Tue, 16 Mar 2021 13:51:52 +0100 Subject: [PATCH 04/10] drm/vc4: Rework the encoder retrieval code Due to a FIFO that cannot be flushed between the pixelvalve and the HDMI controllers on BCM2711, we need to carefully disable both at boot time if they were left enabled by the firmware. However, at the time we're running that code, the struct drm_connector encoder pointer isn't set yet, and thus we cannot retrieve the encoder associated to our CRTC. We can however make use of the fact that we have a less flexible setup than what DRM allows where we have a 1:1 relationship between our CRTCs and encoders (and connectors), and thus store the crtc associated to our encoder at boot time. We cannot do that at the time the encoders are probed though, since the CRTCs won't be probed yet and thus we don't know at that time which CRTC index we're going to get, so let's do this in two passes: we can first bind all the components and then once they all are bound, we can iterate over all the encoders to find their associated CRTC and set the pointer. This is similar to what we're doing to set the possible_crtcs field. Fixes: 875a4d536842 ("drm/vc4: drv: Disable the CRTC at boot time") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_crtc.c | 25 +++++++++++++++++++++-- drivers/gpu/drm/vc4/vc4_drv.c | 36 ++++++++++++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_drv.h | 10 ++++++++++ 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 7a43c14a2d45c5..45aef3005efe31 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -272,6 +272,19 @@ static u32 vc4_crtc_get_fifo_full_level_bits(struct vc4_crtc *vc4_crtc, PV_CONTROL_FIFO_LEVEL); } +static struct drm_encoder *vc4_get_connector_encoder(struct drm_connector *connector) +{ + struct drm_encoder *encoder; + + if (drm_WARN_ON(connector->dev, hweight32(connector->possible_encoders) != 1)) + return NULL; + + drm_connector_for_each_possible_encoder(connector, encoder) + return encoder; + + return NULL; +} + /* * Returns the encoder attached to the CRTC. * @@ -286,9 +299,17 @@ static struct drm_encoder *vc4_get_crtc_encoder(struct drm_crtc *crtc) drm_connector_list_iter_begin(crtc->dev, &conn_iter); drm_for_each_connector_iter(connector, &conn_iter) { - if (connector->state->crtc == crtc) { + struct drm_encoder *encoder; + struct vc4_encoder *vc4_encoder; + + encoder = vc4_get_connector_encoder(connector); + if (!encoder) + continue; + + vc4_encoder = to_vc4_encoder(encoder); + if (vc4_encoder->crtc == crtc) { drm_connector_list_iter_end(&conn_iter); - return connector->encoder; + return encoder; } } drm_connector_list_iter_end(&conn_iter); diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 617c113b033fba..8baa90837e9e62 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -226,6 +226,41 @@ static int compare_dev(struct device *dev, void *data) return dev == data; } +static struct drm_crtc *vc4_drv_find_crtc(struct drm_device *drm, + struct drm_encoder *encoder) +{ + struct drm_crtc *crtc; + + if (WARN_ON(hweight32(encoder->possible_crtcs) != 1)) + return NULL; + + drm_for_each_crtc(crtc, drm) { + if (!drm_encoder_crtc_ok(encoder, crtc)) + continue; + + return crtc; + } + + return NULL; +} + +static void vc4_drv_set_encoder_data(struct drm_device *drm) +{ + struct drm_encoder *encoder; + + drm_for_each_encoder(encoder, drm) { + struct vc4_encoder *vc4_encoder; + struct drm_crtc *crtc; + + crtc = vc4_drv_find_crtc(drm, encoder); + if (WARN_ON(!crtc)) + return; + + vc4_encoder = to_vc4_encoder(encoder); + vc4_encoder->crtc = crtc; + } +} + static void vc4_match_add_drivers(struct device *dev, struct component_match **match, struct platform_driver *const *drivers, @@ -308,6 +343,7 @@ static int vc4_drm_bind(struct device *dev) ret = component_bind_all(dev, drm); if (ret) return ret; + vc4_drv_set_encoder_data(drm); if (!vc4->firmware_kms) { ret = vc4_plane_create_additional_planes(drm); diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h index 52c3ee43d004e1..632fed13a8f952 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.h +++ b/drivers/gpu/drm/vc4/vc4_drv.h @@ -447,6 +447,16 @@ enum vc4_encoder_type { struct vc4_encoder { struct drm_encoder base; + + /* + * At boot time, we need to be able to retrieve the CRTC for a given + * connector in order to run the disable hooks below to avoid the stuck + * pixel issue. Unfortunately the drm_connector->encoder pointer is + * NULL at that time so we can't move up the chain, so we'll store it + * ourselves here. + */ + struct drm_crtc *crtc; + enum vc4_encoder_type type; u32 clock_select; From 62a6fbb04f0914777dd06c2c13e6f6f1cfa19ddf Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Mar 2021 10:37:38 +0100 Subject: [PATCH 05/10] drm/vc4: hdmi: Prevent clock unbalance Since we fixed the hooks to disable the encoder at boot, we now have an unbalanced clk_disable call at boot since we never enabled them in the first place. Let's mimic the state of the hardware and enable the clocks at boot if the controller is enabled to get the use-count right. Cc: # v5.10+ Fixes: 09c438139b8f ("drm/vc4: hdmi: Implement finer-grained hooks") Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 1872b3a2bb5199..3a0ac5a9c0277b 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2626,6 +2626,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) if (vc4_hdmi->variant->reset) vc4_hdmi->variant->reset(vc4_hdmi); + if ((of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi0") || + of_device_is_compatible(dev->of_node, "brcm,bcm2711-hdmi1")) && + HDMI_READ(HDMI_VID_CTL) & VC4_HD_VID_CTL_ENABLE) { + clk_prepare_enable(vc4_hdmi->pixel_clock); + clk_prepare_enable(vc4_hdmi->hsm_clock); + clk_prepare_enable(vc4_hdmi->pixel_bvb_clock); + } + pm_runtime_enable(dev); drm_simple_encoder_init(drm, encoder, DRM_MODE_ENCODER_TMDS); From 76b1c4b92ebc404e195defb47c84a9348e4e8edc Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Feb 2021 14:42:03 +0100 Subject: [PATCH 06/10] drm/vc4: hvs: Make the HVS bind first We'll need to have the HVS binding before the HDMI controllers so that we can check whether the firmware allows to run in 4kp60. Reorder a bit the component list, and document the current constraints we're aware of. Acked-by: Dave Stevenson Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_drv.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c index 8baa90837e9e62..c404ef49f42057 100644 --- a/drivers/gpu/drm/vc4/vc4_drv.c +++ b/drivers/gpu/drm/vc4/vc4_drv.c @@ -390,12 +390,21 @@ static const struct component_master_ops vc4_drm_ops = { .unbind = vc4_drm_unbind, }; +/* + * This list determines the binding order of our components, and we have + * a few constraints: + * - The TXP driver needs to be bound before the PixelValves (CRTC) + * but after the HVS to set the possible_crtc field properly + * - The HDMI driver needs to be bound after the HVS so that we can + * lookup the HVS maximum core clock rate and figure out if we + * support 4kp60 or not. + */ static struct platform_driver *const component_drivers[] = { + &vc4_hvs_driver, &vc4_hdmi_driver, &vc4_vec_driver, &vc4_dpi_driver, &vc4_dsi_driver, - &vc4_hvs_driver, &vc4_txp_driver, &vc4_crtc_driver, &vc4_firmware_kms_driver, From 403a6176a14ac7f905b478e4d490fa85a6afa1b8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Oct 2020 16:06:08 +0200 Subject: [PATCH 07/10] drm/vc4: hdmi: Properly compute the BVB clock rate The BVB clock rate computation doesn't take into account a mode clock of 594MHz that we're going to need to support 4k60. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 3a0ac5a9c0277b..ca6651607acd70 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -93,7 +93,6 @@ # define VC4_HD_M_ENABLE BIT(0) #define CEC_CLOCK_FREQ 40000 -#define VC4_HSM_MID_CLOCK 149985000 #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 @@ -1120,7 +1119,7 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, conn_state_to_vc4_hdmi_conn_state(conn_state); struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); - unsigned long pixel_rate, hsm_rate; + unsigned long bvb_rate, pixel_rate, hsm_rate; int ret; ret = pm_runtime_get_sync(&vc4_hdmi->pdev->dev); @@ -1174,12 +1173,14 @@ static void vc4_hdmi_encoder_pre_crtc_configure(struct drm_encoder *encoder, vc4_hdmi_cec_update_clk_div(vc4_hdmi); - /* - * FIXME: When the pixel freq is 594MHz (4k60), this needs to be setup - * at 300MHz. - */ - vc4_hdmi->bvb_req = clk_request_start(vc4_hdmi->pixel_bvb_clock, - (hsm_rate > VC4_HSM_MID_CLOCK ? 150000000 : 75000000)); + if (pixel_rate > 297000000) + bvb_rate = 300000000; + else if (pixel_rate > 148500000) + bvb_rate = 150000000; + else + bvb_rate = 75000000; + + vc4_hdmi->bvb_req = clk_request_start(vc4_hdmi->pixel_bvb_clock, bvb_rate); if (IS_ERR(vc4_hdmi->bvb_req)) { DRM_ERROR("Failed to set pixel bvb clock rate: %ld\n", PTR_ERR(vc4_hdmi->bvb_req)); clk_request_done(vc4_hdmi->hsm_req); From ad23ccc4f37feea5e6ecde0f8d6d6098900d55f8 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 25 Feb 2021 15:35:02 +0100 Subject: [PATCH 08/10] drm/vc4: hdmi: Check and warn if we can't reach 4kp60 frequencies In order to reach the frequencies needed to output at 594MHz, the firmware needs to be configured with the appropriate parameters in the config.txt file (enable_hdmi_4kp60 and force_turbo). Let's detect it at bind time, warn the user if we can't, and filter out the relevant modes. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 31 +++++++++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_hdmi.h | 8 ++++++++ 2 files changed, 39 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index ca6651607acd70..08bb54eb76e384 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -401,6 +401,11 @@ static void hdmi_codec_eld_chmap(struct vc4_hdmi *vc4_hdmi) #define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000) +static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode) +{ + return (mode->clock * 1000) > HDMI_14_MAX_TMDS_CLK; +} + static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused) { struct drm_info_node *node = (struct drm_info_node *)m->private; @@ -523,6 +528,18 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) ret = drm_add_edid_modes(connector, edid); kfree(edid); + if (vc4_hdmi->disable_4kp60) { + struct drm_device *drm = connector->dev; + struct drm_display_mode *mode; + + list_for_each_entry(mode, &connector->probed_modes, head) { + if (vc4_hdmi_mode_needs_scrambling(mode)) { + drm_warn_once(drm, "The core clock cannot reach frequencies high enough to support 4k @ 60Hz."); + drm_warn_once(drm, "Please change your config.txt file to add hdmi_enable_4kp60."); + } + } + } + return ret; } @@ -1343,6 +1360,9 @@ static int vc4_hdmi_encoder_atomic_check(struct drm_encoder *encoder, if (pixel_rate > vc4_hdmi->variant->max_pixel_clock) return -EINVAL; + if (vc4_hdmi->disable_4kp60 && (pixel_rate > HDMI_14_MAX_TMDS_CLK)) + return -EINVAL; + vc4_state->pixel_rate = pixel_rate; return 0; @@ -1362,6 +1382,9 @@ vc4_hdmi_encoder_mode_valid(struct drm_encoder *encoder, if ((mode->clock * 1000) > vc4_hdmi->variant->max_pixel_clock) return MODE_CLOCK_HIGH; + if (vc4_hdmi->disable_4kp60 && vc4_hdmi_mode_needs_scrambling(mode)) + return MODE_CLOCK_HIGH; + return MODE_OK; } @@ -2624,6 +2647,14 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data) vc4_hdmi->disable_wifi_frequencies = of_property_read_bool(dev->of_node, "wifi-2.4ghz-coexistence"); + if (variant->max_pixel_clock == 600000000) { + struct vc4_dev *vc4 = to_vc4_dev(drm); + long max_rate = clk_round_rate(vc4->hvs->core_clk, 550000000); + + if (max_rate < 550000000) + vc4_hdmi->disable_4kp60 = true; + } + if (vc4_hdmi->variant->reset) vc4_hdmi->variant->reset(vc4_hdmi); diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h index 11a4b737d0abc9..23e8cfc22c4dca 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h @@ -162,6 +162,14 @@ struct vc4_hdmi { */ bool disable_wifi_frequencies; + /* + * Even if HDMI0 on the RPi4 can output modes requiring a pixel + * rate higher than 297MHz, it needs some adjustments in the + * config.txt file to be able to do so and thus won't always be + * available. + */ + bool disable_4kp60; + struct cec_adapter *cec_adap; struct cec_msg cec_rx_msg; bool cec_tx_ok; From c33e5fb76b6191f041a23b54ecb339769392a18d Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Oct 2020 16:06:58 +0200 Subject: [PATCH 09/10] drm/vc4: hdmi: Enable the scrambler The HDMI controller on the BCM2711 includes a scrambler in order to reach the HDMI 2.0 modes that require it. Let's add the support for it. Acked-by: Thomas Zimmermann Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 64 +++++++++++++++++++++++++++++ drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 3 ++ 2 files changed, 67 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 08bb54eb76e384..b8785dc9f4f39e 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -78,6 +79,8 @@ #define VC5_HDMI_VERTB_VSPO_SHIFT 16 #define VC5_HDMI_VERTB_VSPO_MASK VC4_MASK(29, 16) +#define VC5_HDMI_SCRAMBLER_CTL_ENABLE BIT(0) + #define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_SHIFT 8 #define VC5_HDMI_DEEP_COLOR_CONFIG_1_INIT_PACK_PHASE_MASK VC4_MASK(10, 8) @@ -841,6 +844,64 @@ static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder) vc4_hdmi_set_hdr_infoframe(encoder); } +static bool vc4_hdmi_supports_scrambling(struct drm_encoder *encoder, + struct drm_display_mode *mode) +{ + struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder); + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_display_info *display = &vc4_hdmi->connector.display_info; + + if (!vc4_encoder->hdmi_monitor) + return false; + + if (!display->hdmi.scdc.supported || + !display->hdmi.scdc.scrambling.supported) + return false; + + return true; +} + +static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder) +{ + struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode; + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + + if (!vc4_hdmi_supports_scrambling(encoder, mode)) + return; + + if (!vc4_hdmi_mode_needs_scrambling(mode)) + return; + + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, true); + drm_scdc_set_scrambling(vc4_hdmi->ddc, true); + + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) | + VC5_HDMI_SCRAMBLER_CTL_ENABLE); +} + +static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder) +{ + struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder); + struct drm_crtc *crtc = encoder->crtc; + + /* + * At boot, encoder->crtc will be NULL. Since we don't know the + * state of the scrambler and in order to avoid any + * inconsistency, let's disable it all the time. + */ + if (crtc && !vc4_hdmi_supports_scrambling(encoder, &crtc->mode)) + return; + + if (crtc && !vc4_hdmi_mode_needs_scrambling(&crtc->mode)) + return; + + HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) & + ~VC5_HDMI_SCRAMBLER_CTL_ENABLE); + + drm_scdc_set_scrambling(vc4_hdmi->ddc, false); + drm_scdc_set_high_tmds_clock_ratio(vc4_hdmi->ddc, false); +} + static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, struct drm_atomic_state *state) { @@ -853,6 +914,8 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder, HDMI_WRITE(HDMI_VID_CTL, HDMI_READ(HDMI_VID_CTL) | VC4_HD_VID_CTL_BLANKPIX); + + vc4_hdmi_disable_scrambling(encoder); } static void vc4_hdmi_encoder_post_crtc_powerdown(struct drm_encoder *encoder, @@ -1308,6 +1371,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder, } vc4_hdmi_recenter_fifo(vc4_hdmi); + vc4_hdmi_enable_scrambling(encoder); } static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h index 20a1438a72cb73..a81fdf90f66b7f 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h @@ -100,6 +100,7 @@ enum vc4_hdmi_field { HDMI_RM_FORMAT, HDMI_RM_OFFSET, HDMI_SCHEDULER_CONTROL, + HDMI_SCRAMBLER_CTL, HDMI_SW_RESET_CONTROL, HDMI_TX_PHY_CHANNEL_SWAP, HDMI_TX_PHY_CLK_DIV, @@ -238,6 +239,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi0_fields[] = { VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178), VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c), VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), + VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), @@ -317,6 +319,7 @@ static const struct vc4_hdmi_register vc5_hdmi_hdmi1_fields[] = { VC4_HDMI_REG(HDMI_GCP_CONFIG, 0x178), VC4_HDMI_REG(HDMI_GCP_WORD_1, 0x17c), VC4_HDMI_REG(HDMI_HOTPLUG, 0x1a8), + VC4_HDMI_REG(HDMI_SCRAMBLER_CTL, 0x1c4), VC5_DVP_REG(HDMI_CLOCK_STOP, 0x0bc), VC5_DVP_REG(HDMI_VEC_INTERFACE_XBAR, 0x0f0), From 8d6d26709d0d4373a214225ac510aa5156e6645f Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Thu, 8 Oct 2020 16:08:06 +0200 Subject: [PATCH 10/10] drm/vc4: hdmi: Raise the maximum clock rate Now that we have the infrastructure in place, we can raise the maximum pixel rate we can reach for HDMI0 on the BCM2711. HDMI1 is left untouched since its pixelvalve has a smaller FIFO and would need a clock faster than what we can provide to support the same modes. Acked-by: Thomas Zimmermann Reviewed-by: Dave Stevenson Signed-off-by: Maxime Ripard --- drivers/gpu/drm/vc4/vc4_hdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index b8785dc9f4f39e..7d0d1da476097a 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -2844,7 +2844,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = { .encoder_type = VC4_ENCODER_TYPE_HDMI0, .debugfs_name = "hdmi0_regs", .card_name = "vc4-hdmi-0", - .max_pixel_clock = HDMI_14_MAX_TMDS_CLK, + .max_pixel_clock = 600000000, .registers = vc5_hdmi_hdmi0_fields, .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields), .phy_lane_mapping = {