[PATCH v10 11/18] drm/bridge: analogix_dp: Apply drm_bridge_connector helper
From: Damon Ding <hidden>
Date: 2026-03-10 01:31:09
Also in:
dri-devel, imx, linux-rockchip, linux-samsung-soc, lkml
Subsystem:
arm/rockchip soc support, drm drivers, drm drivers and misc gpu patches, drm drivers for bridge chips, drm drivers for exynos, drm drivers for rockchip, exynos dp driver, the rest · Maintainers:
Heiko Stuebner, David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Andrzej Hajda, Neil Armstrong, Robert Foss, Inki Dae, Seung-Woo Kim, Kyungmin Park, Sandy Huang, Heiko Stübner, Andy Yan, Jingoo Han, Linus Torvalds
Initialize bridge_connector for both Rockchip and Exynos encoder sides.
Then, make DRM_BRIDGE_ATTACH_NO_CONNECTOR mandatory for Analogix bridge
side, as the private &drm_connector is no longer created.
The previous &drm_connector_funcs and &drm_connector_helper_funcs APIs
are replaced by the corresponding &drm_bridge_funcs APIs:
analogix_dp_atomic_check() -> analogix_dp_bridge_atomic_check()
analogix_dp_detect() -> analogix_dp_bridge_detect()
analogix_dp_get_modes() -> analogix_dp_bridge_get_modes()
analogix_dp_bridge_edid_read()
Additionally, the compatibilities of Analogix DP bridge based on whether
the next bridge is a 'panel'. If it is, OP_MODES and OP_DETECT are
supported; If not (the next bridge is a 'monitor' or a bridge chip),
OP_EDID and OP_DETECT are supported.
The devm_drm_bridge_add() is placed in analogix_dp_bind() instead of
analogix_dp_probe(), because the type of next bridge (the panel, monitor
or bridge chip) can only be determined after the probe process has fully
completed.
Signed-off-by: Damon Ding <redacted>
Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>
Tested-by: Heiko Stuebner <heiko@sntech.de> (on rk3588)
------
Changes in v2:
- For &drm_bridge.ops, remove DRM_BRIDGE_OP_HPD and add
DRM_BRIDGE_OP_EDID.
- Add analogix_dp_bridge_edid_read().
- Move &analogix_dp_plat_data.skip_connector deletion to the previous
patches.
Changes in v3:
- Rebase with the new devm_drm_bridge_alloc() related commit
48f05c3b4b70 ("drm/bridge: analogix_dp: Use devm_drm_bridge_alloc()
API").
- Expand the commit message.
- Call drm_bridge_get_modes() in analogix_dp_bridge_get_modes() if the
bridge is available.
- Remove unnecessary parameter struct drm_connector* for callback
&analogix_dp_plat_data.attach.
- In order to decouple the connector driver and the bridge driver, move
the bridge connector initilization to the Rockchip and Exynos sides.
Changes in v4:
- Expand analogix_dp_bridge_detect() parameters to &drm_bridge and
&drm_connector.
- Rename the &analogix_dp_plat_data.bridge to
&analogix_dp_plat_data.next_bridge.
Changes in v5:
- Set the flag fo drm_bridge_attach() to DRM_BRIDGE_ATTACH_NO_CONNECTOR
for next bridge attachment of Exynos side.
- Distinguish the &drm_bridge->ops of Analogix bridge based on whether
the downstream device is a panel, a bridge or neither.
- Remove the calls to &analogix_dp_plat_data.get_modes().
Changes in v6:
- Select DRM_BRIDGE_CONNECTOR for both Rockchip and Exynos sides.
- Remove unnecessary drm_bridge_get_modes() in
analogix_dp_bridge_get_modes().
- Simplify analogix_dp_bridge_edid_read().
- If the next is a bridge, set DRM_BRIDGE_OP_DETECT and return
connector_status_connected in analogix_dp_bridge_detect().
- Set flag DRM_BRIDGE_ATTACH_NO_CONNECTOR for bridge attachment while
binding. Meanwhile, make DRM_BRIDGE_ATTACH_NO_CONNECTOR unsuppported
in analogix_dp_bridge_attach().
- Simplify the check of bridge capabilities.
Changes in v7:
- Remove temporary flag &exynos_dp_device.has_of_bridge.
Change in v9
- Add Tested-by tag.
Change in v10:
- Split this commit into serval smaller ones.
- Simplify the commit message.
---
.../drm/bridge/analogix/analogix_dp_core.c | 135 +++++++-----------
drivers/gpu/drm/exynos/exynos_dp.c | 26 ++--
.../gpu/drm/rockchip/analogix_dp-rockchip.c | 11 +-
3 files changed, 76 insertions(+), 96 deletions(-)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 7e42eb18313d..81c6e81dd352 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c@@ -856,44 +856,32 @@ static int analogix_dp_disable_psr(struct analogix_dp_device *dp) return analogix_dp_send_psr_spd(dp, &psr_vsc, true); } -static int analogix_dp_get_modes(struct drm_connector *connector) +static int analogix_dp_bridge_get_modes(struct drm_bridge *bridge, struct drm_connector *connector) { - struct analogix_dp_device *dp = to_dp(connector); - const struct drm_edid *drm_edid; + struct analogix_dp_device *dp = to_dp(bridge); int num_modes = 0; - if (dp->plat_data->panel) { + if (dp->plat_data->panel) num_modes += drm_panel_get_modes(dp->plat_data->panel, connector); - } else { - drm_edid = drm_edid_read_ddc(connector, &dp->aux.ddc); - - drm_edid_connector_update(&dp->connector, drm_edid); - - if (drm_edid) { - num_modes += drm_edid_connector_add_modes(&dp->connector); - drm_edid_free(drm_edid); - } - } return num_modes; } -static struct drm_encoder * -analogix_dp_best_encoder(struct drm_connector *connector) +static const struct drm_edid *analogix_dp_bridge_edid_read(struct drm_bridge *bridge, + struct drm_connector *connector) { - struct analogix_dp_device *dp = to_dp(connector); + struct analogix_dp_device *dp = to_dp(bridge); - return dp->encoder; + return drm_edid_read_ddc(connector, &dp->aux.ddc); } - -static int analogix_dp_atomic_check(struct drm_connector *connector, - struct drm_atomic_state *state) +static int analogix_dp_bridge_atomic_check(struct drm_bridge *bridge, + struct drm_bridge_state *bridge_state, + struct drm_crtc_state *crtc_state, + struct drm_connector_state *conn_state) { - struct analogix_dp_device *dp = to_dp(connector); - struct drm_display_info *di = &connector->display_info; - struct drm_connector_state *conn_state; - struct drm_crtc_state *crtc_state; + struct analogix_dp_device *dp = to_dp(bridge); + struct drm_display_info *di = &conn_state->connector->display_info; u32 mask = DRM_COLOR_FORMAT_YCBCR444 | DRM_COLOR_FORMAT_YCBCR422; if (is_rockchip(dp->plat_data->dev_type)) {
@@ -905,38 +893,21 @@ static int analogix_dp_atomic_check(struct drm_connector *connector, } } - conn_state = drm_atomic_get_new_connector_state(state, connector); - if (WARN_ON(!conn_state)) - return -ENODEV; - conn_state->self_refresh_aware = true; - if (!conn_state->crtc) - return 0; - - crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc); - if (!crtc_state) - return 0; - if (crtc_state->self_refresh_active && !dp->psr_supported) return -EINVAL; return 0; } -static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = { - .get_modes = analogix_dp_get_modes, - .best_encoder = analogix_dp_best_encoder, - .atomic_check = analogix_dp_atomic_check, -}; - static enum drm_connector_status -analogix_dp_detect(struct drm_connector *connector, bool force) +analogix_dp_bridge_detect(struct drm_bridge *bridge, struct drm_connector *connector) { - struct analogix_dp_device *dp = to_dp(connector); + struct analogix_dp_device *dp = to_dp(bridge); enum drm_connector_status status = connector_status_disconnected; - if (dp->plat_data->panel) + if (dp->plat_data->panel || dp->plat_data->next_bridge) return connector_status_connected; if (!analogix_dp_detect_hpd(dp))
@@ -945,51 +916,18 @@ analogix_dp_detect(struct drm_connector *connector, bool force) return status; } -static const struct drm_connector_funcs analogix_dp_connector_funcs = { - .fill_modes = drm_helper_probe_single_connector_modes, - .detect = analogix_dp_detect, - .destroy = drm_connector_cleanup, - .reset = drm_atomic_helper_connector_reset, - .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, - .atomic_destroy_state = drm_atomic_helper_connector_destroy_state, -}; - static int analogix_dp_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder, enum drm_bridge_attach_flags flags) { struct analogix_dp_device *dp = to_dp(bridge); - struct drm_connector *connector = NULL; int ret = 0; - if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) { - DRM_ERROR("Fix bridge driver to make connector optional!"); + if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) { + DRM_ERROR("Unsupported connector creation\n"); return -EINVAL; } - if (!dp->plat_data->next_bridge) { - connector = &dp->connector; - connector->polled = DRM_CONNECTOR_POLL_HPD; - - ret = drm_connector_init(dp->drm_dev, connector, - &analogix_dp_connector_funcs, - DRM_MODE_CONNECTOR_eDP); - if (ret) { - DRM_ERROR("Failed to initialize connector with drm\n"); - return ret; - } - - drm_connector_helper_add(connector, - &analogix_dp_connector_helper_funcs); - drm_connector_attach_encoder(connector, encoder); - } - - /* - * NOTE: the connector registration is implemented in analogix - * platform driver, that to say connector would be exist after - * plat_data->attch return, that's why we record the connector - * point after plat attached. - */ if (dp->plat_data->attach) { ret = dp->plat_data->attach(dp->plat_data, bridge); if (ret) {
@@ -1309,7 +1247,11 @@ static const struct drm_bridge_funcs analogix_dp_bridge_funcs = { .atomic_enable = analogix_dp_bridge_atomic_enable, .atomic_disable = analogix_dp_bridge_atomic_disable, .atomic_post_disable = analogix_dp_bridge_atomic_post_disable, + .atomic_check = analogix_dp_bridge_atomic_check, .attach = analogix_dp_bridge_attach, + .get_modes = analogix_dp_bridge_get_modes, + .edid_read = analogix_dp_bridge_edid_read, + .detect = analogix_dp_bridge_detect, }; static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
@@ -1539,6 +1481,7 @@ EXPORT_SYMBOL_GPL(analogix_dp_resume); int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) { + struct drm_bridge *bridge = &dp->bridge; int ret; dp->drm_dev = drm_dev;
@@ -1552,7 +1495,18 @@ int analogix_dp_bind(struct analogix_dp_device *dp, struct drm_device *drm_dev) return ret; } - ret = drm_bridge_attach(dp->encoder, &dp->bridge, NULL, 0); + if (dp->plat_data->panel) + bridge->ops = DRM_BRIDGE_OP_MODES | DRM_BRIDGE_OP_DETECT; + else + bridge->ops = DRM_BRIDGE_OP_EDID | DRM_BRIDGE_OP_DETECT; + + bridge->of_node = dp->dev->of_node; + bridge->type = DRM_MODE_CONNECTOR_eDP; + ret = devm_drm_bridge_add(dp->dev, &dp->bridge); + if (ret) + goto err_unregister_aux; + + ret = drm_bridge_attach(dp->encoder, bridge, NULL, DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) { DRM_ERROR("failed to create bridge (%d)\n", ret); goto err_unregister_aux;
@@ -1570,7 +1524,6 @@ EXPORT_SYMBOL_GPL(analogix_dp_bind); void analogix_dp_unbind(struct analogix_dp_device *dp) { analogix_dp_bridge_disable(&dp->bridge); - dp->connector.funcs->destroy(&dp->connector); drm_panel_unprepare(dp->plat_data->panel);
@@ -1580,7 +1533,8 @@ EXPORT_SYMBOL_GPL(analogix_dp_unbind); int analogix_dp_start_crc(struct drm_connector *connector) { - struct analogix_dp_device *dp = to_dp(connector); + struct analogix_dp_device *dp; + struct drm_bridge *bridge; if (!connector->state->crtc) { DRM_ERROR("Connector %s doesn't currently have a CRTC.\n",
@@ -1588,13 +1542,26 @@ int analogix_dp_start_crc(struct drm_connector *connector) return -EINVAL; } + bridge = drm_bridge_chain_get_first_bridge(connector->encoder); + if (bridge->type != DRM_MODE_CONNECTOR_eDP) + return -EINVAL; + + dp = to_dp(bridge); + return drm_dp_start_crc(&dp->aux, connector->state->crtc); } EXPORT_SYMBOL_GPL(analogix_dp_start_crc); int analogix_dp_stop_crc(struct drm_connector *connector) { - struct analogix_dp_device *dp = to_dp(connector); + struct analogix_dp_device *dp; + struct drm_bridge *bridge; + + bridge = drm_bridge_chain_get_first_bridge(connector->encoder); + if (bridge->type != DRM_MODE_CONNECTOR_eDP) + return -EINVAL; + + dp = to_dp(bridge); return drm_dp_stop_crc(&dp->aux); }
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 71a00ee97782..478eaa6f3175 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c@@ -22,6 +22,7 @@ #include <drm/bridge/of-display-mode-bridge.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_bridge.h> +#include <drm/drm_bridge_connector.h> #include <drm/drm_crtc.h> #include <drm/drm_of.h> #include <drm/drm_panel.h>
@@ -41,8 +42,6 @@ struct exynos_dp_device { struct analogix_dp_device *adp; struct analogix_dp_plat_data plat_data; - - bool has_of_bridge; }; static int exynos_dp_crtc_clock_enable(struct analogix_dp_plat_data *plat_data,
@@ -73,15 +72,12 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data, struct drm_bridge *bridge) { struct exynos_dp_device *dp = to_dp(plat_data); - enum drm_bridge_attach_flags flags = 0; int ret; /* Pre-empt DP connector creation if there's a bridge */ if (plat_data->next_bridge) { - if (dp->has_of_bridge) - flags = DRM_BRIDGE_ATTACH_NO_CONNECTOR; - - ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge, flags); + ret = drm_bridge_attach(&dp->encoder, plat_data->next_bridge, bridge, + DRM_BRIDGE_ATTACH_NO_CONNECTOR); if (ret) return ret; }
@@ -111,6 +107,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) struct exynos_dp_device *dp = dev_get_drvdata(dev); struct drm_encoder *encoder = &dp->encoder; struct drm_device *drm_dev = data; + struct drm_connector *connector; int ret; dp->drm_dev = drm_dev;
@@ -126,10 +123,19 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data) dp->plat_data.encoder = encoder; ret = analogix_dp_bind(dp->adp, dp->drm_dev); - if (ret) + if (ret) { dp->encoder.funcs->destroy(&dp->encoder); + return ret; + } + + connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + dev_err(dp->dev, "Failed to initialize bridge_connector\n"); + return ret; + } - return ret; + return drm_connector_attach_encoder(connector, dp->plat_data.encoder); } static void exynos_dp_unbind(struct device *dev, struct device *master,
@@ -186,8 +192,6 @@ static int exynos_dp_probe(struct platform_device *pdev) dp->dev->of_node, DRM_MODE_CONNECTOR_eDP); ret = IS_ERR(dp->plat_data.next_bridge) ? PTR_ERR(dp->plat_data.next_bridge) : 0; - if (!ret) - dp->has_of_bridge = true; } if (ret) return ret;
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 70fe5ae69e2e..7fa17ba26c46 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c@@ -25,6 +25,7 @@ #include <drm/display/drm_dp_helper.h> #include <drm/drm_atomic.h> #include <drm/drm_atomic_helper.h> +#include <drm/drm_bridge_connector.h> #include <drm/bridge/analogix_dp.h> #include <drm/drm_of.h> #include <drm/drm_panel.h>
@@ -369,6 +370,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, { struct rockchip_dp_device *dp = dev_get_drvdata(dev); struct drm_device *drm_dev = data; + struct drm_connector *connector; int ret; dp->drm_dev = drm_dev;
@@ -388,7 +390,14 @@ static int rockchip_dp_bind(struct device *dev, struct device *master, if (ret) goto err_cleanup_encoder; - return 0; + connector = drm_bridge_connector_init(dp->drm_dev, dp->plat_data.encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + dev_err(dp->dev, "Failed to initialize bridge_connector\n"); + goto err_cleanup_encoder; + } + + return drm_connector_attach_encoder(connector, dp->plat_data.encoder); err_cleanup_encoder: dp->encoder.encoder.funcs->destroy(&dp->encoder.encoder); return ret;
--
2.34.1