From patchwork Tue Sep 1 18:51:11 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Cristian Ciocaltea X-Patchwork-Id: 3129 Return-Path: X-Original-To: noreply@patchwork.local Delivered-To: noreply@patchwork.local Received: from sea.lore.kernel.org (sea.lore.kernel.org [172.234.253.10]) by mxe881.netcup.net (Postfix) with ESMTPS id 751651C0066 for ; Tue, 1 Sep 2026 21:55:14 +0200 (CEST) Authentication-Results: mxe881; dkim=pass header.d=collabora.com; spf=pass (sender IP is 172.234.253.10) smtp.mailfrom=linux-sunxi+bounces-25439-noreply=patchwork.local@lists.linux.dev smtp.helo=sea.lore.kernel.org Received-SPF: pass (mxe881: domain of lists.linux.dev designates 172.234.253.10 as permitted sender) client-ip=172.234.253.10; envelope-from=linux-sunxi+bounces-25439-noreply=patchwork.local@lists.linux.dev; helo=sea.lore.kernel.org; Received: from smtp.subspace.kernel.org (conduit.subspace.kernel.org [100.90.174.1]) by sea.lore.kernel.org (Postfix) with ESMTP id 961F812814C for ; Tue, 1 Sep 2026 18:56:31 +0000 (UTC) Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 9711E4A8413; Tue, 1 Sep 2026 18:51:22 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="leSEDaWE" X-Original-To: linux-sunxi@lists.linux.dev Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 2FA084A64C9 for ; Tue, 1 Sep 2026 18:51:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788288682; cv=none; b=az6tZH0sj6HYjVJPfMA7qxoopdOgoIBACxwLCEBS/StLglcMWdsLDaeJ9c57M5YT+Xet/Uq/0ZLW51KBMuktbUxAD+lhhoMkMJAvzNau160vEaCyx42Glb9ZTn51R6rK7VHyw7m5+MMSD0bX4TTXKK4yKAV8d89WDC0jZjk47bI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788288682; c=relaxed/simple; bh=Fd31gx+8nH7NnmF/4yMZ/lSFjp4BKvqcvH1y78FnRDg=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=KEczOimMREPxvm/4SUJY1qCwbReqckrGh0e31Y8vo+lrVnMticXQ262QJfp02w8KRNDjBiz4UlvixRy9aZGZ9zXHjS5+4IIvr0Jr+3zQQciV8MLy/uYAYl0dpadC2JRc0w32m8dR8box1iNrTv5Anynt9M3DTbbpS/r4YKqn130= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=leSEDaWE; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1788288675; bh=Fd31gx+8nH7NnmF/4yMZ/lSFjp4BKvqcvH1y78FnRDg=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=leSEDaWECBjPHjnsGE2QnD+yyaANIn/pnrYM+mRIeG4OjfIFhtZOEZZYnc3HEHNOU 0KQ8EJZVD3EwxIvlnKCFWlfTMKpKfYYhpS3Dxvwag8UXiRhzR8k1XBQTG+SpXNnssw rhf02a3NDecn9QtFscb6+RMgjvZN+O5wK/XcC3vJLS+xTvZJPxA1MoVdy1W/30ah12 tAVHrz9pliFz6K3YZg+OOnjA+efsY4zUyFmOOZm11q4f1PKBv4Fj2U4Y3D3CNLELc0 FC5BD2bEyhWhg9zLBb1EXglmxawX00+H5wJgvGzENJ3jYE7KvPYLfPWuDNw31RCOvA Cfv6IWLfyS4AQ== Received: from localhost (unknown [100.64.0.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange secp256r1 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: cristicc) by bali.collaboradmins.com (Postfix) with ESMTPSA id B735717E3C6A; Tue, 01 Sep 2026 20:51:15 +0200 (CEST) From: Cristian Ciocaltea Date: Tue, 01 Sep 2026 21:51:11 +0300 Subject: [PATCH v11 47/74] drm/vc4: hdmi: Convert to common HDMI 2.0 scrambling infrastructure Precedence: bulk X-Mailing-List: linux-sunxi@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Message-Id: <20260901-dw-hdmi-qp-scramb-v11-47-bc12954a0688@collabora.com> References: <20260901-dw-hdmi-qp-scramb-v11-0-bc12954a0688@collabora.com> In-Reply-To: <20260901-dw-hdmi-qp-scramb-v11-0-bc12954a0688@collabora.com> To: Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , David Airlie , Simona Vetter , Dave Stevenson , Dmitry Baryshkov , Andrzej Hajda , Neil Armstrong , Robert Foss , Laurent Pinchart , Jonas Karlman , Jernej Skrabec , Luca Ceresoli , Chen-Yu Tsai , Samuel Holland , =?utf-8?q?Ma=C3=ADra_Canal?= , Raspberry Pi Kernel Maintenance , Raphael Gallais-Pou , Sandy Huang , =?utf-8?q?Heiko_St=C3=BCbner?= , Andy Yan , Algea Cao , Daniel Stone , Liu Ying , Phong LE , Helge Deller Cc: kernel@collabora.com, linux-kernel@vger.kernel.org, dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-sunxi@lists.linux.dev, linux-rockchip@lists.infradead.org, linux-fbdev@vger.kernel.org X-Mailer: b4 0.15.2 X-MORS-Enabled: yes X-MORS-DOMAIN: patchwork.local X-MORS-HOSTING: hosting172546 X-MORS-USER: hosting172546 X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= 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. Signed-off-by: Cristian Ciocaltea --- 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 #include #include -#include #include #include #include @@ -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.