From nobody Mon Feb 9 03:14:06 2026 Received: from srv01.abscue.de (abscue.de [89.58.28.240]) (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 8925D2EBB9E; Tue, 22 Jul 2025 14:41:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=89.58.28.240 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753195316; cv=none; b=XVAWzi4oNwEkYmDrUOzmtdDsusphII7gF8DhjMmKGt/Bz+bB3IvBQ3i/tbvgqVi6eSnutlMViht9djE9D4FwSX1XROP66pcumOxm6QmrY68ILpotrcaz5QKs6Xl1OJ48S/Z+Bc6urjrsQXLF22kxSNPwOOXbyQZM/3I0S7y5zEg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753195316; c=relaxed/simple; bh=4r2vDCLvSqxe7kXzFYLqrXmuU0H4GqHjqzMSESXkuck=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=IRddLO2AdOEx9groI93QDzuMmCUrcZgiRx9PvF8Et+52Y94fasSZ5VSmZ1hmg2olGLL8ic4W1Lhm8uXLfQinouDT13dpzazPJODmYMDepiVUeRu9OhG6OaV1t24zqwnKA27eD1Bx1jQNbNLHhTF5QyrG7DhomSkJK9oHrJfIg10= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=abscue.de; spf=pass smtp.mailfrom=abscue.de; arc=none smtp.client-ip=89.58.28.240 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=abscue.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=abscue.de Received: from srv01.abscue.de (localhost [127.0.0.1]) by spamfilter.srv.local (Postfix) with ESMTP id 33EE81C0680; Tue, 22 Jul 2025 16:41:42 +0200 (CEST) X-Spam-Level: Received: from fluffy-mammal.metal.fwg-cag.de (unknown [IPv6:2001:9e8:cdcb:3c00:ce39:8bff:5db4:1ef8]) by srv01.abscue.de (Postfix) with ESMTPSA id A606E1C06E1; Tue, 22 Jul 2025 16:41:39 +0200 (CEST) From: =?utf-8?q?Otto_Pfl=C3=BCger?= Date: Tue, 22 Jul 2025 16:41:08 +0200 Subject: [PATCH v2 06/15] drm: sprd: register a DSI bridge and move init code to pre_enable Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250722-ums9230-drm-v2-6-054276ec213d@abscue.de> References: <20250722-ums9230-drm-v2-0-054276ec213d@abscue.de> In-Reply-To: <20250722-ums9230-drm-v2-0-054276ec213d@abscue.de> To: David Airlie , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Orson Zhai , Baolin Wang , Chunyan Zhang , Kevin Tang Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, =?utf-8?q?Otto_Pfl=C3=BCger?= X-Mailer: b4 0.14.2 If a panel needs to send DSI commands during initialization, it sets the prepare_prev_first flag, which allows the DSI host to initialize itself before the panel's prepare function is called. To support this, the DSI host must register a bridge and perform the necessary initialization steps in its pre_enable function. Implement this for the Unisoc DSI driver by moving the initialization code from the encoder callbacks to a bridge and simplify the remaining encoder-related code which no longer needs any callbacks. Signed-off-by: Otto Pfl=C3=BCger --- drivers/gpu/drm/sprd/Kconfig | 2 + drivers/gpu/drm/sprd/sprd_dsi.c | 143 +++++++++++++++++++++++++-----------= ---- drivers/gpu/drm/sprd/sprd_dsi.h | 6 +- 3 files changed, 97 insertions(+), 54 deletions(-) diff --git a/drivers/gpu/drm/sprd/Kconfig b/drivers/gpu/drm/sprd/Kconfig index e22b780fe82248296a7153d02269faf8cd63294f..1afcdbf6f0ee3304f2297835241= c9bb10d422154 100644 --- a/drivers/gpu/drm/sprd/Kconfig +++ b/drivers/gpu/drm/sprd/Kconfig @@ -2,6 +2,8 @@ config DRM_SPRD tristate "DRM Support for Unisoc SoCs Platform" depends on ARCH_SPRD || COMPILE_TEST depends on DRM && OF + select DRM_BRIDGE_CONNECTOR + select DRM_DISPLAY_HELPER select DRM_GEM_DMA_HELPER select DRM_KMS_HELPER select DRM_MIPI_DSI diff --git a/drivers/gpu/drm/sprd/sprd_dsi.c b/drivers/gpu/drm/sprd/sprd_ds= i.c index 23b0e1dc547a5023ee6ad7d5e1c49e2cec986bf0..43fff12d73f12619da57606a3c4= 785924e2c1507 100644 --- a/drivers/gpu/drm/sprd/sprd_dsi.c +++ b/drivers/gpu/drm/sprd/sprd_dsi.c @@ -11,8 +11,10 @@ =20 #include #include +#include #include #include +#include =20 #include "sprd_drm.h" #include "sprd_dpu.h" @@ -778,19 +780,53 @@ static void sprd_dphy_fini(struct dsi_context *ctx) dsi_reg_up(ctx, PHY_INTERFACE_CTRL, RF_PHY_RESET_N, RF_PHY_RESET_N); } =20 -static void sprd_dsi_encoder_mode_set(struct drm_encoder *encoder, - struct drm_display_mode *mode, - struct drm_display_mode *adj_mode) +static int sprd_dsi_encoder_init(struct sprd_dsi *dsi, + struct device *dev) +{ + struct drm_encoder *encoder =3D &dsi->encoder; + u32 crtc_mask; + int ret; + + crtc_mask =3D drm_of_find_possible_crtcs(dsi->drm, dev->of_node); + if (!crtc_mask) { + drm_err(dsi->drm, "failed to find crtc mask\n"); + return -EINVAL; + } + + drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask); + + encoder->possible_crtcs =3D crtc_mask; + ret =3D drm_simple_encoder_init(dsi->drm, encoder, DRM_MODE_ENCODER_DSI); + if (ret) { + drm_err(dsi->drm, "failed to init dsi encoder\n"); + return ret; + } + + return 0; +} + +static int sprd_dsi_bridge_attach(struct drm_bridge *bridge, + struct drm_encoder *encoder, + enum drm_bridge_attach_flags flags) +{ + struct sprd_dsi *dsi =3D bridge_to_dsi(bridge); + + return drm_bridge_attach(&dsi->encoder, dsi->panel_bridge, + bridge, flags); +} + +static void sprd_dsi_bridge_mode_set(struct drm_bridge *bridge, + const struct drm_display_mode *mode, + const struct drm_display_mode *adj_mode) { - struct sprd_dsi *dsi =3D encoder_to_dsi(encoder); + struct sprd_dsi *dsi =3D bridge_to_dsi(bridge); =20 drm_display_mode_to_videomode(adj_mode, &dsi->ctx.vm); } =20 -static void sprd_dsi_encoder_enable(struct drm_encoder *encoder) +static void sprd_dsi_bridge_pre_enable(struct drm_bridge *bridge) { - struct sprd_dsi *dsi =3D encoder_to_dsi(encoder); - struct sprd_dpu *dpu =3D to_sprd_crtc(encoder->crtc); + struct sprd_dsi *dsi =3D bridge_to_dsi(bridge); struct dsi_context *ctx =3D &dsi->ctx; =20 if (ctx->enabled) { @@ -819,15 +855,15 @@ static void sprd_dsi_encoder_enable(struct drm_encode= r *encoder) dphy_wait_pll_locked(ctx); } =20 - sprd_dpu_run(dpu); + /* DSI commands cannot be issued unless the DPU is running. */ + sprd_dpu_run(to_sprd_crtc(dsi->encoder.crtc)); =20 ctx->enabled =3D true; } =20 -static void sprd_dsi_encoder_disable(struct drm_encoder *encoder) +static void sprd_dsi_bridge_post_disable(struct drm_bridge *bridge) { - struct sprd_dsi *dsi =3D encoder_to_dsi(encoder); - struct sprd_dpu *dpu =3D to_sprd_crtc(encoder->crtc); + struct sprd_dsi *dsi =3D bridge_to_dsi(bridge); struct dsi_context *ctx =3D &dsi->ctx; =20 if (!ctx->enabled) { @@ -835,51 +871,21 @@ static void sprd_dsi_encoder_disable(struct drm_encod= er *encoder) return; } =20 - sprd_dpu_stop(dpu); + sprd_dpu_stop(to_sprd_crtc(dsi->encoder.crtc)); + sprd_dphy_fini(ctx); sprd_dsi_fini(ctx); =20 ctx->enabled =3D false; } =20 -static const struct drm_encoder_helper_funcs sprd_encoder_helper_funcs =3D= { - .mode_set =3D sprd_dsi_encoder_mode_set, - .enable =3D sprd_dsi_encoder_enable, - .disable =3D sprd_dsi_encoder_disable +static const struct drm_bridge_funcs sprd_dsi_bridge_funcs =3D { + .attach =3D sprd_dsi_bridge_attach, + .mode_set =3D sprd_dsi_bridge_mode_set, + .pre_enable =3D sprd_dsi_bridge_pre_enable, + .post_disable =3D sprd_dsi_bridge_post_disable, }; =20 -static const struct drm_encoder_funcs sprd_encoder_funcs =3D { - .destroy =3D drm_encoder_cleanup, -}; - -static int sprd_dsi_encoder_init(struct sprd_dsi *dsi, - struct device *dev) -{ - struct drm_encoder *encoder =3D &dsi->encoder; - u32 crtc_mask; - int ret; - - crtc_mask =3D drm_of_find_possible_crtcs(dsi->drm, dev->of_node); - if (!crtc_mask) { - drm_err(dsi->drm, "failed to find crtc mask\n"); - return -EINVAL; - } - - drm_dbg(dsi->drm, "find possible crtcs: 0x%08x\n", crtc_mask); - - encoder->possible_crtcs =3D crtc_mask; - ret =3D drm_encoder_init(dsi->drm, encoder, &sprd_encoder_funcs, - DRM_MODE_ENCODER_DSI, NULL); - if (ret) { - drm_err(dsi->drm, "failed to init dsi encoder\n"); - return ret; - } - - drm_encoder_helper_add(encoder, &sprd_encoder_helper_funcs); - - return 0; -} - static int sprd_dsi_bridge_init(struct sprd_dsi *dsi, struct device *dev) { @@ -889,11 +895,35 @@ static int sprd_dsi_bridge_init(struct sprd_dsi *dsi, if (IS_ERR(dsi->panel_bridge)) return PTR_ERR(dsi->panel_bridge); =20 - ret =3D drm_bridge_attach(&dsi->encoder, dsi->panel_bridge, NULL, 0); + dsi->bridge.funcs =3D &sprd_dsi_bridge_funcs; + dsi->bridge.of_node =3D dev->of_node; + dsi->bridge.type =3D DRM_MODE_CONNECTOR_DSI; + + drm_bridge_add(&dsi->bridge); + + ret =3D drm_bridge_attach(&dsi->encoder, &dsi->bridge, NULL, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) - return ret; + goto err_cleanup; + + dsi->connector =3D drm_bridge_connector_init(dsi->drm, &dsi->encoder); + if (IS_ERR(dsi->connector)) { + drm_err(dsi->drm, "Unable to create bridge connector\n"); + ret =3D PTR_ERR(dsi->connector); + goto err_cleanup; + } + + ret =3D drm_connector_attach_encoder(dsi->connector, &dsi->encoder); + if (ret < 0) + goto err_cleanup; =20 return 0; + +err_cleanup: + drm_bridge_remove(&dsi->bridge); + drm_of_panel_bridge_remove(dev->of_node, 1, 0); + + return ret; } =20 static int sprd_dsi_context_init(struct sprd_dsi *dsi, @@ -940,13 +970,21 @@ static int sprd_dsi_bind(struct device *dev, struct d= evice *master, void *data) =20 ret =3D sprd_dsi_bridge_init(dsi, dev); if (ret) - return ret; + goto err_cleanup_encoder; =20 ret =3D sprd_dsi_context_init(dsi, dev); if (ret) - return ret; + goto err_cleanup_bridge; =20 return 0; + +err_cleanup_encoder: + drm_encoder_cleanup(&dsi->encoder); +err_cleanup_bridge: + drm_bridge_remove(&dsi->bridge); + drm_of_panel_bridge_remove(dev->of_node, 1, 0); + + return ret; } =20 static void sprd_dsi_unbind(struct device *dev, @@ -954,6 +992,7 @@ static void sprd_dsi_unbind(struct device *dev, { struct sprd_dsi *dsi =3D dev_get_drvdata(dev); =20 + drm_bridge_remove(&dsi->bridge); drm_of_panel_bridge_remove(dev->of_node, 1, 0); =20 drm_encoder_cleanup(&dsi->encoder); diff --git a/drivers/gpu/drm/sprd/sprd_dsi.h b/drivers/gpu/drm/sprd/sprd_ds= i.h index d858ebb111150546e99403a87bc7cea42cad0158..1956ead3237a17ada14804302ec= 3d7dadd8ddab0 100644 --- a/drivers/gpu/drm/sprd/sprd_dsi.h +++ b/drivers/gpu/drm/sprd/sprd_dsi.h @@ -18,8 +18,8 @@ #include #include =20 -#define encoder_to_dsi(encoder) \ - container_of(encoder, struct sprd_dsi, encoder) +#define bridge_to_dsi(x) container_of(x, struct sprd_dsi, bridge) +#define encoder_to_dsi(x) container_of(x, struct sprd_dsi, encoder) =20 enum dsi_work_mode { DSI_MODE_CMD =3D 0, @@ -116,7 +116,9 @@ struct sprd_dsi { struct mipi_dsi_host host; struct mipi_dsi_device *slave; struct drm_encoder encoder; + struct drm_bridge bridge; struct drm_bridge *panel_bridge; + struct drm_connector *connector; struct dsi_context ctx; }; =20 --=20 2.50.0