* [PATCH 1/7] drm/vc4: hdmi: Use common TMDS char rate constants
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 2/7] drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling() Cristian Ciocaltea
` (5 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
Replace HDMI_14_MAX_TMDS_CLK defined locally with
HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ provided by linux/hdmi.h. Note this
incorrectly referenced HDMI 1.4, as the 340 MHz maximum TMDS character
rate was actually introduced in HDMI 1.3.
Similarly, use HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ instead of the 600000000
magic number.
Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 3a90dbb61f4e..8e4623ccc4f8 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -45,6 +45,7 @@
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/gpio/consumer.h>
+#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/of.h>
#include <linux/of_address.h>
@@ -113,8 +114,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-#define HDMI_14_MAX_TMDS_CLK (340 * 1000 * 1000)
-
static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
{
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
@@ -137,7 +136,7 @@ static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
{
unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
- return clock > HDMI_14_MAX_TMDS_CLK;
+ return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
}
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
@@ -1728,7 +1727,7 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
if (clock > vc4_hdmi->variant->max_pixel_clock)
return MODE_CLOCK_HIGH;
- if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_14_MAX_TMDS_CLK)
+ if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
/* 4096x2160@60 is not reliable without overclocking core */
@@ -3254,7 +3253,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
* vc4_hdmi_disable_scrambling() will thus run at boot, make
* sure it's disabled, and avoid any inconsistency.
*/
- if (variant->max_pixel_clock > HDMI_14_MAX_TMDS_CLK)
+ if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
vc4_hdmi->scdc_enabled = true;
ret = variant->init_resources(drm, vc4_hdmi);
@@ -3384,7 +3383,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 = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3413,7 +3412,7 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_14_MAX_TMDS_CLK,
+ .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3442,7 +3441,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3469,7 +3468,7 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = 600000000,
+ .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 2/7] drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling()
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 1/7] drm/vc4: hdmi: Use common TMDS char rate constants Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 3/7] drm/vc4: hdmi: Switch to .force_ctx() connector helper Cristian Ciocaltea
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
The VC4 HDMI driver has a local helper to check whether a mode requires
scrambling. It is equivalent to drm_hdmi_mode_needs_scrambling(), so
use the common helper instead.
No functional change intended.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 8e4623ccc4f8..26c63ce2dc2f 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -130,15 +130,6 @@ static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
return true;
}
-static bool vc4_hdmi_mode_needs_scrambling(const struct drm_display_mode *mode,
- unsigned int bpc,
- enum drm_output_color_format fmt)
-{
- unsigned long long clock = drm_hdmi_compute_mode_clock(mode, bpc, fmt);
-
- return clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ;
-}
-
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -313,7 +304,7 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
return 0;
}
- scrambling_needed = vc4_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
+ scrambling_needed = drm_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format);
if (!scrambling_needed) {
@@ -443,7 +434,8 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
const struct drm_display_mode *mode;
list_for_each_entry(mode, &connector->probed_modes, head) {
- if (vc4_hdmi_mode_needs_scrambling(mode, 8, DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
+ if (drm_hdmi_mode_needs_scrambling(mode, 8,
+ DRM_OUTPUT_COLOR_FORMAT_RGB444)) {
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.");
}
@@ -803,7 +795,7 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
return;
- if (!vc4_hdmi_mode_needs_scrambling(mode,
+ if (!drm_hdmi_mode_needs_scrambling(mode,
vc4_hdmi->output_bpc,
vc4_hdmi->output_format))
return;
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 3/7] drm/vc4: hdmi: Switch to .force_ctx() connector helper
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 1/7] drm/vc4: hdmi: Use common TMDS char rate constants Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 2/7] drm/vc4: hdmi: Switch to drm_hdmi_mode_needs_scrambling() Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 4/7] drm/vc4: hdmi: Propagate -EDEADLK to the top level Cristian Ciocaltea
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
Use drm_atomic_helper_connector_hdmi_force_ctx() as the .force_ctx()
implementation, so that the acquire context created by the probe helper
reaches the HDMI connector framework.
This is a prerequisite for converting the driver to the common HDMI 2.0
scrambling infrastructure, which implicitly handles SCDC state recovery
through a CRTC reset when the sink reconnects while the display pipeline
is active. Note that this does not interfere with the local SCDC
state-management implementation, since the driver's scrambler capability
has not yet been exposed through the common helpers.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
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 26c63ce2dc2f..7c921a444e98 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -505,7 +505,6 @@ static void vc4_hdmi_connector_reset(struct drm_connector *connector)
static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
.debugfs_init = drm_hdmi_connector_debugfs_init,
- .force = drm_atomic_helper_connector_hdmi_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.reset = vc4_hdmi_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -514,6 +513,7 @@ static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs = {
.detect_ctx = vc4_hdmi_connector_detect_ctx,
+ .force_ctx = drm_atomic_helper_connector_hdmi_force_ctx,
.get_modes = vc4_hdmi_connector_get_modes,
.atomic_check = vc4_hdmi_connector_atomic_check,
.mode_valid = drm_hdmi_connector_mode_valid,
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 4/7] drm/vc4: hdmi: Propagate -EDEADLK to the top level
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
` (2 preceding siblings ...)
2026-10-01 0:26 ` [PATCH 3/7] drm/vc4: hdmi: Switch to .force_ctx() connector helper Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 5/7] drm/vc4: hdmi: Convert to drmm_connector_hdmi_init() Cristian Ciocaltea
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
drm_connector_helper_funcs.detect_ctx() is expected to propagate
-EDEADLK so that context owners, e.g. drm_helper_probe_detect_ctx(), can
perform the required backoff and retry.
vc4_hdmi_handle_hotplug() instead runs its own retry loop and calls
drm_modeset_backoff() on an acquire context it does not own. This drops
all locks in the context, including connection_mutex held by the core.
Drop the local retry logic and propagate -EDEADLK to the caller instead.
This aligns VC4 with the expected detect_ctx() semantics.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 23 +++++++----------------
1 file changed, 7 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 7c921a444e98..6bd5aa77538e 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -344,12 +344,11 @@ static int vc4_hdmi_reset_link(struct drm_connector *connector,
return drm_atomic_helper_reset_crtc(crtc, ctx);
}
-static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
- struct drm_modeset_acquire_ctx *ctx,
- enum drm_connector_status status)
+static int vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
+ struct drm_modeset_acquire_ctx *ctx,
+ enum drm_connector_status status)
{
struct drm_connector *connector = &vc4_hdmi->connector;
- int ret;
/*
* NOTE: This function should really be called with vc4_hdmi->mutex
@@ -368,17 +367,9 @@ static void vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
if (status != connector_status_connected)
- return;
+ return 0;
- for (;;) {
- ret = vc4_hdmi_reset_link(connector, ctx);
- if (ret == -EDEADLK) {
- drm_modeset_backoff(ctx);
- continue;
- }
-
- break;
- }
+ return vc4_hdmi_reset_link(connector, ctx);
}
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
@@ -416,10 +407,10 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
pm_runtime_put(&vc4_hdmi->pdev->dev);
- return status;
+ return ret == -EDEADLK ? ret : status;
}
static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 5/7] drm/vc4: hdmi: Convert to drmm_connector_hdmi_init()
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
` (3 preceding siblings ...)
2026-10-01 0:26 ` [PATCH 4/7] drm/vc4: hdmi: Propagate -EDEADLK to the top level Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 6/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers Cristian Ciocaltea
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
Switch driver over to the new drmm_connector_hdmi_init() signature. The
vendor, product, supported_formats and max_bpc values previously passed
as arguments are now provided through struct drm_connector_hdmi_funcs,
together with the new supported_hdmi_ver field.
VC4 needs three distinct capability sets, based on the maximum TMDS
character rate and color depth supported by each controller variant:
RPi 0-3: 162 MHz (HDMI 1.2), 8-bit
RPi 4 (HDMI1): 340 MHz (HDMI 1.4), 12-bit
RPi 4 (HDMI0), RPi 5: 600 MHz (HDMI 2.0), 12-bit
Introduce three drm_connector_hdmi_funcs instances for these tiers and
assign them to the corresponding vc4_hdmi_variant entries. Additionally,
drop the now redundant .supports_hdr field of struct vc4_hdmi_variant.
As the callback members are identical across all three, factor the
shared initializers into a VC4_HDMI_CONNECTOR_FUNCS_COMMON macro to
avoid duplication, with each variant adding only its distinguishing
max_bpc/supported_hdmi_ver fields.
Note that HDMI 2.0 cannot be advertised at this point, since it requires
converting the driver to common scrambling infrastructure. This will be
handled separately, hence temporarily use HDMI_VERSION_UNKNOWN for the
related hdmi_funcs instance to skip generic scrambler and TMDS rate
validation, and continue to rely on current driver-local implementation.
No functional change intended.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 93 ++++++++++++++++++++++++------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 6 +--
2 files changed, 56 insertions(+), 43 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 6bd5aa77538e..a03e50e8afcb 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -510,7 +510,6 @@ static const struct drm_connector_helper_funcs vc4_hdmi_connector_helper_funcs =
.mode_valid = drm_hdmi_connector_mode_valid,
};
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs;
static const struct drm_connector_hdmi_audio_funcs vc4_hdmi_audio_funcs;
static int vc4_hdmi_connector_init(struct drm_device *dev,
@@ -518,22 +517,13 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
{
struct drm_connector *connector = &vc4_hdmi->connector;
struct drm_encoder *encoder = &vc4_hdmi->encoder.base;
- unsigned int max_bpc = 8;
int ret;
- if (vc4_hdmi->variant->supports_hdr)
- max_bpc = 12;
-
- ret = drmm_connector_hdmi_ini2(dev, connector,
- "Broadcom", "Videocore",
+ ret = drmm_connector_hdmi_init(dev, connector,
&vc4_hdmi_connector_funcs,
- &vc4_hdmi_hdmi_connector_funcs,
+ vc4_hdmi->variant->hdmi_funcs,
DRM_MODE_CONNECTOR_HDMIA,
- vc4_hdmi->ddc,
- BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) |
- BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444),
- max_bpc);
+ vc4_hdmi->ddc);
if (ret)
return ret;
@@ -1722,28 +1712,51 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
return MODE_OK;
}
-static const struct drm_connector_hdmi_funcs vc4_hdmi_hdmi_connector_funcs = {
- .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid,
- .avi = {
- .clear_infoframe = vc4_hdmi_clear_avi_infoframe,
- .write_infoframe = vc4_hdmi_write_avi_infoframe,
- },
- .hdmi = {
- .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe,
- .write_infoframe = vc4_hdmi_write_hdmi_infoframe,
- },
- .audio = {
- .clear_infoframe = vc4_hdmi_clear_audio_infoframe,
- .write_infoframe = vc4_hdmi_write_audio_infoframe,
- },
- .hdr_drm = {
- .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe,
- .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe,
- },
- .spd = {
- .clear_infoframe = vc4_hdmi_clear_spd_infoframe,
- .write_infoframe = vc4_hdmi_write_spd_infoframe,
- },
+#define VC4_HDMI_CONNECTOR_FUNCS_COMMON \
+ .vendor = "Broadcom", \
+ .product = "Videocore", \
+ .supported_formats = BIT(DRM_OUTPUT_COLOR_FORMAT_RGB444) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR422) | \
+ BIT(DRM_OUTPUT_COLOR_FORMAT_YCBCR444), \
+ .tmds_char_rate_valid = vc4_hdmi_connector_clock_valid, \
+ .avi = { \
+ .clear_infoframe = vc4_hdmi_clear_avi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_avi_infoframe, \
+ }, \
+ .hdmi = { \
+ .clear_infoframe = vc4_hdmi_clear_hdmi_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdmi_infoframe, \
+ }, \
+ .audio = { \
+ .clear_infoframe = vc4_hdmi_clear_audio_infoframe, \
+ .write_infoframe = vc4_hdmi_write_audio_infoframe, \
+ }, \
+ .hdr_drm = { \
+ .clear_infoframe = vc4_hdmi_clear_hdr_drm_infoframe, \
+ .write_infoframe = vc4_hdmi_write_hdr_drm_infoframe, \
+ }, \
+ .spd = { \
+ .clear_infoframe = vc4_hdmi_clear_spd_infoframe, \
+ .write_infoframe = vc4_hdmi_write_spd_infoframe, \
+ }
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 8,
+ .supported_hdmi_ver = HDMI_VERSION_1_2,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ .supported_hdmi_ver = HDMI_VERSION_1_4,
+};
+
+static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
+ VC4_HDMI_CONNECTOR_FUNCS_COMMON,
+ .max_bpc = 12,
+ /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
+ .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3359,7 +3372,7 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.phy_rng_enable = vc4_hdmi_phy_rng_enable,
.phy_rng_disable = vc4_hdmi_phy_rng_disable,
.channel_map = vc4_hdmi_channel_map,
- .supports_hdr = false,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi12,
};
static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
@@ -3387,8 +3400,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi0_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
@@ -3416,8 +3429,8 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.phy_rng_enable = vc5_hdmi_phy_rng_enable,
.phy_rng_disable = vc5_hdmi_phy_rng_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi14,
};
static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
@@ -3443,8 +3456,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
@@ -3470,8 +3483,8 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.phy_init = vc6_hdmi_phy_init,
.phy_disable = vc6_hdmi_phy_disable,
.channel_map = vc5_hdmi_channel_map,
- .supports_hdr = true,
.hp_detect = vc5_hdmi_hp_detect,
+ .hdmi_funcs = &vc4_hdmi_connector_funcs_hdmi20,
};
static const struct of_device_id vc4_hdmi_dt_match[] = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index 29d461d4ee49..d5ffcc17de32 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -90,11 +90,11 @@ struct vc4_hdmi_variant {
/* Callback to get channel map */
u32 (*channel_map)(struct vc4_hdmi *vc4_hdmi, u32 channel_mask);
- /* Enables HDR metadata */
- bool supports_hdr;
-
/* Callback for hardware specific hotplug detect */
bool (*hp_detect)(struct vc4_hdmi *vc4_hdmi);
+
+ /* HDMI-related connector callbacks and controller capabilities */
+ const struct drm_connector_hdmi_funcs *hdmi_funcs;
};
/* HDMI audio information */
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 6/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
` (4 preceding siblings ...)
2026-10-01 0:26 ` [PATCH 5/7] drm/vc4: hdmi: Convert to drmm_connector_hdmi_init() Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-01 0:26 ` [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers Cristian Ciocaltea
6 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
Replace driver local scrambling logic with the newly introduced common
HDMI 2.0 scrambling support:
- Advertise source-side scrambling capability by setting supported HDMI
version based on the variant's max_pixel_clock.
- Provide minimal .scrambler_{enable,disable} connector callbacks that
only toggle the VC5 HDMI_SCRAMBLER_CTL register, while delegating
sink-side SCDC programming and periodic status monitoring to
drm_connector_hdmi_{enable,disable}_scrambling().
- Drop vc4_hdmi_reset_link() and vc4_hdmi_handle_hotplug(), switching
the .detect_ctx() path to drm_atomic_helper_connector_hdmi_hotplug()
which internally calls drm_connector_hdmi_sync_scdc() to trigger a
CRTC reset on reconnection.
- Drop the local scrambling_work delayed workqueue and scdc_enabled
flag, now tracked by the common drm_connector_hdmi layer, as well as
the now unused output_{bpc,color_format} driver data members.
No functional change intended.
Acked-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 230 +++++------------------------------------
drivers/gpu/drm/vc4/vc4_hdmi.h | 21 ----
2 files changed, 28 insertions(+), 223 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index a03e50e8afcb..2451ff85e759 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -35,7 +35,6 @@
#include <drm/display/drm_hdmi_cec_helper.h>
#include <drm/display/drm_hdmi_helper.h>
#include <drm/display/drm_hdmi_state_helper.h>
-#include <drm/display/drm_scdc_helper.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
@@ -114,22 +113,6 @@
#define HSM_MIN_CLOCK_FREQ 120000000
#define CEC_CLOCK_FREQ 40000
-static bool vc4_hdmi_supports_scrambling(struct vc4_hdmi *vc4_hdmi)
-{
- struct drm_display_info *display = &vc4_hdmi->connector.display_info;
-
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!display->is_hdmi)
- return false;
-
- if (!display->hdmi.scdc.supported ||
- !display->hdmi.scdc.scrambling.supported)
- return false;
-
- return true;
-}
-
static int vc4_hdmi_debugfs_regs(struct seq_file *m, void *unused)
{
struct drm_debugfs_entry *entry = m->private;
@@ -263,115 +246,6 @@ static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi)
static void vc4_hdmi_cec_update_clk_div(struct vc4_hdmi *vc4_hdmi) {}
#endif
-static int vc4_hdmi_reset_link(struct drm_connector *connector,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_device *drm;
- struct vc4_hdmi *vc4_hdmi;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
- struct drm_crtc *crtc;
- bool scrambling_needed;
- u8 config;
- int ret;
-
- if (!connector)
- return 0;
-
- drm = connector->dev;
- ret = drm_modeset_lock(&drm->mode_config.connection_mutex, ctx);
- if (ret)
- return ret;
-
- conn_state = connector->state;
- crtc = conn_state->crtc;
- if (!crtc)
- return 0;
-
- ret = drm_modeset_lock(&crtc->mutex, ctx);
- if (ret)
- return ret;
-
- crtc_state = crtc->state;
- if (!crtc_state->active)
- return 0;
-
- vc4_hdmi = connector_to_vc4_hdmi(connector);
- mutex_lock(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- scrambling_needed = drm_hdmi_mode_needs_scrambling(&vc4_hdmi->saved_adjusted_mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format);
- if (!scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (conn_state->commit &&
- !try_wait_for_completion(&conn_state->commit->hw_done)) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- ret = drm_scdc_readb(connector->ddc, SCDC_TMDS_CONFIG, &config);
- if (ret < 0) {
- drm_err(drm, "Failed to read TMDS config: %d\n", ret);
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- if (!!(config & SCDC_SCRAMBLING_ENABLE) == scrambling_needed) {
- mutex_unlock(&vc4_hdmi->mutex);
- return 0;
- }
-
- mutex_unlock(&vc4_hdmi->mutex);
-
- /*
- * HDMI 2.0 says that one should not send scrambled data
- * prior to configuring the sink scrambling, and that
- * TMDS clock/data transmission should be suspended when
- * changing the TMDS clock rate in the sink. So let's
- * just do a full modeset here, even though some sinks
- * would be perfectly happy if were to just reconfigure
- * the SCDC settings on the fly.
- */
- return drm_atomic_helper_reset_crtc(crtc, ctx);
-}
-
-static int vc4_hdmi_handle_hotplug(struct vc4_hdmi *vc4_hdmi,
- struct drm_modeset_acquire_ctx *ctx,
- enum drm_connector_status status)
-{
- struct drm_connector *connector = &vc4_hdmi->connector;
-
- /*
- * NOTE: This function should really be called with vc4_hdmi->mutex
- * held, but doing so results in reentrancy issues since
- * cec_s_phys_addr() might call .adap_enable, which leads to that
- * funtion being called with our mutex held.
- *
- * A similar situation occurs with vc4_hdmi_reset_link() that
- * will call into our KMS hooks if the scrambling was enabled.
- *
- * Concurrency isn't an issue at the moment since we don't share
- * any state with any of the other frameworks so we can ignore
- * the lock for now.
- */
-
- drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
-
- if (status != connector_status_connected)
- return 0;
-
- return vc4_hdmi_reset_link(connector, ctx);
-}
-
static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
@@ -383,8 +257,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
/*
* NOTE: This function should really take vc4_hdmi->mutex, but
* doing so results in reentrancy issues since
- * vc4_hdmi_handle_hotplug() can call into other functions that
- * would take the mutex while it's held here.
+ * drm_atomic_helper_connector_hdmi_hotplug() can call into other
+ * functions that would take the mutex while it's held here.
*
* Concurrency isn't an issue at the moment since we don't share
* any state with any of the other frameworks so we can ignore
@@ -407,7 +281,8 @@ static int vc4_hdmi_connector_detect_ctx(struct drm_connector *connector,
status = connector_status_connected;
}
- ret = vc4_hdmi_handle_hotplug(vc4_hdmi, ctx, status);
+ ret = drm_atomic_helper_connector_hdmi_hotplug(connector, ctx, status);
+
pm_runtime_put(&vc4_hdmi->pdev->dev);
return ret == -EDEADLK ? ret : status;
@@ -535,6 +410,14 @@ static int vc4_hdmi_connector_init(struct drm_device *dev,
drm_connector_helper_add(connector, &vc4_hdmi_connector_helper_funcs);
+ /*
+ * Since we don't know the state of the controller and its
+ * display (if any), let's assume it's always enabled.
+ * drm_connector_hdmi_disable_scrambling() will thus run at boot,
+ * make sure it's disabled, and avoid any inconsistency.
+ */
+ connector->hdmi.scrambler_enabled = drm_connector_hdmi_scrambler_supported(connector);
+
/*
* Some of the properties below require access to state, like bpc.
* Allocate some default initial connector state with our reset helper.
@@ -760,32 +643,15 @@ static int vc4_hdmi_write_spd_infoframe(struct drm_connector *connector,
buffer, len);
}
-#define SCRAMBLING_POLLING_DELAY_MS 1000
-
-static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_enable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
- const struct drm_display_mode *mode = &vc4_hdmi->saved_adjusted_mode;
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi_supports_scrambling(vc4_hdmi))
- return;
-
- if (!drm_hdmi_mode_needs_scrambling(mode,
- vc4_hdmi->output_bpc,
- vc4_hdmi->output_format))
- return;
-
if (!drm_dev_enter(drm, &idx))
- return;
-
- drm_scdc_set_high_tmds_clock_ratio(connector, true);
- drm_scdc_set_scrambling(connector, true);
+ return 0;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) |
@@ -794,59 +660,27 @@ static void vc4_hdmi_enable_scrambling(struct drm_encoder *encoder)
drm_dev_exit(idx);
- vc4_hdmi->scdc_enabled = true;
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
-static void vc4_hdmi_disable_scrambling(struct drm_encoder *encoder)
+static int vc4_hdmi_scrambler_disable(struct drm_connector *connector)
{
- struct vc4_hdmi *vc4_hdmi = encoder_to_vc4_hdmi(encoder);
- struct drm_connector *connector = &vc4_hdmi->connector;
+ struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct drm_device *drm = connector->dev;
unsigned long flags;
int idx;
- lockdep_assert_held(&vc4_hdmi->mutex);
-
- if (!vc4_hdmi->scdc_enabled)
- return;
-
- vc4_hdmi->scdc_enabled = false;
-
- if (delayed_work_pending(&vc4_hdmi->scrambling_work))
- cancel_delayed_work_sync(&vc4_hdmi->scrambling_work);
-
if (!drm_dev_enter(drm, &idx))
- return;
+ return 0;
spin_lock_irqsave(&vc4_hdmi->hw_lock, flags);
HDMI_WRITE(HDMI_SCRAMBLER_CTL, HDMI_READ(HDMI_SCRAMBLER_CTL) &
~VC5_HDMI_SCRAMBLER_CTL_ENABLE);
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
- drm_scdc_set_scrambling(connector, false);
- drm_scdc_set_high_tmds_clock_ratio(connector, false);
-
drm_dev_exit(idx);
-}
-static void vc4_hdmi_scrambling_wq(struct work_struct *work)
-{
- struct vc4_hdmi *vc4_hdmi = container_of(to_delayed_work(work),
- struct vc4_hdmi,
- scrambling_work);
- struct drm_connector *connector = &vc4_hdmi->connector;
-
- if (drm_scdc_get_scrambling_status(connector))
- return;
-
- drm_scdc_set_high_tmds_clock_ratio(connector, true);
- drm_scdc_set_scrambling(connector, true);
-
- queue_delayed_work(system_percpu_wq, &vc4_hdmi->scrambling_work,
- msecs_to_jiffies(SCRAMBLING_POLLING_DELAY_MS));
+ return 0;
}
static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
@@ -891,7 +725,7 @@ static void vc4_hdmi_encoder_post_crtc_disable(struct drm_encoder *encoder,
spin_unlock_irqrestore(&vc4_hdmi->hw_lock, flags);
}
- vc4_hdmi_disable_scrambling(encoder);
+ drm_connector_hdmi_disable_scrambling(&vc4_hdmi->connector);
drm_dev_exit(idx);
@@ -1599,6 +1433,7 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
struct drm_display_info *display = &vc4_hdmi->connector.display_info;
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
+ struct drm_connector_state *conn_state;
unsigned long flags;
int ret;
int idx;
@@ -1667,7 +1502,9 @@ static void vc4_hdmi_encoder_post_crtc_enable(struct drm_encoder *encoder,
}
vc4_hdmi_recenter_fifo(vc4_hdmi);
- vc4_hdmi_enable_scrambling(encoder);
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ drm_connector_hdmi_enable_scrambling(connector, conn_state);
drm_dev_exit(idx);
@@ -1684,8 +1521,6 @@ static void vc4_hdmi_encoder_atomic_mode_set(struct drm_encoder *encoder,
mutex_lock(&vc4_hdmi->mutex);
drm_mode_copy(&vc4_hdmi->saved_adjusted_mode,
&crtc_state->adjusted_mode);
- vc4_hdmi->output_bpc = conn_state->hdmi.output_bpc;
- vc4_hdmi->output_format = conn_state->hdmi.output_format;
mutex_unlock(&vc4_hdmi->mutex);
}
@@ -1755,8 +1590,9 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi20 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 12,
- /* TODO: set HDMI_VERSION_2_0 and convert to common scrambler infra */
- .supported_hdmi_ver = HDMI_VERSION_UNKNOWN,
+ .supported_hdmi_ver = HDMI_VERSION_2_0,
+ .scrambler_enable = vc4_hdmi_scrambler_enable,
+ .scrambler_disable = vc4_hdmi_scrambler_disable,
};
#define WIFI_2_4GHz_CH1_MIN_FREQ 2400000000ULL
@@ -3230,7 +3066,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
return ret;
spin_lock_init(&vc4_hdmi->hw_lock);
- INIT_DELAYED_WORK(&vc4_hdmi->scrambling_work, vc4_hdmi_scrambling_wq);
dev_set_drvdata(dev, vc4_hdmi);
encoder = &vc4_hdmi->encoder.base;
@@ -3243,15 +3078,6 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
vc4_hdmi->pdev = pdev;
vc4_hdmi->variant = variant;
- /*
- * Since we don't know the state of the controller and its
- * display (if any), let's assume it's always enabled.
- * vc4_hdmi_disable_scrambling() will thus run at boot, make
- * sure it's disabled, and avoid any inconsistency.
- */
- if (variant->max_pixel_clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
- vc4_hdmi->scdc_enabled = true;
-
ret = variant->init_resources(drm, vc4_hdmi);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index d5ffcc17de32..f6159c9e6144 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -118,8 +118,6 @@ struct vc4_hdmi {
struct vc4_encoder encoder;
struct drm_connector connector;
- struct delayed_work scrambling_work;
-
struct i2c_adapter *ddc;
void __iomem *hdmicore_regs;
void __iomem *hd_regs;
@@ -193,25 +191,6 @@ struct vc4_hdmi {
*/
bool packet_ram_enabled;
- /**
- * @scdc_enabled: Is the HDMI controller currently running with
- * the scrambler on? Protected by @mutex.
- */
- bool scdc_enabled;
-
- /**
- * @output_bpc: Copy of @drm_connector_state.hdmi.output_bpc for
- * use outside of KMS hooks. Protected by @mutex.
- */
- unsigned int output_bpc;
-
- /**
- * @output_format: Copy of
- * @drm_connector_state.hdmi.output_format for use outside of
- * KMS hooks. Protected by @mutex.
- */
- enum drm_output_color_format output_format;
-
/**
* @hdmi_jack: Represents the connection state of the HDMI plug, for
* ALSA jack detection.
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
2026-10-01 0:26 [PATCH 0/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
` (5 preceding siblings ...)
2026-10-01 0:26 ` [PATCH 6/7] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Cristian Ciocaltea
@ 2026-10-01 0:26 ` Cristian Ciocaltea
2026-10-08 18:01 ` Dave Stevenson
6 siblings, 1 reply; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-01 0:26 UTC (permalink / raw)
To: Maxime Ripard, Dave Stevenson, Maíra Canal,
Raspberry Pi Kernel Maintenance, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter
Cc: kernel, dri-devel, linux-kernel
drm_atomic_helper_connector_hdmi_check() rejects modes whose computed
TMDS character rate exceeds the connector limit before invoking the
driver's .tmds_char_rate_valid() hook.
BCM2835 is capped at 162 MHz, slightly below the 165 MHz limit of HDMI
1.2. Set supported_tmds_char_rate in vc4_hdmi_connector_funcs_hdmi10 so
that the limit inferred from supported_hdmi_ver is overridden by the
lower hardware constraint. All other chip variants rely on the standard
HDMI 1.4/2.0 limits, so the default validation suffices.
This allows vc4_hdmi_connector_clock_valid() to be simplified by
dropping the now-redundant max_pixel_clock field from struct
vc4_hdmi_variant.
Reviewed-by: Maxime Ripard <mripard@kernel.org>
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
---
drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +---------
drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ---
2 files changed, 1 insertion(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 2451ff85e759..6d3db0d24c38 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -1529,12 +1529,8 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
const struct drm_display_mode *mode,
unsigned long long clock)
{
- const struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
- if (clock > vc4_hdmi->variant->max_pixel_clock)
- return MODE_CLOCK_HIGH;
-
if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
return MODE_CLOCK_HIGH;
@@ -1579,6 +1575,7 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
VC4_HDMI_CONNECTOR_FUNCS_COMMON,
.max_bpc = 8,
.supported_hdmi_ver = HDMI_VERSION_1_2,
+ .supported_tmds_char_rate = 162000000,
};
static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
@@ -3185,7 +3182,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi_regs",
.card_name = "vc4-hdmi",
- .max_pixel_clock = 162000000,
.registers = vc4_hdmi_fields,
.num_registers = ARRAY_SIZE(vc4_hdmi_fields),
@@ -3205,7 +3201,6 @@ 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_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3234,7 +3229,6 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc5_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
.phy_lane_mapping = {
@@ -3263,7 +3257,6 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI0,
.debugfs_name = "hdmi0_regs",
.card_name = "vc4-hdmi-0",
- .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi0_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
.phy_lane_mapping = {
@@ -3290,7 +3283,6 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
.encoder_type = VC4_ENCODER_TYPE_HDMI1,
.debugfs_name = "hdmi1_regs",
.card_name = "vc4-hdmi-1",
- .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
.registers = vc6_hdmi_hdmi1_fields,
.num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
.phy_lane_mapping = {
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
index f6159c9e6144..61486e7b4ba2 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
@@ -29,9 +29,6 @@ struct vc4_hdmi_variant {
/* Filename to expose the registers in debugfs */
const char *debugfs_name;
- /* 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;
--
2.55.0
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
2026-10-01 0:26 ` [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers Cristian Ciocaltea
@ 2026-10-08 18:01 ` Dave Stevenson
2026-10-11 22:00 ` Cristian Ciocaltea
0 siblings, 1 reply; 10+ messages in thread
From: Dave Stevenson @ 2026-10-08 18:01 UTC (permalink / raw)
To: Cristian Ciocaltea
Cc: Maxime Ripard, Maíra Canal, Raspberry Pi Kernel Maintenance,
Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, kernel, dri-devel, linux-kernel
Hi Cristian
Sorry for coming in late on this one.
On Thu, 1 Oct 2026 at 01:27, Cristian Ciocaltea
<cristian.ciocaltea@collabora.com> wrote:
>
> drm_atomic_helper_connector_hdmi_check() rejects modes whose computed
> TMDS character rate exceeds the connector limit before invoking the
> driver's .tmds_char_rate_valid() hook.
>
> BCM2835 is capped at 162 MHz, slightly below the 165 MHz limit of HDMI
> 1.2.
Nothing I have says that BCM2835 is HDMI capped at 162MHz.
Working back through the history, originally the HSM clock was always
set to 163.7MHz and the pixel rate had to be >1% below that, hence
below 162MHz.
However that was reworked so that the HSM clock rate is now set to the
pixel clock * 101/100.
The HSM clock can run at 166.65MHz without issue, so a pixel clock of
165MHz is fine.
Dave
> Set supported_tmds_char_rate in vc4_hdmi_connector_funcs_hdmi10 so
> that the limit inferred from supported_hdmi_ver is overridden by the
> lower hardware constraint. All other chip variants rely on the standard
> HDMI 1.4/2.0 limits, so the default validation suffices.
>
> This allows vc4_hdmi_connector_clock_valid() to be simplified by
> dropping the now-redundant max_pixel_clock field from struct
> vc4_hdmi_variant.
>
> Reviewed-by: Maxime Ripard <mripard@kernel.org>
> Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
> ---
> drivers/gpu/drm/vc4/vc4_hdmi.c | 10 +---------
> drivers/gpu/drm/vc4/vc4_hdmi.h | 3 ---
> 2 files changed, 1 insertion(+), 12 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
> index 2451ff85e759..6d3db0d24c38 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
> @@ -1529,12 +1529,8 @@ vc4_hdmi_connector_clock_valid(const struct drm_connector *connector,
> const struct drm_display_mode *mode,
> unsigned long long clock)
> {
> - const struct vc4_hdmi *vc4_hdmi = connector_to_vc4_hdmi(connector);
> struct vc4_dev *vc4 = to_vc4_dev(connector->dev);
>
> - if (clock > vc4_hdmi->variant->max_pixel_clock)
> - return MODE_CLOCK_HIGH;
> -
> if (!vc4->hvs->vc5_hdmi_enable_hdmi_20 && clock > HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ)
> return MODE_CLOCK_HIGH;
>
> @@ -1579,6 +1575,7 @@ static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi12 = {
> VC4_HDMI_CONNECTOR_FUNCS_COMMON,
> .max_bpc = 8,
> .supported_hdmi_ver = HDMI_VERSION_1_2,
> + .supported_tmds_char_rate = 162000000,
> };
>
> static const struct drm_connector_hdmi_funcs vc4_hdmi_connector_funcs_hdmi14 = {
> @@ -3185,7 +3182,6 @@ static const struct vc4_hdmi_variant bcm2835_variant = {
> .encoder_type = VC4_ENCODER_TYPE_HDMI0,
> .debugfs_name = "hdmi_regs",
> .card_name = "vc4-hdmi",
> - .max_pixel_clock = 162000000,
> .registers = vc4_hdmi_fields,
> .num_registers = ARRAY_SIZE(vc4_hdmi_fields),
>
> @@ -3205,7 +3201,6 @@ 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_2_0_TMDS_CHAR_RATE_MAX_HZ,
> .registers = vc5_hdmi_hdmi0_fields,
> .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi0_fields),
> .phy_lane_mapping = {
> @@ -3234,7 +3229,6 @@ static const struct vc4_hdmi_variant bcm2711_hdmi1_variant = {
> .encoder_type = VC4_ENCODER_TYPE_HDMI1,
> .debugfs_name = "hdmi1_regs",
> .card_name = "vc4-hdmi-1",
> - .max_pixel_clock = HDMI_1_3_TMDS_CHAR_RATE_MAX_HZ,
> .registers = vc5_hdmi_hdmi1_fields,
> .num_registers = ARRAY_SIZE(vc5_hdmi_hdmi1_fields),
> .phy_lane_mapping = {
> @@ -3263,7 +3257,6 @@ static const struct vc4_hdmi_variant bcm2712_hdmi0_variant = {
> .encoder_type = VC4_ENCODER_TYPE_HDMI0,
> .debugfs_name = "hdmi0_regs",
> .card_name = "vc4-hdmi-0",
> - .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
> .registers = vc6_hdmi_hdmi0_fields,
> .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi0_fields),
> .phy_lane_mapping = {
> @@ -3290,7 +3283,6 @@ static const struct vc4_hdmi_variant bcm2712_hdmi1_variant = {
> .encoder_type = VC4_ENCODER_TYPE_HDMI1,
> .debugfs_name = "hdmi1_regs",
> .card_name = "vc4-hdmi-1",
> - .max_pixel_clock = HDMI_2_0_TMDS_CHAR_RATE_MAX_HZ,
> .registers = vc6_hdmi_hdmi1_fields,
> .num_registers = ARRAY_SIZE(vc6_hdmi_hdmi1_fields),
> .phy_lane_mapping = {
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.h b/drivers/gpu/drm/vc4/vc4_hdmi.h
> index f6159c9e6144..61486e7b4ba2 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi.h
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi.h
> @@ -29,9 +29,6 @@ struct vc4_hdmi_variant {
> /* Filename to expose the registers in debugfs */
> const char *debugfs_name;
>
> - /* 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;
>
>
> --
> 2.55.0
>
^ permalink raw reply [flat|nested] 10+ messages in thread* Re: [PATCH 7/7] drm/vc4: hdmi: Defer pixel clock validation to HDMI helpers
2026-10-08 18:01 ` Dave Stevenson
@ 2026-10-11 22:00 ` Cristian Ciocaltea
0 siblings, 0 replies; 10+ messages in thread
From: Cristian Ciocaltea @ 2026-10-11 22:00 UTC (permalink / raw)
To: Dave Stevenson
Cc: Maxime Ripard, Maíra Canal, Raspberry Pi Kernel Maintenance,
Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, kernel, dri-devel, linux-kernel
Hi Dave,
On 10/8/26 9:01 PM, Dave Stevenson wrote:
> Hi Cristian
>
> Sorry for coming in late on this one.
>
> On Thu, 1 Oct 2026 at 01:27, Cristian Ciocaltea
> <cristian.ciocaltea@collabora.com> wrote:
>>
>> drm_atomic_helper_connector_hdmi_check() rejects modes whose computed
>> TMDS character rate exceeds the connector limit before invoking the
>> driver's .tmds_char_rate_valid() hook.
>>
>> BCM2835 is capped at 162 MHz, slightly below the 165 MHz limit of HDMI
>> 1.2.
>
> Nothing I have says that BCM2835 is HDMI capped at 162MHz.
> Working back through the history, originally the HSM clock was always
> set to 163.7MHz and the pixel rate had to be >1% below that, hence
> below 162MHz.
>
> However that was reworked so that the HSM clock rate is now set to the
> pixel clock * 101/100.
> The HSM clock can run at 166.65MHz without issue, so a pixel clock of
> 165MHz is fine.
Thanks for checking this out.
Since that would be a functional change, I think it's worth introducing a
dedicated patch, acting as a prerequisite to the current one. I'll handle it
in v2.
Speaking of which, assuming no additional changes are required, would you be
able to merge the series afterwards? That would get us one step closer to
finalizing the infrastructure cleanup.
Cristian
^ permalink raw reply [flat|nested] 10+ messages in thread