* [PATCH v5 00/16] drm/bridge: Various quality of life improvements
@ 2025-03-04 11:10 Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach Maxime Ripard
` (15 more replies)
0 siblings, 16 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov, Simona Vetter
Hi,
Here's a series of changes after to the KMS helpers and bridge API
following a bunch of reviews I did.
It's mostly centered across providing an easier time to deal with bridge
states, and a somewhat consistent with the other entities API.
It's build tested only, with arm64 allmodconfig.
Maxime
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
Changes in v5:
- Rebased on top of current drm-misc-next
- Split the new crtc / connector enabling helper into two patches
- Fix a depmod breakage with drm_bridge_reset_crtc()
- Renamed drm_bridge_reset_crtc() to drm_bridge_helper_reset_crtc()
- Add new test case for drm_bridge_helper_reset_crtc() when the bridge
is disabled.
- Fix a few commit logs
- Link to v4: https://lore.kernel.org/r/20250225-bridge-connector-v4-0-7ecb07b09cad@kernel.org
Changes in v4:
- Rebased on top of drm-misc-next-2025-02-20
- Changed the approach to helpers suggested by Sima, dropped the tags
affected by the rework
- Drop drm_bridge_state->crtc and connector fields
- Drop drm_bridge->encoder deprecation
- Introduced kunit tests
- Link to v3: https://lore.kernel.org/r/20250213-bridge-connector-v3-0-e71598f49c8f@kernel.org
Changes in v3:
- Add tags
- Fix compilation breakages
- Reword some commit messages
- Create drm_bridge_is_atomic() helper
- Retrieve the CRTC state through drm_atomic_get_new_crtc_state()
instead of crtc->state in bridges
- Fix ti-sn65dsi86
- Link to v2: https://lore.kernel.org/r/20250204-bridge-connector-v2-0-35dd6c834e08@kernel.org
Changes in v2:
- Pass the full atomic state to bridge atomic hooks
- Make attach take the encoder as a parameter
- Mark bridge->encoder as deprecated
- Rework the logic to detect if a bridge uses a state or not at
atomic_check time
- Add lockdep assertion to drm_bridge_get_current_state()
- Link to v1: https://lore.kernel.org/r/20250115-bridge-connector-v1-0-9a2fecd886a6@kernel.org
---
Maxime Ripard (16):
drm/bridge: Add encoder parameter to drm_bridge_funcs.attach
drm/bridge: Provide a helper to retrieve current bridge state
drm/tests: Add kunit tests for bridges
drm/atomic: Introduce helper to lookup connector by encoder
drm/tests: helpers: Create new helper to enable output
drm/tests: hdmi_state_helpers: Switch to new helper
drm/tests: Create tests for drm_atomic
drm/bridge: Add helper to reset bridge pipeline
drm/tests: bridge: Provide tests for drm_bridge_helper_reset_crtc
drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc
drm/bridge: Introduce drm_bridge_is_atomic() helper
drm/bridge: cdns-csi: Switch to atomic helpers
drm/bridge: tc358775: Switch to atomic commit
drm/bridge: tc358768: Stop disabling when failing to enable
drm/bridge: tc358768: Convert to atomic helpers
drm/bridge: ti-sn65dsi86: Remove drm_encoder->crtc use
drivers/gpu/drm/Kconfig | 1 +
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/adp/adp-mipi.c | 3 +-
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 3 +-
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 3 +-
drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 3 +-
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +-
drivers/gpu/drm/bridge/analogix/anx7625.c | 3 +-
drivers/gpu/drm/bridge/aux-bridge.c | 3 +-
drivers/gpu/drm/bridge/aux-hpd-bridge.c | 1 +
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 34 +-
.../gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 1 +
drivers/gpu/drm/bridge/chipone-icn6211.c | 6 +-
drivers/gpu/drm/bridge/chrontel-ch7033.c | 5 +-
drivers/gpu/drm/bridge/display-connector.c | 1 +
drivers/gpu/drm/bridge/fsl-ldb.c | 3 +-
drivers/gpu/drm/bridge/imx/imx-ldb-helper.c | 7 +-
drivers/gpu/drm/bridge/imx/imx-ldb-helper.h | 2 +-
drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c | 3 +-
drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c | 3 +-
.../gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c | 3 +-
drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 3 +-
drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 3 +-
drivers/gpu/drm/bridge/ite-it6263.c | 7 +-
drivers/gpu/drm/bridge/ite-it6505.c | 1 +
drivers/gpu/drm/bridge/ite-it66121.c | 3 +-
drivers/gpu/drm/bridge/lontium-lt8912b.c | 3 +-
drivers/gpu/drm/bridge/lontium-lt9211.c | 3 +-
drivers/gpu/drm/bridge/lontium-lt9611.c | 3 +-
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 3 +-
drivers/gpu/drm/bridge/lvds-codec.c | 3 +-
.../drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 1 +
drivers/gpu/drm/bridge/microchip-lvds.c | 3 +-
drivers/gpu/drm/bridge/nwl-dsi.c | 3 +-
drivers/gpu/drm/bridge/nxp-ptn3460.c | 5 +-
drivers/gpu/drm/bridge/panel.c | 3 +-
drivers/gpu/drm/bridge/parade-ps8622.c | 1 +
drivers/gpu/drm/bridge/parade-ps8640.c | 3 +-
drivers/gpu/drm/bridge/samsung-dsim.c | 3 +-
drivers/gpu/drm/bridge/sii902x.c | 5 +-
drivers/gpu/drm/bridge/sil-sii8620.c | 1 +
drivers/gpu/drm/bridge/simple-bridge.c | 5 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +-
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 5 +-
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c | 5 +-
drivers/gpu/drm/bridge/tc358762.c | 3 +-
drivers/gpu/drm/bridge/tc358764.c | 3 +-
drivers/gpu/drm/bridge/tc358767.c | 2 +
drivers/gpu/drm/bridge/tc358768.c | 41 +-
drivers/gpu/drm/bridge/tc358775.c | 45 ++-
drivers/gpu/drm/bridge/tda998x_drv.c | 1 +
drivers/gpu/drm/bridge/thc63lvd1024.c | 3 +-
drivers/gpu/drm/bridge/ti-dlpc3433.c | 4 +-
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 31 +-
drivers/gpu/drm/bridge/ti-sn65dsi86.c | 58 ++-
drivers/gpu/drm/bridge/ti-tdp158.c | 6 +-
drivers/gpu/drm/bridge/ti-tfp410.c | 5 +-
drivers/gpu/drm/bridge/ti-tpd12s015.c | 3 +-
drivers/gpu/drm/drm_atomic.c | 45 +++
drivers/gpu/drm/drm_bridge.c | 11 +-
drivers/gpu/drm/drm_bridge_helper.c | 55 +++
drivers/gpu/drm/imx/ipuv3/parallel-display.c | 3 +-
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 5 +-
drivers/gpu/drm/mcde/mcde_dsi.c | 3 +-
drivers/gpu/drm/mediatek/mtk_dp.c | 3 +-
drivers/gpu/drm/mediatek/mtk_dpi.c | 3 +-
drivers/gpu/drm/mediatek/mtk_dsi.c | 3 +-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 3 +-
drivers/gpu/drm/meson/meson_encoder_cvbs.c | 3 +-
drivers/gpu/drm/meson/meson_encoder_dsi.c | 3 +-
drivers/gpu/drm/meson/meson_encoder_hdmi.c | 3 +-
drivers/gpu/drm/msm/dsi/dsi_manager.c | 3 +-
drivers/gpu/drm/omapdrm/dss/dpi.c | 3 +-
drivers/gpu/drm/omapdrm/dss/dsi.c | 3 +-
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 +-
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 +-
drivers/gpu/drm/omapdrm/dss/sdi.c | 3 +-
drivers/gpu/drm/omapdrm/dss/venc.c | 3 +-
drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c | 3 +-
drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c | 3 +-
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 3 +-
drivers/gpu/drm/stm/lvds.c | 11 +-
drivers/gpu/drm/tests/Makefile | 2 +
drivers/gpu/drm/tests/drm_atomic_test.c | 153 ++++++++
drivers/gpu/drm/tests/drm_bridge_test.c | 417 +++++++++++++++++++++
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 158 ++++----
drivers/gpu/drm/tests/drm_kunit_helpers.c | 61 +++
drivers/gpu/drm/tidss/tidss_encoder.c | 3 +-
drivers/gpu/drm/vc4/vc4_dsi.c | 3 +-
drivers/gpu/drm/xlnx/zynqmp_dp.c | 3 +-
drivers/platform/arm64/acer-aspire1-ec.c | 3 +-
include/drm/drm_atomic.h | 3 +
include/drm/drm_bridge.h | 34 +-
include/drm/drm_bridge_helper.h | 12 +
include/drm/drm_kunit_helpers.h | 8 +
95 files changed, 1172 insertions(+), 246 deletions(-)
---
base-commit: 95a5c9d197bb22a506913acb330a926d4e51aa95
change-id: 20250115-bridge-connector-f93194e267ff
Best regards,
--
Maxime Ripard <mripard@kernel.org>
^ permalink raw reply [flat|nested] 52+ messages in thread
* [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-05 13:04 ` Luca Ceresoli
2025-03-04 11:10 ` [PATCH v5 02/16] drm/bridge: Provide a helper to retrieve current bridge state Maxime Ripard
` (14 subsequent siblings)
15 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The drm_bridge structure contains an encoder pointer that is widely used
by bridge drivers. This pattern is largely documented as deprecated in
other KMS entities for atomic drivers.
However, one of the main use of that pointer is done in attach to just
call drm_bridge_attach on the next bridge to add it to the bridge list.
While this dereferences the bridge->encoder pointer, it's effectively
the same encoder the bridge was being attached to.
We can make it more explicit by adding the encoder the bridge is
attached to to the list of attach parameters. This also removes the need
to dereference bridge->encoder in most drivers.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/adp/adp-mipi.c | 3 ++-
drivers/gpu/drm/bridge/adv7511/adv7511_drv.c | 3 ++-
drivers/gpu/drm/bridge/analogix/analogix-anx6345.c | 3 ++-
drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c | 3 ++-
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 2 +-
drivers/gpu/drm/bridge/analogix/anx7625.c | 3 ++-
drivers/gpu/drm/bridge/aux-bridge.c | 3 ++-
drivers/gpu/drm/bridge/aux-hpd-bridge.c | 1 +
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 3 ++-
drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c | 1 +
drivers/gpu/drm/bridge/chipone-icn6211.c | 6 ++++--
drivers/gpu/drm/bridge/chrontel-ch7033.c | 5 +++--
drivers/gpu/drm/bridge/display-connector.c | 1 +
drivers/gpu/drm/bridge/fsl-ldb.c | 3 ++-
drivers/gpu/drm/bridge/imx/imx-ldb-helper.c | 7 +++----
drivers/gpu/drm/bridge/imx/imx-ldb-helper.h | 2 +-
drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c | 3 ++-
drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c | 3 ++-
drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c | 3 ++-
drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c | 3 ++-
drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c | 3 ++-
drivers/gpu/drm/bridge/ite-it6263.c | 7 ++++---
drivers/gpu/drm/bridge/ite-it6505.c | 1 +
drivers/gpu/drm/bridge/ite-it66121.c | 3 ++-
drivers/gpu/drm/bridge/lontium-lt8912b.c | 3 ++-
drivers/gpu/drm/bridge/lontium-lt9211.c | 3 ++-
drivers/gpu/drm/bridge/lontium-lt9611.c | 3 ++-
drivers/gpu/drm/bridge/lontium-lt9611uxc.c | 3 ++-
drivers/gpu/drm/bridge/lvds-codec.c | 3 ++-
drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c | 1 +
drivers/gpu/drm/bridge/microchip-lvds.c | 3 ++-
drivers/gpu/drm/bridge/nwl-dsi.c | 3 ++-
drivers/gpu/drm/bridge/nxp-ptn3460.c | 5 +++--
drivers/gpu/drm/bridge/panel.c | 3 ++-
drivers/gpu/drm/bridge/parade-ps8622.c | 1 +
drivers/gpu/drm/bridge/parade-ps8640.c | 3 ++-
drivers/gpu/drm/bridge/samsung-dsim.c | 3 ++-
drivers/gpu/drm/bridge/sii902x.c | 5 +++--
drivers/gpu/drm/bridge/sil-sii8620.c | 1 +
drivers/gpu/drm/bridge/simple-bridge.c | 5 +++--
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 ++-
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 5 +++--
drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c | 5 +++--
drivers/gpu/drm/bridge/tc358762.c | 3 ++-
drivers/gpu/drm/bridge/tc358764.c | 3 ++-
drivers/gpu/drm/bridge/tc358767.c | 2 ++
drivers/gpu/drm/bridge/tc358768.c | 3 ++-
drivers/gpu/drm/bridge/tc358775.c | 3 ++-
drivers/gpu/drm/bridge/tda998x_drv.c | 1 +
drivers/gpu/drm/bridge/thc63lvd1024.c | 3 ++-
drivers/gpu/drm/bridge/ti-dlpc3433.c | 4 ++--
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 3 ++-
drivers/gpu/drm/bridge/ti-sn65dsi86.c | 3 ++-
drivers/gpu/drm/bridge/ti-tdp158.c | 6 ++++--
drivers/gpu/drm/bridge/ti-tfp410.c | 5 +++--
drivers/gpu/drm/bridge/ti-tpd12s015.c | 3 ++-
drivers/gpu/drm/drm_bridge.c | 2 +-
drivers/gpu/drm/imx/ipuv3/parallel-display.c | 3 ++-
drivers/gpu/drm/ingenic/ingenic-drm-drv.c | 5 +++--
drivers/gpu/drm/mcde/mcde_dsi.c | 3 ++-
drivers/gpu/drm/mediatek/mtk_dp.c | 3 ++-
drivers/gpu/drm/mediatek/mtk_dpi.c | 3 ++-
drivers/gpu/drm/mediatek/mtk_dsi.c | 3 ++-
drivers/gpu/drm/mediatek/mtk_hdmi.c | 3 ++-
drivers/gpu/drm/meson/meson_encoder_cvbs.c | 3 ++-
drivers/gpu/drm/meson/meson_encoder_dsi.c | 3 ++-
drivers/gpu/drm/meson/meson_encoder_hdmi.c | 3 ++-
drivers/gpu/drm/msm/dsi/dsi_manager.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/dpi.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/dsi.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/hdmi4.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/hdmi5.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/sdi.c | 3 ++-
drivers/gpu/drm/omapdrm/dss/venc.c | 3 ++-
drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c | 3 ++-
drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c | 3 ++-
drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c | 3 ++-
drivers/gpu/drm/stm/lvds.c | 11 +++++------
drivers/gpu/drm/tidss/tidss_encoder.c | 3 ++-
drivers/gpu/drm/vc4/vc4_dsi.c | 3 ++-
drivers/gpu/drm/xlnx/zynqmp_dp.c | 3 ++-
drivers/platform/arm64/acer-aspire1-ec.c | 3 ++-
include/drm/drm_bridge.h | 2 +-
83 files changed, 172 insertions(+), 95 deletions(-)
diff --git a/drivers/gpu/drm/adp/adp-mipi.c b/drivers/gpu/drm/adp/adp-mipi.c
index ad80542b60ed6de3fe76a4d134b87d20df98ee33..2b60128e2c693e9f85affff569cc57cdb6f47909 100644
--- a/drivers/gpu/drm/adp/adp-mipi.c
+++ b/drivers/gpu/drm/adp/adp-mipi.c
@@ -210,16 +210,17 @@ static const struct mipi_dsi_host_ops adp_dsi_host_ops = {
.attach = adp_dsi_host_attach,
.detach = adp_dsi_host_detach,
};
static int adp_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct adp_mipi_drv_private *adp =
container_of(bridge, struct adp_mipi_drv_private, bridge);
- return drm_bridge_attach(bridge->encoder, adp->next_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, adp->next_bridge, bridge, flags);
}
static const struct drm_bridge_funcs adp_dsi_bridge_funcs = {
.attach = adp_dsi_bridge_attach,
};
diff --git a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
index 050dae338ffee36a8d6ee6fcce69f51486a957fe..1257009e850c1b20184cfaea5b6a4440e75e10d7 100644
--- a/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
+++ b/drivers/gpu/drm/bridge/adv7511/adv7511_drv.c
@@ -946,17 +946,18 @@ static enum drm_mode_status adv7511_bridge_mode_valid(struct drm_bridge *bridge,
else
return adv7511_mode_valid(adv, mode);
}
static int adv7511_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct adv7511 *adv = bridge_to_adv7511(bridge);
int ret = 0;
if (adv->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, adv->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, adv->next_bridge, bridge,
flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
index 83d711ee3a2eb8b7a491c115171b5cc12a9df066..a88a33eb5d972cb47e82cfccde87ecf43d051637 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx6345.c
@@ -515,10 +515,11 @@ static const struct drm_connector_funcs anx6345_connector_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int anx6345_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx6345 *anx6345 = bridge_to_anx6345(bridge);
int err;
@@ -551,11 +552,11 @@ static int anx6345_bridge_attach(struct drm_bridge *bridge,
&anx6345_connector_helper_funcs);
anx6345->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx6345->connector,
- bridge->encoder);
+ encoder);
if (err) {
DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
goto connector_cleanup;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
index f74694bb9c50a2f71d51d27e08c08bb854cf29ea..8b4597885614d6278f5782fdce5065044d5c2966 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix-anx78xx.c
@@ -886,10 +886,11 @@ static const struct drm_connector_funcs anx78xx_connector_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int anx78xx_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx78xx *anx78xx = bridge_to_anx78xx(bridge);
int err;
@@ -922,11 +923,11 @@ static int anx78xx_bridge_attach(struct drm_bridge *bridge,
&anx78xx_connector_helper_funcs);
anx78xx->connector.polled = DRM_CONNECTOR_POLL_HPD;
err = drm_connector_attach_encoder(&anx78xx->connector,
- bridge->encoder);
+ encoder);
if (err) {
DRM_ERROR("Failed to link up connector to encoder: %d\n", err);
goto connector_cleanup;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 071168aa0c3bda880d3a53093159fb7b9681931c..042154e2d8ccd74ac2dc27fe527e810a50e08a09 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1111,14 +1111,14 @@ static const struct drm_connector_funcs analogix_dp_connector_funcs = {
.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 = bridge->driver_private;
- struct drm_encoder *encoder = dp->encoder;
struct drm_connector *connector = NULL;
int ret = 0;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
DRM_ERROR("Fix bridge driver to make connector optional!");
diff --git a/drivers/gpu/drm/bridge/analogix/anx7625.c b/drivers/gpu/drm/bridge/analogix/anx7625.c
index 0b97b66de577421b0e68e748d0075f674c71fbf1..0b61e77c0398bbce3ecf55753dde71a27eda8fe5 100644
--- a/drivers/gpu/drm/bridge/analogix/anx7625.c
+++ b/drivers/gpu/drm/bridge/analogix/anx7625.c
@@ -2139,10 +2139,11 @@ static void hdcp_check_work_func(struct work_struct *work)
mutex_unlock(&ctx->hdcp_wq_lock);
drm_modeset_unlock(&drm_dev->mode_config.connection_mutex);
}
static int anx7625_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct anx7625_data *ctx = bridge_to_anx7625(bridge);
int err;
struct device *dev = ctx->dev;
@@ -2157,11 +2158,11 @@ static int anx7625_bridge_attach(struct drm_bridge *bridge,
dev_err(dev, "failed to register aux channel: %d\n", err);
return err;
}
if (ctx->pdata.panel_bridge) {
- err = drm_bridge_attach(bridge->encoder,
+ err = drm_bridge_attach(encoder,
ctx->pdata.panel_bridge,
&ctx->bridge, flags);
if (err)
return err;
}
diff --git a/drivers/gpu/drm/bridge/aux-bridge.c b/drivers/gpu/drm/bridge/aux-bridge.c
index 015983c015e508f75435bf97ee1dba785edcd23e..c179b86d208f70d95b41e6f2157b78f97bac4d8d 100644
--- a/drivers/gpu/drm/bridge/aux-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-bridge.c
@@ -84,20 +84,21 @@ struct drm_aux_bridge_data {
struct drm_bridge *next_bridge;
struct device *dev;
};
static int drm_aux_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct drm_aux_bridge_data *data;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
data = container_of(bridge, struct drm_aux_bridge_data, bridge);
- return drm_bridge_attach(bridge->encoder, data->next_bridge, bridge,
+ return drm_bridge_attach(encoder, data->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
static const struct drm_bridge_funcs drm_aux_bridge_funcs = {
.attach = drm_aux_bridge_attach,
diff --git a/drivers/gpu/drm/bridge/aux-hpd-bridge.c b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
index 48f297c78ee67c8f9034869f6824a6dc7f88bdd7..b3f588b71a7d7ad5c2ee7b07c39079bc5ba34cee 100644
--- a/drivers/gpu/drm/bridge/aux-hpd-bridge.c
+++ b/drivers/gpu/drm/bridge/aux-hpd-bridge.c
@@ -154,10 +154,11 @@ void drm_aux_hpd_bridge_notify(struct device *dev, enum drm_connector_status sta
drm_bridge_hpd_notify(&data->bridge, status);
}
EXPORT_SYMBOL_GPL(drm_aux_hpd_bridge_notify);
static int drm_aux_hpd_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
}
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index c7a0247e06adf3e532f830363b3422a8058513ef..8f54c034ac4f3e82c38607a0e52d4745654b571f 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -603,10 +603,11 @@ static int cdns_dsi_check_conf(struct cdns_dsi *dsi,
return 0;
}
static int cdns_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
struct cdns_dsi_output *output = &dsi->output;
@@ -615,11 +616,11 @@ static int cdns_dsi_bridge_attach(struct drm_bridge *bridge,
dev_err(dsi->base.dev,
"cdns-dsi driver is only compatible with DRM devices supporting atomic updates");
return -ENOTSUPP;
}
- return drm_bridge_attach(bridge->encoder, output->bridge, bridge,
+ return drm_bridge_attach(encoder, output->bridge, bridge,
flags);
}
static enum drm_mode_status
cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
index 81fad14c2cd598045d989c7d51f292bafb92c144..ae1bd58975ce3ab42b6633d537e5280d14d2614b 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-mhdp8546-core.c
@@ -1724,10 +1724,11 @@ static int cdns_mhdp_connector_init(struct cdns_mhdp_device *mhdp)
return ret;
}
static int cdns_mhdp_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct cdns_mhdp_device *mhdp = bridge_to_mhdp(bridge);
bool hw_ready;
int ret;
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index 81f7c701961fddadbced6e4ad1bf9f12d3325fa7..634c5b0306679d2e68798c2b9013aae4491dd44c 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -578,15 +578,17 @@ static int chipone_dsi_host_attach(struct chipone *icn)
mipi_dsi_device_unregister(dsi);
return ret;
}
-static int chipone_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
+static int chipone_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
{
struct chipone *icn = bridge_to_chipone(bridge);
- return drm_bridge_attach(bridge->encoder, icn->panel_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, icn->panel_bridge, bridge, flags);
}
#define MAX_INPUT_SEL_FORMATS 1
static u32 *
diff --git a/drivers/gpu/drm/bridge/chrontel-ch7033.c b/drivers/gpu/drm/bridge/chrontel-ch7033.c
index da17f0978a791fe9bffab3fa0527e3a355d65c6b..210c45c1efd48f5b541bf73da66a169c27e110b2 100644
--- a/drivers/gpu/drm/bridge/chrontel-ch7033.c
+++ b/drivers/gpu/drm/bridge/chrontel-ch7033.c
@@ -266,17 +266,18 @@ static void ch7033_hpd_event(void *arg, enum drm_connector_status status)
if (priv->bridge.dev)
drm_helper_hpd_irq_event(priv->connector.dev);
}
static int ch7033_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
struct drm_connector *connector = &priv->connector;
int ret;
- ret = drm_bridge_attach(bridge->encoder, priv->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, priv->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
@@ -303,11 +304,11 @@ static int ch7033_bridge_attach(struct drm_bridge *bridge,
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
}
- return drm_connector_attach_encoder(&priv->connector, bridge->encoder);
+ return drm_connector_attach_encoder(&priv->connector, encoder);
}
static void ch7033_bridge_detach(struct drm_bridge *bridge)
{
struct ch7033_priv *priv = bridge_to_ch7033_priv(bridge);
diff --git a/drivers/gpu/drm/bridge/display-connector.c b/drivers/gpu/drm/bridge/display-connector.c
index 72bc508d4e6e2bf5be535c8856b46465d1ff835e..09c08a53d5bdc5c48f5d520472f5a311289d4862 100644
--- a/drivers/gpu/drm/bridge/display-connector.c
+++ b/drivers/gpu/drm/bridge/display-connector.c
@@ -32,10 +32,11 @@ to_display_connector(struct drm_bridge *bridge)
{
return container_of(bridge, struct display_connector, bridge);
}
static int display_connector_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
}
diff --git a/drivers/gpu/drm/bridge/fsl-ldb.c b/drivers/gpu/drm/bridge/fsl-ldb.c
index 26ae1ab5237f81ebd6c56075a18136f4a5b56ec9..72d8f32d48faf6726ea67d8770ed83f77f3a0862 100644
--- a/drivers/gpu/drm/bridge/fsl-ldb.c
+++ b/drivers/gpu/drm/bridge/fsl-ldb.c
@@ -111,15 +111,16 @@ static unsigned long fsl_ldb_link_frequency(struct fsl_ldb *fsl_ldb, int clock)
else
return clock * 7000;
}
static int fsl_ldb_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct fsl_ldb *fsl_ldb = to_fsl_ldb(bridge);
- return drm_bridge_attach(bridge->encoder, fsl_ldb->panel_bridge,
+ return drm_bridge_attach(encoder, fsl_ldb->panel_bridge,
bridge, flags);
}
static void fsl_ldb_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c
index 9b5bebbe357dd4905a792abc5cecdbb9ce10ffb8..61347f6ec33d906264f7e06902b0d915d263f3f8 100644
--- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c
+++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.c
@@ -102,11 +102,11 @@ void ldb_bridge_disable_helper(struct drm_bridge *bridge)
regmap_write(ldb->regmap, ldb->ctrl_reg, ldb->ldb_ctrl);
}
EXPORT_SYMBOL_GPL(ldb_bridge_disable_helper);
-int ldb_bridge_attach_helper(struct drm_bridge *bridge,
+int ldb_bridge_attach_helper(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ldb_channel *ldb_ch = bridge->driver_private;
struct ldb *ldb = ldb_ch->ldb;
@@ -114,13 +114,12 @@ int ldb_bridge_attach_helper(struct drm_bridge *bridge,
DRM_DEV_ERROR(ldb->dev,
"do not support creating a drm_connector\n");
return -EINVAL;
}
- return drm_bridge_attach(bridge->encoder,
- ldb_ch->next_bridge, bridge,
- DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+ return drm_bridge_attach(encoder, ldb_ch->next_bridge, bridge,
+ DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
EXPORT_SYMBOL_GPL(ldb_bridge_attach_helper);
int ldb_init_helper(struct ldb *ldb)
{
diff --git a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h
index a0a5cde27fbc6eb0d3932381f78d6803542b9bac..38a8a54b37a60e1be942aaa60b1d1bc375a7a131 100644
--- a/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h
+++ b/drivers/gpu/drm/bridge/imx/imx-ldb-helper.h
@@ -79,11 +79,11 @@ void ldb_bridge_mode_set_helper(struct drm_bridge *bridge,
void ldb_bridge_enable_helper(struct drm_bridge *bridge);
void ldb_bridge_disable_helper(struct drm_bridge *bridge);
-int ldb_bridge_attach_helper(struct drm_bridge *bridge,
+int ldb_bridge_attach_helper(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags);
int ldb_init_helper(struct ldb *ldb);
int ldb_find_next_bridge_helper(struct ldb *ldb);
diff --git a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
index 3ebf0b9866de13b12fab2b3c1e4db5f3d446089a..7d9cb25595b17c3f008ebf0bf4b6190020a793d7 100644
--- a/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
+++ b/drivers/gpu/drm/bridge/imx/imx-legacy-bridge.c
@@ -21,11 +21,12 @@ struct imx_legacy_bridge {
};
#define to_imx_legacy_bridge(bridge) container_of(bridge, struct imx_legacy_bridge, base)
static int imx_legacy_bridge_attach(struct drm_bridge *bridge,
- enum drm_bridge_attach_flags flags)
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
{
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
return 0;
diff --git a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c
index a17433a7c75530668662ed8dd1526b44f9a32f32..8a4fd7d77a8d516b3b46f41cf07d2633d23bde12 100644
--- a/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8mp-hdmi-pvi.c
@@ -38,15 +38,16 @@ to_imx8mp_hdmi_pvi(struct drm_bridge *bridge)
{
return container_of(bridge, struct imx8mp_hdmi_pvi, bridge);
}
static int imx8mp_hdmi_pvi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct imx8mp_hdmi_pvi *pvi = to_imx8mp_hdmi_pvi(bridge);
- return drm_bridge_attach(bridge->encoder, pvi->next_bridge,
+ return drm_bridge_attach(encoder, pvi->next_bridge,
bridge, flags);
}
static void imx8mp_hdmi_pvi_bridge_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
index 1d9529dc7f2a93e7547ae1f4c6193598a5574135..1f6fd488e7039e943351006d3373009f0c15cb08 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-combiner.c
@@ -106,10 +106,11 @@ imx8qxp_pc_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_OK;
}
static int imx8qxp_pc_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct imx8qxp_pc_channel *ch = bridge->driver_private;
struct imx8qxp_pc *pc = ch->pc;
@@ -117,11 +118,11 @@ static int imx8qxp_pc_bridge_attach(struct drm_bridge *bridge,
DRM_DEV_ERROR(pc->dev,
"do not support creating a drm_connector\n");
return -EINVAL;
}
- return drm_bridge_attach(bridge->encoder,
+ return drm_bridge_attach(encoder,
ch->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
static void
diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
index cd6818db0fd332cac03241917bbb107b7261097c..e092c9ea99b0224802919ff84b448acb53508951 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pixel-link.c
@@ -126,21 +126,22 @@ static void imx8qxp_pixel_link_set_mst_addr(struct imx8qxp_pixel_link *pl)
"failed to set DC%u stream%u pixel link mst addr(%u): %d\n",
pl->dc_id, pl->stream_id, pl->mst_addr, ret);
}
static int imx8qxp_pixel_link_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct imx8qxp_pixel_link *pl = bridge->driver_private;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
DRM_DEV_ERROR(pl->dev,
"do not support creating a drm_connector\n");
return -EINVAL;
}
- return drm_bridge_attach(bridge->encoder,
+ return drm_bridge_attach(encoder,
pl->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
static void
diff --git a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
index 49dd4f96d52c966d9a038b0b04007631d0837f4d..da138ab51b3bd2c6ebd3780c09818891d5320092 100644
--- a/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
+++ b/drivers/gpu/drm/bridge/imx/imx8qxp-pxl2dpi.c
@@ -46,21 +46,22 @@ struct imx8qxp_pxl2dpi {
};
#define bridge_to_p2d(b) container_of(b, struct imx8qxp_pxl2dpi, bridge)
static int imx8qxp_pxl2dpi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct imx8qxp_pxl2dpi *p2d = bridge->driver_private;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)) {
DRM_DEV_ERROR(p2d->dev,
"do not support creating a drm_connector\n");
return -EINVAL;
}
- return drm_bridge_attach(bridge->encoder,
+ return drm_bridge_attach(encoder,
p2d->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
}
static int
diff --git a/drivers/gpu/drm/bridge/ite-it6263.c b/drivers/gpu/drm/bridge/ite-it6263.c
index 21152a1c28f7f5e326794488f473b030219a2f65..a3a63a977b0a8487ad38fc08e0eed08672f4d41a 100644
--- a/drivers/gpu/drm/bridge/ite-it6263.c
+++ b/drivers/gpu/drm/bridge/ite-it6263.c
@@ -663,33 +663,34 @@ it6263_bridge_mode_valid(struct drm_bridge *bridge,
return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
}
static int it6263_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct it6263 *it = bridge_to_it6263(bridge);
struct drm_connector *connector;
int ret;
- ret = drm_bridge_attach(bridge->encoder, it->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, it->next_bridge, bridge,
flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
return 0;
- connector = drm_bridge_connector_init(bridge->dev, bridge->encoder);
+ connector = drm_bridge_connector_init(bridge->dev, encoder);
if (IS_ERR(connector)) {
ret = PTR_ERR(connector);
dev_err(it->dev, "failed to initialize bridge connector: %d\n",
ret);
return ret;
}
- drm_connector_attach_encoder(connector, bridge->encoder);
+ drm_connector_attach_encoder(connector, encoder);
return 0;
}
static enum drm_connector_status it6263_bridge_detect(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
index 8a607558ac89ed2961d13515d987c141f2b6e116..4e8b1dcba64fcf09ffd68d1a57dec5d30190ebe6 100644
--- a/drivers/gpu/drm/bridge/ite-it6505.c
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -3122,10 +3122,11 @@ static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge)
{
return container_of(bridge, struct it6505, bridge);
}
static int it6505_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct it6505 *it6505 = bridge_to_it6505(bridge);
struct device *dev = it6505->dev;
int ret;
diff --git a/drivers/gpu/drm/bridge/ite-it66121.c b/drivers/gpu/drm/bridge/ite-it66121.c
index b9f90f32145de0f17eadfdf0efbe95a2b5ca026d..7b110ae532918d2d6f91ebc5f747c38e7e77dc07 100644
--- a/drivers/gpu/drm/bridge/ite-it66121.c
+++ b/drivers/gpu/drm/bridge/ite-it66121.c
@@ -584,19 +584,20 @@ static bool it66121_is_hpd_detect(struct it66121_ctx *ctx)
return val & IT66121_SYS_STATUS_HPDETECT;
}
static int it66121_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct it66121_ctx *ctx = container_of(bridge, struct it66121_ctx, bridge);
int ret;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- ret = drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags);
+ ret = drm_bridge_attach(encoder, ctx->next_bridge, bridge, flags);
if (ret)
return ret;
if (ctx->info->id == ID_IT66121) {
ret = regmap_write_bits(ctx->regmap, IT66121_CLK_BANK_REG,
diff --git a/drivers/gpu/drm/bridge/lontium-lt8912b.c b/drivers/gpu/drm/bridge/lontium-lt8912b.c
index 52da204f57404e63c7eadb4318b55082ae732105..3e49d855b3648880cea9bce5f3f04fbb6f838a45 100644
--- a/drivers/gpu/drm/bridge/lontium-lt8912b.c
+++ b/drivers/gpu/drm/bridge/lontium-lt8912b.c
@@ -541,16 +541,17 @@ static int lt8912_bridge_connector_init(struct drm_bridge *bridge)
exit:
return ret;
}
static int lt8912_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct lt8912 *lt = bridge_to_lt8912(bridge);
int ret;
- ret = drm_bridge_attach(bridge->encoder, lt->hdmi_port, bridge,
+ ret = drm_bridge_attach(encoder, lt->hdmi_port, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0) {
dev_err(lt->dev, "Failed to attach next bridge (%d)\n", ret);
return ret;
}
diff --git a/drivers/gpu/drm/bridge/lontium-lt9211.c b/drivers/gpu/drm/bridge/lontium-lt9211.c
index 0fc5ea18fe6a8d0c1578dcae960d78cc33f4fb6d..9b2dac9bd63c5afd4ffbafafdbbb1230549bc36f 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9211.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9211.c
@@ -97,15 +97,16 @@ static struct lt9211 *bridge_to_lt9211(struct drm_bridge *bridge)
{
return container_of(bridge, struct lt9211, bridge);
}
static int lt9211_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct lt9211 *ctx = bridge_to_lt9211(bridge);
- return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+ return drm_bridge_attach(encoder, ctx->panel_bridge,
&ctx->bridge, flags);
}
static int lt9211_read_chipid(struct lt9211 *ctx)
{
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611.c b/drivers/gpu/drm/bridge/lontium-lt9611.c
index 026803034231f78c17f619dc04119bdd9b2b6679..53987e826ccd3368e94a1d7563354d359ebcbb17 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611.c
@@ -738,15 +738,16 @@ static struct mipi_dsi_device *lt9611_attach_dsi(struct lt9611 *lt9611,
return dsi;
}
static int lt9611_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct lt9611 *lt9611 = bridge_to_lt9611(bridge);
- return drm_bridge_attach(bridge->encoder, lt9611->next_bridge,
+ return drm_bridge_attach(encoder, lt9611->next_bridge,
bridge, flags);
}
static enum drm_mode_status lt9611_bridge_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
diff --git a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
index f4c3ff1fdc6923eb7a8c0d8f7f92e7649c797d77..20bf1a3c786d8ecc10ac58225f28e5c519fd1bf9 100644
--- a/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
+++ b/drivers/gpu/drm/bridge/lontium-lt9611uxc.c
@@ -278,15 +278,16 @@ static struct mipi_dsi_device *lt9611uxc_attach_dsi(struct lt9611uxc *lt9611uxc,
return dsi;
}
static int lt9611uxc_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct lt9611uxc *lt9611uxc = bridge_to_lt9611uxc(bridge);
- return drm_bridge_attach(bridge->encoder, lt9611uxc->next_bridge,
+ return drm_bridge_attach(encoder, lt9611uxc->next_bridge,
bridge, flags);
}
static enum drm_mode_status
lt9611uxc_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/bridge/lvds-codec.c b/drivers/gpu/drm/bridge/lvds-codec.c
index 389af0233fcdec9af7a4fbfe8d267170fbc4759c..1646e454e0b0b558d00f9421f15bb7084e2aa45a 100644
--- a/drivers/gpu/drm/bridge/lvds-codec.c
+++ b/drivers/gpu/drm/bridge/lvds-codec.c
@@ -32,15 +32,16 @@ static inline struct lvds_codec *to_lvds_codec(struct drm_bridge *bridge)
{
return container_of(bridge, struct lvds_codec, bridge);
}
static int lvds_codec_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct lvds_codec *lvds_codec = to_lvds_codec(bridge);
- return drm_bridge_attach(bridge->encoder, lvds_codec->panel_bridge,
+ return drm_bridge_attach(encoder, lvds_codec->panel_bridge,
bridge, flags);
}
static void lvds_codec_enable(struct drm_bridge *bridge)
{
diff --git a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
index a47aabf134fd5c78448eae50b14a5ec322e6d6d0..15a5a1f644fc10182c55bc9e489ccb81d4f924f9 100644
--- a/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
+++ b/drivers/gpu/drm/bridge/megachips-stdpxxxx-ge-b850v3-fw.c
@@ -188,10 +188,11 @@ static irqreturn_t ge_b850v3_lvds_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int ge_b850v3_lvds_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct i2c_client *stdp4028_i2c
= ge_b850v3_lvds_ptr->stdp4028_i2c;
diff --git a/drivers/gpu/drm/bridge/microchip-lvds.c b/drivers/gpu/drm/bridge/microchip-lvds.c
index 53dd140a1b8d1b333c1f932b4d205a028f818251..1d4ae0097df847d9f93c79eecff0c4587ae331ba 100644
--- a/drivers/gpu/drm/bridge/microchip-lvds.c
+++ b/drivers/gpu/drm/bridge/microchip-lvds.c
@@ -102,15 +102,16 @@ static void lvds_serialiser_on(struct mchp_lvds *lvds)
/* Enable the LVDS serializer */
lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN);
}
static int mchp_lvds_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mchp_lvds *lvds = bridge_to_lvds(bridge);
- return drm_bridge_attach(bridge->encoder, lvds->panel_bridge,
+ return drm_bridge_attach(encoder, lvds->panel_bridge,
bridge, flags);
}
static void mchp_lvds_enable(struct drm_bridge *bridge)
{
diff --git a/drivers/gpu/drm/bridge/nwl-dsi.c b/drivers/gpu/drm/bridge/nwl-dsi.c
index d04c62a0cb9f8ab6bbc1e3f6e49c3a5ba9cf9716..55912ae11f46a1d551e11f93a306a8a00ef3f7d8 100644
--- a/drivers/gpu/drm/bridge/nwl-dsi.c
+++ b/drivers/gpu/drm/bridge/nwl-dsi.c
@@ -908,20 +908,21 @@ static void nwl_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
if (ret < 0)
DRM_DEV_ERROR(dsi->dev, "Failed to deassert DPI: %d\n", ret);
}
static int nwl_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct nwl_dsi *dsi = bridge_to_dsi(bridge);
struct drm_bridge *panel_bridge;
panel_bridge = devm_drm_of_get_bridge(dsi->dev, dsi->dev->of_node, 1, 0);
if (IS_ERR(panel_bridge))
return PTR_ERR(panel_bridge);
- return drm_bridge_attach(bridge->encoder, panel_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, panel_bridge, bridge, flags);
}
static u32 *nwl_bridge_atomic_get_input_bus_fmts(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
struct drm_crtc_state *crtc_state,
diff --git a/drivers/gpu/drm/bridge/nxp-ptn3460.c b/drivers/gpu/drm/bridge/nxp-ptn3460.c
index 27261b2ac9c83c311201b20f02aef7afeb6475b2..25d7c415478b14ef634bff4185a8dd8e866be0c6 100644
--- a/drivers/gpu/drm/bridge/nxp-ptn3460.c
+++ b/drivers/gpu/drm/bridge/nxp-ptn3460.c
@@ -212,17 +212,18 @@ static const struct drm_connector_funcs ptn3460_connector_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int ptn3460_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
int ret;
/* Let this driver create connector if requested */
- ret = drm_bridge_attach(bridge->encoder, ptn_bridge->panel_bridge,
+ ret = drm_bridge_attach(encoder, ptn_bridge->panel_bridge,
bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
@@ -237,11 +238,11 @@ static int ptn3460_bridge_attach(struct drm_bridge *bridge,
}
drm_connector_helper_add(&ptn_bridge->connector,
&ptn3460_connector_helper_funcs);
drm_connector_register(&ptn_bridge->connector);
drm_connector_attach_encoder(&ptn_bridge->connector,
- bridge->encoder);
+ encoder);
drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
return ret;
}
diff --git a/drivers/gpu/drm/bridge/panel.c b/drivers/gpu/drm/bridge/panel.c
index 258c85c83a28349672d660dcf8b0b50bbbb824f8..79b009ab9396048eac57ad47631a902e949d77c6 100644
--- a/drivers/gpu/drm/bridge/panel.c
+++ b/drivers/gpu/drm/bridge/panel.c
@@ -56,10 +56,11 @@ static const struct drm_connector_funcs panel_bridge_connector_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int panel_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct panel_bridge *panel_bridge = drm_bridge_to_panel_bridge(bridge);
struct drm_connector *connector = &panel_bridge->connector;
int ret;
@@ -79,11 +80,11 @@ static int panel_bridge_attach(struct drm_bridge *bridge,
}
drm_panel_bridge_set_orientation(connector, bridge);
drm_connector_attach_encoder(&panel_bridge->connector,
- bridge->encoder);
+ encoder);
if (bridge->dev->registered) {
if (connector->funcs->reset)
connector->funcs->reset(connector);
drm_connector_register(connector);
diff --git a/drivers/gpu/drm/bridge/parade-ps8622.c b/drivers/gpu/drm/bridge/parade-ps8622.c
index 13ada42a55142cd22696671e8fb363bee6d6aa68..8726fefc5c654e49bce029d943d241789ca4f802 100644
--- a/drivers/gpu/drm/bridge/parade-ps8622.c
+++ b/drivers/gpu/drm/bridge/parade-ps8622.c
@@ -416,10 +416,11 @@ static void ps8622_post_disable(struct drm_bridge *bridge)
msleep(PS8622_POWER_OFF_T17_MS);
}
static int ps8622_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge);
return drm_bridge_attach(ps8622->bridge.encoder, ps8622->panel_bridge,
diff --git a/drivers/gpu/drm/bridge/parade-ps8640.c b/drivers/gpu/drm/bridge/parade-ps8640.c
index a42138b33258a48a303a97fbb07504893aeafaf7..2422ff68c1042bd8eaa6821ff387d4faad47c550 100644
--- a/drivers/gpu/drm/bridge/parade-ps8640.c
+++ b/drivers/gpu/drm/bridge/parade-ps8640.c
@@ -492,10 +492,11 @@ static void ps8640_atomic_post_disable(struct drm_bridge *bridge,
mutex_unlock(&ps_bridge->aux_lock);
}
static int ps8640_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ps8640 *ps_bridge = bridge_to_ps8640(bridge);
struct device *dev = &ps_bridge->page[0]->dev;
int ret;
@@ -516,11 +517,11 @@ static int ps8640_bridge_attach(struct drm_bridge *bridge,
ret = -EINVAL;
goto err_devlink;
}
/* Attach the panel-bridge to the dsi bridge */
- ret = drm_bridge_attach(bridge->encoder, ps_bridge->panel_bridge,
+ ret = drm_bridge_attach(encoder, ps_bridge->panel_bridge,
&ps_bridge->bridge, flags);
if (ret)
goto err_bridge_attach;
return 0;
diff --git a/drivers/gpu/drm/bridge/samsung-dsim.c b/drivers/gpu/drm/bridge/samsung-dsim.c
index 54de6ed2fae81bc13301a6b1ee8f38183a3118b6..55ac6bd5da08c037aa7974df679d51e72bc54faf 100644
--- a/drivers/gpu/drm/bridge/samsung-dsim.c
+++ b/drivers/gpu/drm/bridge/samsung-dsim.c
@@ -1638,15 +1638,16 @@ static void samsung_dsim_mode_set(struct drm_bridge *bridge,
drm_mode_copy(&dsi->mode, adjusted_mode);
}
static int samsung_dsim_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct samsung_dsim *dsi = bridge_to_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, dsi->out_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi->out_bridge, bridge,
flags);
}
static const struct drm_bridge_funcs samsung_dsim_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index 914a2609a685f7e853fde181fa22494bf9b5996f..6d185b7b0c3e9eda3154a8b7880819157bb1e53a 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -414,19 +414,20 @@ static void sii902x_bridge_mode_set(struct drm_bridge *bridge,
out:
mutex_unlock(&sii902x->mutex);
}
static int sii902x_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct sii902x *sii902x = bridge_to_sii902x(bridge);
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct drm_device *drm = bridge->dev;
int ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
- return drm_bridge_attach(bridge->encoder, sii902x->next_bridge,
+ return drm_bridge_attach(encoder, sii902x->next_bridge,
bridge, flags);
drm_connector_helper_add(&sii902x->connector,
&sii902x_connector_helper_funcs);
@@ -450,11 +451,11 @@ static int sii902x_bridge_attach(struct drm_bridge *bridge,
ret = drm_display_info_set_bus_formats(&sii902x->connector.display_info,
&bus_format, 1);
if (ret)
return ret;
- drm_connector_attach_encoder(&sii902x->connector, bridge->encoder);
+ drm_connector_attach_encoder(&sii902x->connector, encoder);
return 0;
}
static enum drm_connector_status sii902x_bridge_detect(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/sil-sii8620.c b/drivers/gpu/drm/bridge/sil-sii8620.c
index 28a2e1ee04b2828364c6e633399b821562fc8728..3af650dc92a1612ca88fe378319519546b79901f 100644
--- a/drivers/gpu/drm/bridge/sil-sii8620.c
+++ b/drivers/gpu/drm/bridge/sil-sii8620.c
@@ -2201,10 +2201,11 @@ static inline struct sii8620 *bridge_to_sii8620(struct drm_bridge *bridge)
{
return container_of(bridge, struct sii8620, bridge);
}
static int sii8620_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct sii8620 *ctx = bridge_to_sii8620(bridge);
sii8620_init_rcp_input_dev(ctx);
diff --git a/drivers/gpu/drm/bridge/simple-bridge.c b/drivers/gpu/drm/bridge/simple-bridge.c
index ab0b0e36e97ac244427ac316acd9230c9490f2ce..70db5b99e5bb84f099ec54cf62abbda53475311d 100644
--- a/drivers/gpu/drm/bridge/simple-bridge.c
+++ b/drivers/gpu/drm/bridge/simple-bridge.c
@@ -101,16 +101,17 @@ static const struct drm_connector_funcs simple_bridge_con_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int simple_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct simple_bridge *sbridge = drm_bridge_to_simple_bridge(bridge);
int ret;
- ret = drm_bridge_attach(bridge->encoder, sbridge->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, sbridge->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
@@ -125,11 +126,11 @@ static int simple_bridge_attach(struct drm_bridge *bridge,
if (ret) {
DRM_ERROR("Failed to initialize connector\n");
return ret;
}
- drm_connector_attach_encoder(&sbridge->connector, bridge->encoder);
+ drm_connector_attach_encoder(&sbridge->connector, encoder);
return 0;
}
static void simple_bridge_enable(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 0890add5f7070f13fefad923526e92f516f06764..b1cdf806b3c4007dfef09c632fea354f7f6001b5 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2887,16 +2887,17 @@ static int dw_hdmi_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dw_hdmi *hdmi = bridge->driver_private;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
- return drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ return drm_bridge_attach(encoder, hdmi->next_bridge,
bridge, flags);
return dw_hdmi_connector_create(hdmi);
}
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
index 2b6e70a49f438c475bc60d9595bf246a9e54995b..b08ada920a501d6a62f39581944a87019f5e5c15 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c
@@ -1070,19 +1070,20 @@ dw_mipi_dsi_bridge_mode_valid(struct drm_bridge *bridge,
return mode_status;
}
static int dw_mipi_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dw_mipi_dsi *dsi = bridge_to_dsi(bridge);
/* Set the encoder type as caller does not know it */
- bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
+ encoder->encoder_type = DRM_MODE_ENCODER_DSI;
/* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi->panel_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi->panel_bridge, bridge,
flags);
}
static const struct drm_bridge_funcs dw_mipi_dsi_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c
index 5fd7a459efdd4fc4884cdf77ffedc19c36d1ca13..c76f5f2e74d14bd372f969c6c7832aa57f80772b 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi2.c
@@ -868,19 +868,20 @@ dw_mipi_dsi2_bridge_mode_valid(struct drm_bridge *bridge,
return mode_status;
}
static int dw_mipi_dsi2_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dw_mipi_dsi2 *dsi2 = bridge_to_dsi2(bridge);
/* Set the encoder type as caller does not know it */
- bridge->encoder->encoder_type = DRM_MODE_ENCODER_DSI;
+ encoder->encoder_type = DRM_MODE_ENCODER_DSI;
/* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi2->panel_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi2->panel_bridge, bridge,
flags);
}
static const struct drm_bridge_funcs dw_mipi_dsi2_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
diff --git a/drivers/gpu/drm/bridge/tc358762.c b/drivers/gpu/drm/bridge/tc358762.c
index 49c76027f8316967ea4f7d7dfb85920a025b6df9..edf01476f2ef6e05ef2c144ff4467e7f6babc4c6 100644
--- a/drivers/gpu/drm/bridge/tc358762.c
+++ b/drivers/gpu/drm/bridge/tc358762.c
@@ -200,15 +200,16 @@ static void tc358762_enable(struct drm_bridge *bridge,
if (ret < 0)
dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
}
static int tc358762_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tc358762 *ctx = bridge_to_tc358762(bridge);
- return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+ return drm_bridge_attach(encoder, ctx->panel_bridge,
bridge, flags);
}
static void tc358762_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/bridge/tc358764.c b/drivers/gpu/drm/bridge/tc358764.c
index 3d3d135b43487aaf5a1908c21c1c988e87d24d48..3f76c890fad9ffa50dc02f289a37378332830516 100644
--- a/drivers/gpu/drm/bridge/tc358764.c
+++ b/drivers/gpu/drm/bridge/tc358764.c
@@ -293,15 +293,16 @@ static void tc358764_pre_enable(struct drm_bridge *bridge)
if (ret < 0)
dev_err(ctx->dev, "error initializing bridge (%d)\n", ret);
}
static int tc358764_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tc358764 *ctx = bridge_to_tc358764(bridge);
- return drm_bridge_attach(bridge->encoder, ctx->next_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, ctx->next_bridge, bridge, flags);
}
static const struct drm_bridge_funcs tc358764_bridge_funcs = {
.post_disable = tc358764_post_disable,
.pre_enable = tc358764_pre_enable,
diff --git a/drivers/gpu/drm/bridge/tc358767.c b/drivers/gpu/drm/bridge/tc358767.c
index 39e2d3a7a27d2603bb847d55c4812fb170389ba0..7e5449fb86a3fcdae8255bc490d12c543ef3f8ae 100644
--- a/drivers/gpu/drm/bridge/tc358767.c
+++ b/drivers/gpu/drm/bridge/tc358767.c
@@ -1793,10 +1793,11 @@ static const struct drm_connector_funcs tc_connector_funcs = {
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tc_data *tc = bridge_to_tc(bridge);
if (!tc->panel_bridge)
@@ -1805,10 +1806,11 @@ static int tc_dpi_bridge_attach(struct drm_bridge *bridge,
return drm_bridge_attach(tc->bridge.encoder, tc->panel_bridge,
&tc->bridge, flags);
}
static int tc_edp_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
struct tc_data *tc = bridge_to_tc(bridge);
struct drm_device *drm = bridge->dev;
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index ec79b0dd0e2cd6dfbdd8aee54d6a8d9cf8bfb060..6db18d1e8824dd7d387211d6d1e668645cf88bbe 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -552,20 +552,21 @@ static const struct mipi_dsi_host_ops tc358768_dsi_host_ops = {
.detach = tc358768_dsi_host_detach,
.transfer = tc358768_dsi_host_transfer,
};
static int tc358768_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
if (!drm_core_check_feature(bridge->dev, DRIVER_ATOMIC)) {
dev_err(priv->dev, "needs atomic updates support\n");
return -ENOTSUPP;
}
- return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge,
+ return drm_bridge_attach(encoder, priv->output.bridge, bridge,
flags);
}
static enum drm_mode_status
tc358768_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
index c89757bec4e6cc59ea0e84b1096ba71b077d408e..13cd48e77d2d3f8dd646078fb7de95c420f29f73 100644
--- a/drivers/gpu/drm/bridge/tc358775.c
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -587,16 +587,17 @@ static int tc358775_parse_dt(struct device_node *np, struct tc_data *tc)
return 0;
}
static int tc_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tc_data *tc = bridge_to_tc(bridge);
/* Attach the panel-bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, tc->panel_bridge,
+ return drm_bridge_attach(encoder, tc->panel_bridge,
&tc->bridge, flags);
}
static const struct drm_bridge_funcs tc_bridge_funcs = {
.attach = tc_bridge_attach,
diff --git a/drivers/gpu/drm/bridge/tda998x_drv.c b/drivers/gpu/drm/bridge/tda998x_drv.c
index ebc758c72891188e236d4da0cde283f108d80aca..9c5bb2a1676986c89f47e23fe33dfa391a3de30a 100644
--- a/drivers/gpu/drm/bridge/tda998x_drv.c
+++ b/drivers/gpu/drm/bridge/tda998x_drv.c
@@ -1363,10 +1363,11 @@ static int tda998x_connector_init(struct tda998x_priv *priv,
}
/* DRM bridge functions */
static int tda998x_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tda998x_priv *priv = bridge_to_tda998x_priv(bridge);
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
diff --git a/drivers/gpu/drm/bridge/thc63lvd1024.c b/drivers/gpu/drm/bridge/thc63lvd1024.c
index bba10cf9b4f96aef69f82403a7642d08c2b9f4b7..e2fc78adebcf22f0d8cdb484078e37b748b776c6 100644
--- a/drivers/gpu/drm/bridge/thc63lvd1024.c
+++ b/drivers/gpu/drm/bridge/thc63lvd1024.c
@@ -41,15 +41,16 @@ static inline struct thc63_dev *to_thc63(struct drm_bridge *bridge)
{
return container_of(bridge, struct thc63_dev, bridge);
}
static int thc63_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct thc63_dev *thc63 = to_thc63(bridge);
- return drm_bridge_attach(bridge->encoder, thc63->next, bridge, flags);
+ return drm_bridge_attach(encoder, thc63->next, bridge, flags);
}
static enum drm_mode_status thc63_mode_valid(struct drm_bridge *bridge,
const struct drm_display_info *info,
const struct drm_display_mode *mode)
diff --git a/drivers/gpu/drm/bridge/ti-dlpc3433.c b/drivers/gpu/drm/bridge/ti-dlpc3433.c
index 85f2a0e74a1c8aaa272ce828ad1c82660503b7a8..47638d1c96ec5ad999604c8c7e8839ff85936d98 100644
--- a/drivers/gpu/drm/bridge/ti-dlpc3433.c
+++ b/drivers/gpu/drm/bridge/ti-dlpc3433.c
@@ -240,16 +240,16 @@ static void dlpc_mode_set(struct drm_bridge *bridge,
struct dlpc *dlpc = bridge_to_dlpc(bridge);
drm_mode_copy(&dlpc->mode, adjusted_mode);
}
-static int dlpc_attach(struct drm_bridge *bridge,
+static int dlpc_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dlpc *dlpc = bridge_to_dlpc(bridge);
- return drm_bridge_attach(bridge->encoder, dlpc->next_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, dlpc->next_bridge, bridge, flags);
}
static const struct drm_bridge_funcs dlpc_bridge_funcs = {
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 95563aa1b450d549be8cacbe58c45f07b93595e5..7122a3ebd88399ed32420fcaf9f1f9384d031d2d 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -288,15 +288,16 @@ static struct sn65dsi83 *bridge_to_sn65dsi83(struct drm_bridge *bridge)
{
return container_of(bridge, struct sn65dsi83, bridge);
}
static int sn65dsi83_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct sn65dsi83 *ctx = bridge_to_sn65dsi83(bridge);
- return drm_bridge_attach(bridge->encoder, ctx->panel_bridge,
+ return drm_bridge_attach(encoder, ctx->panel_bridge,
&ctx->bridge, flags);
}
static void sn65dsi83_detach(struct drm_bridge *bridge)
{
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 01d456b955abbb2cca65c222bf7a24d6f1697d02..190929a41abd1d8d6619e27bb9391f75145ed64a 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -730,10 +730,11 @@ static int ti_sn_attach_host(struct auxiliary_device *adev, struct ti_sn65dsi86
return devm_mipi_dsi_attach(&adev->dev, dsi);
}
static int ti_sn_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
int ret;
@@ -746,11 +747,11 @@ static int ti_sn_bridge_attach(struct drm_bridge *bridge,
/*
* Attach the next bridge.
* We never want the next bridge to *also* create a connector.
*/
- ret = drm_bridge_attach(bridge->encoder, pdata->next_bridge,
+ ret = drm_bridge_attach(encoder, pdata->next_bridge,
&pdata->bridge, flags | DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0)
goto err_initted_aux;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
diff --git a/drivers/gpu/drm/bridge/ti-tdp158.c b/drivers/gpu/drm/bridge/ti-tdp158.c
index 22316382451fa3a55e1b3977982bd306b52b5888..cca75443f0121e39527a6cecf711eff2c0d507b5 100644
--- a/drivers/gpu/drm/bridge/ti-tdp158.c
+++ b/drivers/gpu/drm/bridge/ti-tdp158.c
@@ -43,15 +43,17 @@ static void tdp158_disable(struct drm_bridge *bridge,
gpiod_set_value_cansleep(tdp158->enable, 0);
regulator_disable(tdp158->vdd);
regulator_disable(tdp158->vcc);
}
-static int tdp158_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
+static int tdp158_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
{
struct tdp158 *tdp158 = bridge->driver_private;
- return drm_bridge_attach(bridge->encoder, tdp158->next, bridge, flags);
+ return drm_bridge_attach(encoder, tdp158->next, bridge, flags);
}
static const struct drm_bridge_funcs tdp158_bridge_funcs = {
.attach = tdp158_attach,
.atomic_enable = tdp158_enable,
diff --git a/drivers/gpu/drm/bridge/ti-tfp410.c b/drivers/gpu/drm/bridge/ti-tfp410.c
index 79ab5da827e1fd3850435a02daedad87186a4ab8..e15d232ddbac55c6f5f966471a6c63f9c29a06c1 100644
--- a/drivers/gpu/drm/bridge/ti-tfp410.c
+++ b/drivers/gpu/drm/bridge/ti-tfp410.c
@@ -118,16 +118,17 @@ static void tfp410_hpd_callback(void *arg, enum drm_connector_status status)
mod_delayed_work(system_wq, &dvi->hpd_work,
msecs_to_jiffies(HOTPLUG_DEBOUNCE_MS));
}
static int tfp410_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tfp410 *dvi = drm_bridge_to_tfp410(bridge);
int ret;
- ret = drm_bridge_attach(bridge->encoder, dvi->next_bridge, bridge,
+ ret = drm_bridge_attach(encoder, dvi->next_bridge, bridge,
DRM_BRIDGE_ATTACH_NO_CONNECTOR);
if (ret < 0)
return ret;
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR)
@@ -157,11 +158,11 @@ static int tfp410_attach(struct drm_bridge *bridge,
}
drm_display_info_set_bus_formats(&dvi->connector.display_info,
&dvi->bus_format, 1);
- drm_connector_attach_encoder(&dvi->connector, bridge->encoder);
+ drm_connector_attach_encoder(&dvi->connector, encoder);
return 0;
}
static void tfp410_detach(struct drm_bridge *bridge)
diff --git a/drivers/gpu/drm/bridge/ti-tpd12s015.c b/drivers/gpu/drm/bridge/ti-tpd12s015.c
index 47b74cb25b14fcf4a09137d8b5b7f4ff739eae59..1c289051a5987e0aec4c286ef4c01ee1a2f9421f 100644
--- a/drivers/gpu/drm/bridge/ti-tpd12s015.c
+++ b/drivers/gpu/drm/bridge/ti-tpd12s015.c
@@ -36,19 +36,20 @@ static inline struct tpd12s015_device *to_tpd12s015(struct drm_bridge *bridge)
{
return container_of(bridge, struct tpd12s015_device, bridge);
}
static int tpd12s015_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tpd12s015_device *tpd = to_tpd12s015(bridge);
int ret;
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- ret = drm_bridge_attach(bridge->encoder, tpd->next_bridge,
+ ret = drm_bridge_attach(encoder, tpd->next_bridge,
bridge, flags);
if (ret < 0)
return ret;
gpiod_set_value_cansleep(tpd->ls_oe_gpio, 1);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index fa2794217a903b6c61e58edf14756a72f99dad38..8241c00e4506eceeb9bb4ba74a38d8f360c65d38 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -325,11 +325,11 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
list_add(&bridge->chain_node, &previous->chain_node);
else
list_add(&bridge->chain_node, &encoder->bridge_chain);
if (bridge->funcs->attach) {
- ret = bridge->funcs->attach(bridge, flags);
+ ret = bridge->funcs->attach(bridge, encoder, flags);
if (ret < 0)
goto err_reset_bridge;
}
if (bridge->funcs->atomic_reset) {
diff --git a/drivers/gpu/drm/imx/ipuv3/parallel-display.c b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
index 9e66eb77b1ebe853599a60df69ce8db94fdffd49..6d8325c766979aa3ba98970f00806e99c139d3c3 100644
--- a/drivers/gpu/drm/imx/ipuv3/parallel-display.c
+++ b/drivers/gpu/drm/imx/ipuv3/parallel-display.c
@@ -160,15 +160,16 @@ static int imx_pd_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
static int imx_pd_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct imx_parallel_display *imxpd = bridge_to_imxpd(bridge);
- return drm_bridge_attach(bridge->encoder, imxpd->next_bridge, bridge, flags);
+ return drm_bridge_attach(encoder, imxpd->next_bridge, bridge, flags);
}
static const struct drm_bridge_funcs imx_pd_bridge_funcs = {
.attach = imx_pd_bridge_attach,
.atomic_reset = drm_atomic_helper_bridge_reset,
diff --git a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
index 20b93fff023995062096941ae571756185688387..f851e9ffdb280388452c9ad0883932f5b990d6f0 100644
--- a/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
+++ b/drivers/gpu/drm/ingenic/ingenic-drm-drv.c
@@ -789,15 +789,16 @@ static void ingenic_drm_encoder_atomic_mode_set(struct drm_encoder *encoder,
regmap_write(priv->map, JZ_REG_LCD_CFG, cfg);
regmap_write(priv->map, JZ_REG_LCD_RGBC, rgbcfg);
}
static int ingenic_drm_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
- struct ingenic_drm_bridge *ib = to_ingenic_drm_bridge(bridge->encoder);
+ struct ingenic_drm_bridge *ib = to_ingenic_drm_bridge(encoder);
- return drm_bridge_attach(bridge->encoder, ib->next_bridge,
+ return drm_bridge_attach(encoder, ib->next_bridge,
&ib->bridge, flags);
}
static int ingenic_drm_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
diff --git a/drivers/gpu/drm/mcde/mcde_dsi.c b/drivers/gpu/drm/mcde/mcde_dsi.c
index 395449a72f0a1dc0d8ee97ecd245ca52f0282402..b302d8ec3ad0e82ace9c10194ae37948ebb8e753 100644
--- a/drivers/gpu/drm/mcde/mcde_dsi.c
+++ b/drivers/gpu/drm/mcde/mcde_dsi.c
@@ -1046,10 +1046,11 @@ void mcde_dsi_disable(struct drm_bridge *bridge)
clk_disable_unprepare(d->hs_clk);
clk_disable_unprepare(d->lp_clk);
}
static int mcde_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mcde_dsi *d = bridge_to_mcde_dsi(bridge);
struct drm_device *drm = bridge->dev;
@@ -1057,11 +1058,11 @@ static int mcde_dsi_bridge_attach(struct drm_bridge *bridge,
dev_err(d->dev, "we need atomic updates\n");
return -ENOTSUPP;
}
/* Attach the DSI bridge to the output (panel etc) bridge */
- return drm_bridge_attach(bridge->encoder, d->bridge_out, bridge, flags);
+ return drm_bridge_attach(encoder, d->bridge_out, bridge, flags);
}
static const struct drm_bridge_funcs mcde_dsi_bridge_funcs = {
.attach = mcde_dsi_bridge_attach,
.mode_set = mcde_dsi_bridge_mode_set,
diff --git a/drivers/gpu/drm/mediatek/mtk_dp.c b/drivers/gpu/drm/mediatek/mtk_dp.c
index 3d4648d2e15f1a1a3c6ae596e1a35cd654fcc35c..4523cc0a2db8cd8b57183e11140b8a6584e95a34 100644
--- a/drivers/gpu/drm/mediatek/mtk_dp.c
+++ b/drivers/gpu/drm/mediatek/mtk_dp.c
@@ -2285,10 +2285,11 @@ static void mtk_dp_poweroff(struct mtk_dp *mtk_dp)
mtk_dp_power_disable(mtk_dp);
phy_exit(mtk_dp->phy);
}
static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dp *mtk_dp = mtk_dp_from_bridge(bridge);
int ret;
@@ -2308,11 +2309,11 @@ static int mtk_dp_bridge_attach(struct drm_bridge *bridge,
ret = mtk_dp_poweron(mtk_dp);
if (ret)
goto err_aux_register;
if (mtk_dp->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, mtk_dp->next_bridge,
+ ret = drm_bridge_attach(encoder, mtk_dp->next_bridge,
&mtk_dp->bridge, flags);
if (ret) {
drm_warn(mtk_dp->drm_dev,
"Failed to attach external bridge: %d\n", ret);
goto err_bridge_attach;
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 1864eb02dbf50af09c65064834a8b27ca56c3528..6b96ed4fc8614569e53f76fe3e52507c7dc1249c 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -699,10 +699,11 @@ static int mtk_dpi_bridge_atomic_check(struct drm_bridge *bridge,
return 0;
}
static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dpi *dpi = bridge_to_dpi(bridge);
int ret;
@@ -717,11 +718,11 @@ static int mtk_dpi_bridge_attach(struct drm_bridge *bridge,
if (IS_ERR(dpi->next_bridge))
return dev_err_probe(dpi->dev, PTR_ERR(dpi->next_bridge),
"Failed to get bridge\n");
}
- return drm_bridge_attach(bridge->encoder, dpi->next_bridge,
+ return drm_bridge_attach(encoder, dpi->next_bridge,
&dpi->bridge, flags);
}
static void mtk_dpi_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 0683c2b3ca5bc5b09439c42d30fb1380e1c67c97..cd2fbd8487c55930bf3abd1c3131153469e5166a 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -805,16 +805,17 @@ static void mtk_output_dsi_disable(struct mtk_dsi *dsi)
dsi->enabled = false;
}
static int mtk_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_dsi *dsi = bridge_to_dsi(bridge);
/* Attach the panel or bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi->next_bridge,
+ return drm_bridge_attach(encoder, dsi->next_bridge,
&dsi->bridge, flags);
}
static void mtk_dsi_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index d4ab098e117477eea8fad568a134c0a796b380db..e753b8e2d91b9471df00678c5ad66e6adec6c36d 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -1276,10 +1276,11 @@ static const struct drm_edid *mtk_hdmi_bridge_edid_read(struct drm_bridge *bridg
return drm_edid;
}
static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct mtk_hdmi *hdmi = hdmi_ctx_from_bridge(bridge);
int ret;
@@ -1288,11 +1289,11 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge,
__func__);
return -EINVAL;
}
if (hdmi->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ ret = drm_bridge_attach(encoder, hdmi->next_bridge,
bridge, flags);
if (ret)
return ret;
}
diff --git a/drivers/gpu/drm/meson/meson_encoder_cvbs.c b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
index e79f7c3ce32efa8e5fe7afe274fe991ac363b734..c9678dc68fa142882e2beb24fe81185fbdef733b 100644
--- a/drivers/gpu/drm/meson/meson_encoder_cvbs.c
+++ b/drivers/gpu/drm/meson/meson_encoder_cvbs.c
@@ -81,16 +81,17 @@ meson_cvbs_get_mode(const struct drm_display_mode *req_mode)
return NULL;
}
static int meson_encoder_cvbs_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct meson_encoder_cvbs *meson_encoder_cvbs =
bridge_to_meson_encoder_cvbs(bridge);
- return drm_bridge_attach(bridge->encoder, meson_encoder_cvbs->next_bridge,
+ return drm_bridge_attach(encoder, meson_encoder_cvbs->next_bridge,
&meson_encoder_cvbs->bridge, flags);
}
static int meson_encoder_cvbs_get_modes(struct drm_bridge *bridge,
struct drm_connector *connector)
diff --git a/drivers/gpu/drm/meson/meson_encoder_dsi.c b/drivers/gpu/drm/meson/meson_encoder_dsi.c
index fe204437bd6576a258dc11319e2b905f170a24a1..3db518e5f95d324c218b730e0948c3dc845382bd 100644
--- a/drivers/gpu/drm/meson/meson_encoder_dsi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_dsi.c
@@ -31,15 +31,16 @@ struct meson_encoder_dsi {
#define bridge_to_meson_encoder_dsi(x) \
container_of(x, struct meson_encoder_dsi, bridge)
static int meson_encoder_dsi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct meson_encoder_dsi *encoder_dsi = bridge_to_meson_encoder_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, encoder_dsi->next_bridge,
+ return drm_bridge_attach(encoder, encoder_dsi->next_bridge,
&encoder_dsi->bridge, flags);
}
static void meson_encoder_dsi_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
index 6d1c9262a2cfb7b08a68efb86821bf5ecf8c0941..5f02695aafd1aa8444cd936a36e8f3a8010881a0 100644
--- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
+++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
@@ -47,15 +47,16 @@ struct meson_encoder_hdmi {
#define bridge_to_meson_encoder_hdmi(x) \
container_of(x, struct meson_encoder_hdmi, bridge)
static int meson_encoder_hdmi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
- return drm_bridge_attach(bridge->encoder, encoder_hdmi->next_bridge,
+ return drm_bridge_attach(encoder, encoder_hdmi->next_bridge,
&encoder_hdmi->bridge, flags);
}
static void meson_encoder_hdmi_detach(struct drm_bridge *bridge)
{
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index a210b7c9e5ca281a46fbdb226e25832719a684ea..895ba9815a652f00f7ace9cb7125ef8cef555d35 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -422,16 +422,17 @@ static enum drm_mode_status dsi_mgr_bridge_mode_valid(struct drm_bridge *bridge,
return msm_dsi_host_check_dsc(host, mode);
}
static int dsi_mgr_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
int id = dsi_mgr_bridge_get_id(bridge);
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
- return drm_bridge_attach(bridge->encoder, msm_dsi->next_bridge,
+ return drm_bridge_attach(encoder, msm_dsi->next_bridge,
bridge, flags);
}
static const struct drm_bridge_funcs dsi_mgr_bridge_funcs = {
.attach = dsi_mgr_bridge_attach,
diff --git a/drivers/gpu/drm/omapdrm/dss/dpi.c b/drivers/gpu/drm/omapdrm/dss/dpi.c
index b17e77f700ddda6c9972e5ff10d394fd72bf96b3..6eff97a091602f6d137095b3b7bf54fce17e8d3e 100644
--- a/drivers/gpu/drm/omapdrm/dss/dpi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dpi.c
@@ -418,20 +418,21 @@ static void dpi_init_pll(struct dpi_data *dpi)
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int dpi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dpi_data *dpi = drm_bridge_to_dpi(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
dpi_init_pll(dpi);
- return drm_bridge_attach(bridge->encoder, dpi->output.next_bridge,
+ return drm_bridge_attach(encoder, dpi->output.next_bridge,
bridge, flags);
}
static enum drm_mode_status
dpi_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/omapdrm/dss/dsi.c b/drivers/gpu/drm/omapdrm/dss/dsi.c
index 59d20eb8a7e0fdcc13060d00980452bc80c54eb2..35e3e332bdcf4cf69659de65deeea0f5dbd70358 100644
--- a/drivers/gpu/drm/omapdrm/dss/dsi.c
+++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
@@ -4615,18 +4615,19 @@ static const struct component_ops dsi_component_ops = {
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct dsi_data *dsi = drm_bridge_to_dsi(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- return drm_bridge_attach(bridge->encoder, dsi->output.next_bridge,
+ return drm_bridge_attach(encoder, dsi->output.next_bridge,
bridge, flags);
}
static enum drm_mode_status
dsi_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi4.c b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
index e1ac447221ee5ae5ee50637acfc8a30a8f111850..a3b22952fdc32b5899dae82d413108c5c0a1c3c8 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi4.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi4.c
@@ -312,18 +312,19 @@ void hdmi4_core_disable(struct hdmi_core_data *core)
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int hdmi4_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
+ return drm_bridge_attach(encoder, hdmi->output.next_bridge,
bridge, flags);
}
static void hdmi4_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/omapdrm/dss/hdmi5.c b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
index fa9904e4c218235bafa87be600680b3e5d5e2ea5..0c98444d39a93d8336b4d8dbd45aa4521181c3b4 100644
--- a/drivers/gpu/drm/omapdrm/dss/hdmi5.c
+++ b/drivers/gpu/drm/omapdrm/dss/hdmi5.c
@@ -310,18 +310,19 @@ static void hdmi_core_disable(struct omap_hdmi *hdmi)
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int hdmi5_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct omap_hdmi *hdmi = drm_bridge_to_hdmi(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- return drm_bridge_attach(bridge->encoder, hdmi->output.next_bridge,
+ return drm_bridge_attach(encoder, hdmi->output.next_bridge,
bridge, flags);
}
static void hdmi5_bridge_mode_set(struct drm_bridge *bridge,
const struct drm_display_mode *mode,
diff --git a/drivers/gpu/drm/omapdrm/dss/sdi.c b/drivers/gpu/drm/omapdrm/dss/sdi.c
index f9ae358e8e52145b3832b18286ba4834f3c2d8db..e78826e4b560a2b9af2d8a5a38e181bd3e44d250 100644
--- a/drivers/gpu/drm/omapdrm/dss/sdi.c
+++ b/drivers/gpu/drm/omapdrm/dss/sdi.c
@@ -126,18 +126,19 @@ static void sdi_config_lcd_manager(struct sdi_device *sdi)
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int sdi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct sdi_device *sdi = drm_bridge_to_sdi(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- return drm_bridge_attach(bridge->encoder, sdi->output.next_bridge,
+ return drm_bridge_attach(encoder, sdi->output.next_bridge,
bridge, flags);
}
static enum drm_mode_status
sdi_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/omapdrm/dss/venc.c b/drivers/gpu/drm/omapdrm/dss/venc.c
index aaeef603682c25773f2f809d8ac04f64cba5fb21..50349518eda1630400529caf27ca4469bb09fc82 100644
--- a/drivers/gpu/drm/omapdrm/dss/venc.c
+++ b/drivers/gpu/drm/omapdrm/dss/venc.c
@@ -536,18 +536,19 @@ static int venc_get_clocks(struct venc_device *venc)
/* -----------------------------------------------------------------------------
* DRM Bridge Operations
*/
static int venc_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct venc_device *venc = drm_bridge_to_venc(bridge);
if (!(flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR))
return -EINVAL;
- return drm_bridge_attach(bridge->encoder, venc->output.next_bridge,
+ return drm_bridge_attach(encoder, venc->output.next_bridge,
bridge, flags);
}
static enum drm_mode_status
venc_bridge_mode_valid(struct drm_bridge *bridge,
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c
index 380a855b832af9c09652ce39a78f974b63d949bb..a9145253294fcaef6bae4e1406a781f6d710d357 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_lvds.c
@@ -632,18 +632,19 @@ static bool rcar_lvds_mode_fixup(struct drm_bridge *bridge,
return true;
}
static int rcar_lvds_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct rcar_lvds *lvds = bridge_to_rcar_lvds(bridge);
if (!lvds->next_bridge)
return 0;
- return drm_bridge_attach(bridge->encoder, lvds->next_bridge, bridge,
+ return drm_bridge_attach(encoder, lvds->next_bridge, bridge,
flags);
}
static const struct drm_bridge_funcs rcar_lvds_bridge_ops = {
.attach = rcar_lvds_attach,
diff --git a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
index d1e626068065c559a708772d3bbf16efe166ff59..7ab8be46c7f6547f29b4d45af7ac704283da9dcd 100644
--- a/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rcar-du/rcar_mipi_dsi.c
@@ -797,15 +797,16 @@ static void rcar_mipi_dsi_stop_video(struct rcar_mipi_dsi *dsi)
/* -----------------------------------------------------------------------------
* Bridge
*/
static int rcar_mipi_dsi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct rcar_mipi_dsi *dsi = bridge_to_rcar_mipi_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi->next_bridge, bridge,
flags);
}
static void rcar_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
index 4550c6d847962f06886f2b7645bae73646f1ffb6..96c014449547b4042d7568573fde876b5b39bd04 100644
--- a/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
+++ b/drivers/gpu/drm/renesas/rz-du/rzg2l_mipi_dsi.c
@@ -521,15 +521,16 @@ static int rzg2l_mipi_dsi_stop_video(struct rzg2l_mipi_dsi *dsi)
/* -----------------------------------------------------------------------------
* Bridge
*/
static int rzg2l_mipi_dsi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct rzg2l_mipi_dsi *dsi = bridge_to_rzg2l_mipi_dsi(bridge);
- return drm_bridge_attach(bridge->encoder, dsi->next_bridge, bridge,
+ return drm_bridge_attach(encoder, dsi->next_bridge, bridge,
flags);
}
static void rzg2l_mipi_dsi_atomic_enable(struct drm_bridge *bridge,
struct drm_atomic_state *state)
diff --git a/drivers/gpu/drm/stm/lvds.c b/drivers/gpu/drm/stm/lvds.c
index 4613e8e3b8fddc4455be0e3f81e0e811418746a0..a3ae9a93ce6670eb2c4dd36b3e572fcbca791a1c 100644
--- a/drivers/gpu/drm/stm/lvds.c
+++ b/drivers/gpu/drm/stm/lvds.c
@@ -932,32 +932,31 @@ static const struct drm_connector_funcs lvds_conn_funcs = {
.destroy = drm_connector_cleanup,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
-static int lvds_attach(struct drm_bridge *bridge,
+static int lvds_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct stm_lvds *lvds = bridge_to_stm_lvds(bridge);
struct drm_connector *connector = &lvds->connector;
- struct drm_encoder *encoder = bridge->encoder;
int ret;
- if (!bridge->encoder) {
+ if (!encoder) {
drm_err(bridge->dev, "Parent encoder object not found\n");
return -ENODEV;
}
/* Set the encoder type as caller does not know it */
- bridge->encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
+ encoder->encoder_type = DRM_MODE_ENCODER_LVDS;
/* No cloning support */
- bridge->encoder->possible_clones = 0;
+ encoder->possible_clones = 0;
/* If we have a next bridge just attach it. */
if (lvds->next_bridge)
- return drm_bridge_attach(bridge->encoder, lvds->next_bridge,
+ return drm_bridge_attach(encoder, lvds->next_bridge,
bridge, flags);
if (flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR) {
drm_err(bridge->dev, "Fix bridge driver to make connector optional!");
return -EINVAL;
diff --git a/drivers/gpu/drm/tidss/tidss_encoder.c b/drivers/gpu/drm/tidss/tidss_encoder.c
index 17a86bed805481c6cf054f6cb3176d60faa0351c..95b4aeff277505d64254177093d9bcc4de9f4a86 100644
--- a/drivers/gpu/drm/tidss/tidss_encoder.c
+++ b/drivers/gpu/drm/tidss/tidss_encoder.c
@@ -32,15 +32,16 @@ static inline struct tidss_encoder
{
return container_of(b, struct tidss_encoder, bridge);
}
static int tidss_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct tidss_encoder *t_enc = bridge_to_tidss_encoder(bridge);
- return drm_bridge_attach(bridge->encoder, t_enc->next_bridge,
+ return drm_bridge_attach(encoder, t_enc->next_bridge,
bridge, flags);
}
static int tidss_bridge_atomic_check(struct drm_bridge *bridge,
struct drm_bridge_state *bridge_state,
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 779b22efe27bffc586a760fdc49012e02ac23d0d..efc6f6078b026764c59cfb2a33b28a88b7018c3a 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -1158,16 +1158,17 @@ static void vc4_dsi_bridge_enable(struct drm_bridge *bridge,
drm_print_regset32(&p, &dsi->regset);
}
}
static int vc4_dsi_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct vc4_dsi *dsi = bridge_to_vc4_dsi(bridge);
/* Attach the panel or bridge to the dsi bridge */
- return drm_bridge_attach(bridge->encoder, dsi->out_bridge,
+ return drm_bridge_attach(encoder, dsi->out_bridge,
&dsi->bridge, flags);
}
static ssize_t vc4_dsi_host_transfer(struct mipi_dsi_host *host,
const struct mipi_dsi_msg *msg)
diff --git a/drivers/gpu/drm/xlnx/zynqmp_dp.c b/drivers/gpu/drm/xlnx/zynqmp_dp.c
index a6a4a871f197652f589e569b9b8c95f79fa5a2a1..11d2415fb5a1f7fad03421898331289f2295d68b 100644
--- a/drivers/gpu/drm/xlnx/zynqmp_dp.c
+++ b/drivers/gpu/drm/xlnx/zynqmp_dp.c
@@ -1479,10 +1479,11 @@ static void zynqmp_dp_disp_disable(struct zynqmp_dp *dp,
/* -----------------------------------------------------------------------------
* DRM Bridge
*/
static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags)
{
struct zynqmp_dp *dp = bridge_to_dp(bridge);
int ret;
@@ -1492,11 +1493,11 @@ static int zynqmp_dp_bridge_attach(struct drm_bridge *bridge,
dev_err(dp->dev, "failed to initialize DP aux\n");
return ret;
}
if (dp->next_bridge) {
- ret = drm_bridge_attach(bridge->encoder, dp->next_bridge,
+ ret = drm_bridge_attach(encoder, dp->next_bridge,
bridge, flags);
if (ret < 0)
goto error;
}
diff --git a/drivers/platform/arm64/acer-aspire1-ec.c b/drivers/platform/arm64/acer-aspire1-ec.c
index 2df42406430db7bd9ae5dcca6aace88c3bf3baa0..958fe1bf5f85bb69ac7962f217de9f0b40cde9a1 100644
--- a/drivers/platform/arm64/acer-aspire1-ec.c
+++ b/drivers/platform/arm64/acer-aspire1-ec.c
@@ -364,11 +364,12 @@ static const struct power_supply_desc aspire_ec_adp_psy_desc = {
/*
* USB-C DP Alt mode HPD.
*/
-static int aspire_ec_bridge_attach(struct drm_bridge *bridge, enum drm_bridge_attach_flags flags)
+static int aspire_ec_bridge_attach(struct drm_bridge *bridge, struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
{
return flags & DRM_BRIDGE_ATTACH_NO_CONNECTOR ? 0 : -EINVAL;
}
static void aspire_ec_bridge_update_hpd_work(struct work_struct *work)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index d4c75d59fa12be1bd7375ce3ea56415235781b28..2b65466540306feb0694abdc7cd801369cb9c9f0 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -71,11 +71,11 @@ struct drm_bridge_funcs {
*
* RETURNS:
*
* Zero on success, error code on failure.
*/
- int (*attach)(struct drm_bridge *bridge,
+ int (*attach)(struct drm_bridge *bridge, struct drm_encoder *encoder,
enum drm_bridge_attach_flags flags);
/**
* @detach:
*
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 02/16] drm/bridge: Provide a helper to retrieve current bridge state
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 03/16] drm/tests: Add kunit tests for bridges Maxime Ripard
` (13 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The current bridge state is accessible from the drm_bridge structure,
but since it's fairly indirect it's not easy to figure out.
Provide a helper to retrieve it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
include/drm/drm_bridge.h | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 2b65466540306feb0694abdc7cd801369cb9c9f0..6fb1da7c195e99143a67a999d16fe361c1e3f4ab 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -955,10 +955,42 @@ static inline struct drm_bridge *of_drm_find_bridge(struct device_node *np)
{
return NULL;
}
#endif
+/**
+ * drm_bridge_get_current_state() - Get the current bridge state
+ * @bridge: bridge object
+ *
+ * This function must be called with the modeset lock held.
+ *
+ * RETURNS:
+ *
+ * The current bridge state, or NULL if there is none.
+ */
+static inline struct drm_bridge_state *
+drm_bridge_get_current_state(struct drm_bridge *bridge)
+{
+ if (!bridge)
+ return NULL;
+
+ /*
+ * Only atomic bridges will have bridge->base initialized by
+ * drm_atomic_private_obj_init(), so we need to make sure we're
+ * working with one before we try to use the lock.
+ */
+ if (!bridge->funcs || !bridge->funcs->atomic_reset)
+ return NULL;
+
+ drm_modeset_lock_assert_held(&bridge->base.lock);
+
+ if (!bridge->base.state)
+ return NULL;
+
+ return drm_priv_to_bridge_state(bridge->base.state);
+}
+
/**
* drm_bridge_get_next_bridge() - Get the next bridge in the chain
* @bridge: bridge object
*
* RETURNS:
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 03/16] drm/tests: Add kunit tests for bridges
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 02/16] drm/bridge: Provide a helper to retrieve current bridge state Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
` (12 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
None of the drm_bridge function have kunit tests so far. Let's change
that, starting with drm_bridge_get_current_state().
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/Kconfig | 1 +
drivers/gpu/drm/tests/Makefile | 1 +
drivers/gpu/drm/tests/drm_bridge_test.c | 210 ++++++++++++++++++++++++++++++++
3 files changed, 212 insertions(+)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index e5b59de28216385f3783373e636d193d38d02646..9b406123132912f0578e9c8288d4c80e65f75f67 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -72,10 +72,11 @@ config DRM_KUNIT_TEST_HELPERS
KUnit Helpers for KMS drivers.
config DRM_KUNIT_TEST
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
depends on DRM && KUNIT && MMU
+ select DRM_BRIDGE_CONNECTOR
select DRM_BUDDY
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_HDMI_STATE_HELPER
select DRM_DISPLAY_HELPER
select DRM_EXEC
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 0109bcf7faa54993cce337f522eae78f0fa6ffcb..6691c577d2d4581a4185bac2ce89a6b14b339b35 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -3,10 +3,11 @@
obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
drm_kunit_helpers.o
obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_atomic_state_test.o \
+ drm_bridge_test.o \
drm_buddy_test.o \
drm_cmdline_parser_test.o \
drm_connector_test.o \
drm_damage_helper_test.o \
drm_dp_mst_helper_test.o \
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c0a05c459d957c3f9d281957f002f6bd36cce367
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -0,0 +1,210 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_bridge functions
+ */
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_kunit_helpers.h>
+
+#include <kunit/test.h>
+
+struct drm_bridge_init_priv {
+ struct drm_device drm;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder encoder;
+ struct drm_bridge bridge;
+ struct drm_connector *connector;
+};
+
+static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
+};
+
+static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+};
+
+KUNIT_DEFINE_ACTION_WRAPPER(drm_bridge_remove_wrapper,
+ drm_bridge_remove,
+ struct drm_bridge *);
+
+static int drm_kunit_bridge_add(struct kunit *test,
+ struct drm_bridge *bridge)
+{
+ drm_bridge_add(bridge);
+
+ return kunit_add_action_or_reset(test,
+ drm_bridge_remove_wrapper,
+ bridge);
+}
+
+static struct drm_bridge_init_priv *
+drm_test_bridge_init(struct kunit *test, const struct drm_bridge_funcs *funcs)
+{
+ struct drm_bridge_init_priv *priv;
+ struct drm_encoder *enc;
+ struct drm_bridge *bridge;
+ struct drm_device *drm;
+ struct device *dev;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+
+ priv = drm_kunit_helper_alloc_drm_device(test, dev,
+ struct drm_bridge_init_priv, drm,
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ if (IS_ERR(priv))
+ return ERR_CAST(priv);
+
+ drm = &priv->drm;
+ priv->plane = drm_kunit_helper_create_primary_plane(test, drm,
+ NULL,
+ NULL,
+ NULL, 0,
+ NULL);
+ if (IS_ERR(priv->plane))
+ return ERR_CAST(priv->plane);
+
+ priv->crtc = drm_kunit_helper_create_crtc(test, drm,
+ priv->plane, NULL,
+ NULL,
+ NULL);
+ if (IS_ERR(priv->crtc))
+ return ERR_CAST(priv->crtc);
+
+ enc = &priv->encoder;
+ ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ enc->possible_crtcs = drm_crtc_mask(priv->crtc);
+
+ bridge = &priv->bridge;
+ bridge->type = DRM_MODE_CONNECTOR_VIRTUAL;
+ bridge->funcs = funcs;
+
+ ret = drm_kunit_bridge_add(test, bridge);
+ if (ret)
+ return ERR_PTR(ret);
+
+ ret = drm_bridge_attach(enc, bridge, NULL, 0);
+ if (ret)
+ return ERR_PTR(ret);
+
+ priv->connector = drm_bridge_connector_init(drm, enc);
+ if (IS_ERR(priv->connector))
+ return ERR_CAST(priv->connector);
+
+ drm_connector_attach_encoder(priv->connector, enc);
+
+ drm_mode_config_reset(drm);
+
+ return priv;
+}
+
+/*
+ * Test that drm_bridge_get_current_state() returns the last committed
+ * state for an atomic bridge.
+ */
+static void drm_test_drm_bridge_get_current_state_atomic(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_init_priv *priv;
+ struct drm_bridge_state *curr_bridge_state;
+ struct drm_bridge_state *bridge_state;
+ struct drm_atomic_state *state;
+ struct drm_bridge *bridge;
+ struct drm_device *drm;
+ int ret;
+
+ priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &priv->drm;
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+retry_commit:
+ bridge = &priv->bridge;
+ bridge_state = drm_atomic_get_bridge_state(state, bridge);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bridge_state);
+
+ ret = drm_atomic_commit(state);
+ if (ret == -EDEADLK) {
+ drm_atomic_state_clear(state);
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_state:
+ ret = drm_modeset_lock(&bridge->base.lock, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_state;
+ }
+
+ curr_bridge_state = drm_bridge_get_current_state(bridge);
+ KUNIT_EXPECT_PTR_EQ(test, curr_bridge_state, bridge_state);
+
+ drm_modeset_unlock(&bridge->base.lock);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+/*
+ * Test that drm_bridge_get_current_state() returns NULL for a
+ * non-atomic bridge.
+ */
+static void drm_test_drm_bridge_get_current_state_legacy(struct kunit *test)
+{
+ struct drm_bridge_init_priv *priv;
+ struct drm_bridge *bridge;
+
+ priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ /*
+ * NOTE: Strictly speaking, we should take the bridge->base.lock
+ * before calling that function. However, bridge->base is only
+ * initialized if the bridge is atomic, while we explicitly
+ * initialize one that isn't there.
+ *
+ * In order to avoid unnecessary warnings, let's skip the
+ * locking. The function would return NULL in all cases anyway,
+ * so we don't really have any concurrency to worry about.
+ */
+ bridge = &priv->bridge;
+ KUNIT_EXPECT_NULL(test, drm_bridge_get_current_state(bridge));
+}
+
+static struct kunit_case drm_bridge_get_current_state_tests[] = {
+ KUNIT_CASE(drm_test_drm_bridge_get_current_state_atomic),
+ KUNIT_CASE(drm_test_drm_bridge_get_current_state_legacy),
+ { }
+};
+
+
+static struct kunit_suite drm_bridge_get_current_state_test_suite = {
+ .name = "drm_test_bridge_get_current_state",
+ .test_cases = drm_bridge_get_current_state_tests,
+};
+
+kunit_test_suite(drm_bridge_get_current_state_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
+MODULE_LICENSE("GPL");
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (2 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 03/16] drm/tests: Add kunit tests for bridges Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-05 11:55 ` Andy Yan
` (2 more replies)
2025-03-04 11:10 ` [PATCH v5 05/16] drm/tests: helpers: Create new helper to enable output Maxime Ripard
` (11 subsequent siblings)
15 siblings, 3 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov, Simona Vetter
With the bridges switching over to drm_bridge_connector, the direct
association between a bridge driver and its connector was lost.
This is mitigated for atomic bridge drivers by the fact you can access
the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
This was also made easier by providing drm_atomic_state directly to all
atomic hooks bridges can implement.
However, bridge drivers don't have a way to access drm_atomic_state
outside of the modeset path, like from the hotplug interrupt path or any
interrupt handler.
Let's introduce a function to retrieve the connector currently assigned
to an encoder, without using drm_atomic_state, to make these drivers'
life easier.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_atomic.h | 3 +++
2 files changed, 48 insertions(+)
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
return NULL;
}
EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
+/**
+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
+ * @encoder: The encoder to find the connector of
+ * @ctx: Modeset locking context
+ *
+ * This function finds and returns the connector currently assigned to
+ * an @encoder.
+ *
+ * Returns:
+ * The connector connected to @encoder, or an error pointer otherwise.
+ * When the error is EDEADLK, a deadlock has been detected and the
+ * sequence must be restarted.
+ */
+struct drm_connector *
+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector_list_iter conn_iter;
+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
+ struct drm_connector *connector;
+ struct drm_device *dev = encoder->dev;
+ int ret;
+
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_connector_list_iter_begin(dev, &conn_iter);
+ drm_for_each_connector_iter(connector, &conn_iter) {
+ if (!connector->state)
+ continue;
+
+ if (encoder == connector->state->best_encoder) {
+ out_connector = connector;
+ break;
+ }
+ }
+ drm_connector_list_iter_end(&conn_iter);
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+ return out_connector;
+}
+EXPORT_SYMBOL(drm_atomic_get_connector_for_encoder);
+
+
/**
* drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
* @state: Atomic state
* @encoder: The encoder to fetch the crtc state for
*
diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
index 4c673f0698fef6b60f77db980378d5e88e0e250e..38636a593c9d98cadda85ccd67326cb152f0dd27 100644
--- a/include/drm/drm_atomic.h
+++ b/include/drm/drm_atomic.h
@@ -623,10 +623,13 @@ struct drm_connector *
drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder);
struct drm_connector *
drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
struct drm_encoder *encoder);
+struct drm_connector *
+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
+ struct drm_modeset_acquire_ctx *ctx);
struct drm_crtc *
drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
struct drm_encoder *encoder);
struct drm_crtc *
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 05/16] drm/tests: helpers: Create new helper to enable output
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (3 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 06/16] drm/tests: hdmi_state_helpers: Switch to new helper Maxime Ripard
` (10 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
We'll need the HDMI state tests light_up_connector() function in more
tests, so let's promote it to a helper.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 61 +++++++++++++++++++++++++++++++
include/drm/drm_kunit_helpers.h | 8 ++++
2 files changed, 69 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index a4eb68f0decca15988105b9d58266e3871934a8b..14ad8f0a0af18410a7129ec34635678a8120d3cb 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -1,9 +1,10 @@
// SPDX-License-Identifier: GPL-2.0
#include <drm/drm_atomic.h>
#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_uapi.h>
#include <drm/drm_drv.h>
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
@@ -269,10 +270,70 @@ drm_kunit_helper_create_crtc(struct kunit *test,
return crtc;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_create_crtc);
+/**
+ * drm_kunit_helper_enable_crtc_connector - Enables a CRTC -> Connector output
+ * @test: The test context object
+ * @drm: The device to alloc the plane for
+ * @crtc: The CRTC to enable
+ * @connector: The Connector to enable
+ * @mode: The display mode to configure the CRTC with
+ * @ctx: Locking context
+ *
+ * This function creates an atomic update to enable the route from @crtc
+ * to @connector, with the given @mode.
+ *
+ * Returns:
+ *
+ * A pointer to the new CRTC, or an ERR_PTR() otherwise. If the error
+ * returned is EDEADLK, the entire atomic sequence must be restarted.
+ */
+int drm_kunit_helper_enable_crtc_connector(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_atomic_state *state;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
+
+ conn_state = drm_atomic_get_connector_state(state, connector);
+ if (IS_ERR(conn_state))
+ return PTR_ERR(conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
+ if (ret)
+ return ret;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
+ if (ret)
+ return ret;
+
+ crtc_state->enable = true;
+ crtc_state->active = true;
+
+ ret = drm_atomic_commit(state);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_enable_crtc_connector);
+
static void kunit_action_drm_mode_destroy(void *ptr)
{
struct drm_display_mode *mode = ptr;
drm_mode_destroy(NULL, mode);
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index 11d59ce0bac0bbec07ae5f07ed9710cf01d73f09..1cda7281f30029e649c62fc0fd9d9ae6889d43ac 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -7,10 +7,11 @@
#include <linux/device.h>
#include <kunit/test.h>
+struct drm_connector;
struct drm_crtc_funcs;
struct drm_crtc_helper_funcs;
struct drm_device;
struct drm_plane_funcs;
struct drm_plane_helper_funcs;
@@ -116,10 +117,17 @@ drm_kunit_helper_create_crtc(struct kunit *test,
struct drm_plane *primary,
struct drm_plane *cursor,
const struct drm_crtc_funcs *funcs,
const struct drm_crtc_helper_funcs *helper_funcs);
+int drm_kunit_helper_enable_crtc_connector(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ struct drm_connector *connector,
+ const struct drm_display_mode *mode,
+ struct drm_modeset_acquire_ctx *ctx);
+
struct drm_display_mode *
drm_kunit_display_mode_from_cea_vic(struct kunit *test, struct drm_device *dev,
u8 video_code);
#endif // DRM_KUNIT_HELPERS_H_
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 06/16] drm/tests: hdmi_state_helpers: Switch to new helper
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (4 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 05/16] drm/tests: helpers: Create new helper to enable output Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 07/16] drm/tests: Create tests for drm_atomic Maxime Ripard
` (9 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
We introduced a new helper that supersedes the light_up_connector()
function in drm_hdmi_state_helper_test, so let's convert all our tests
to it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c | 158 ++++++++++++---------
1 file changed, 92 insertions(+), 66 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
index e97efd3af9ed18e6cf8ee66b4923dfc805b34e19..7ffd666753b10bc991894e238206a3c5328d0e23 100644
--- a/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_hdmi_state_helper_test.c
@@ -53,53 +53,10 @@ static struct drm_display_mode *find_preferred_mode(struct drm_connector *connec
mutex_unlock(&drm->mode_config.mutex);
return preferred;
}
-static int light_up_connector(struct kunit *test,
- struct drm_device *drm,
- struct drm_crtc *crtc,
- struct drm_connector *connector,
- struct drm_display_mode *mode,
- struct drm_modeset_acquire_ctx *ctx)
-{
- struct drm_atomic_state *state;
- struct drm_connector_state *conn_state;
- struct drm_crtc_state *crtc_state;
- int ret;
-
- state = drm_kunit_helper_atomic_state_alloc(test, drm, ctx);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
-
-retry:
- conn_state = drm_atomic_get_connector_state(state, connector);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
-
- ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
- if (ret == -EDEADLK) {
- drm_atomic_state_clear(state);
- ret = drm_modeset_backoff(ctx);
- if (!ret)
- goto retry;
- }
- KUNIT_EXPECT_EQ(test, ret, 0);
-
- crtc_state = drm_atomic_get_crtc_state(state, crtc);
- KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
-
- ret = drm_atomic_set_mode_for_crtc(crtc_state, mode);
- KUNIT_EXPECT_EQ(test, ret, 0);
-
- crtc_state->enable = true;
- crtc_state->active = true;
-
- ret = drm_atomic_commit(state);
- KUNIT_ASSERT_EQ(test, ret, 0);
-
- return 0;
-}
-
static int set_connector_edid(struct kunit *test, struct drm_connector *connector,
const char *edid, size_t edid_len)
{
struct drm_atomic_helper_connector_hdmi_priv *priv =
connector_to_priv(connector);
@@ -296,11 +253,14 @@ static void drm_test_check_broadcast_rgb_crtc_mode_changed(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -362,11 +322,14 @@ static void drm_test_check_broadcast_rgb_crtc_mode_not_changed(struct kunit *tes
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -430,11 +393,14 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -487,11 +453,14 @@ static void drm_test_check_broadcast_rgb_auto_cea_mode_vic_1(struct kunit *test)
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
- ret = light_up_connector(test, drm, crtc, conn, mode, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ mode,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -545,11 +514,14 @@ static void drm_test_check_broadcast_rgb_full_cea_mode(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -604,11 +576,14 @@ static void drm_test_check_broadcast_rgb_full_cea_mode_vic_1(struct kunit *test)
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
- ret = light_up_connector(test, drm, crtc, conn, mode, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ mode,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -664,11 +639,14 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_NE(test, drm_match_cea_mode(preferred), 1);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -723,11 +701,14 @@ static void drm_test_check_broadcast_rgb_limited_cea_mode_vic_1(struct kunit *te
mode = drm_kunit_display_mode_from_cea_vic(test, drm, 1);
KUNIT_ASSERT_NOT_NULL(test, mode);
crtc = priv->crtc;
- ret = light_up_connector(test, drm, crtc, conn, mode, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ mode,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -787,11 +768,14 @@ static void drm_test_check_output_bpc_crtc_mode_changed(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -863,11 +847,14 @@ static void drm_test_check_output_bpc_crtc_mode_not_changed(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
@@ -939,11 +926,14 @@ static void drm_test_check_output_bpc_dvi(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -986,11 +976,14 @@ static void drm_test_check_tmds_char_rate_rgb_8bpc(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1035,11 +1028,14 @@ static void drm_test_check_tmds_char_rate_rgb_10bpc(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1084,11 +1080,14 @@ static void drm_test_check_tmds_char_rate_rgb_12bpc(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, preferred);
KUNIT_ASSERT_FALSE(test, preferred->flags & DRM_MODE_FLAG_DBLCLK);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1132,11 +1131,14 @@ static void drm_test_check_hdmi_funcs_reject_rate(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
/* You shouldn't be doing that at home. */
conn->hdmi.funcs = &reject_connector_hdmi_funcs;
@@ -1206,11 +1208,14 @@ static void drm_test_check_max_tmds_rate_bpc_fallback(struct kunit *test)
rate = drm_hdmi_compute_mode_clock(preferred, 10, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1280,11 +1285,14 @@ static void drm_test_check_max_tmds_rate_format_fallback(struct kunit *test)
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1345,11 +1353,14 @@ static void drm_test_check_output_bpc_format_vic_1(struct kunit *test)
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
crtc = priv->crtc;
- ret = light_up_connector(test, drm, crtc, conn, mode, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ mode,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1412,11 +1423,14 @@ static void drm_test_check_output_bpc_format_driver_rgb_only(struct kunit *test)
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1481,11 +1495,14 @@ static void drm_test_check_output_bpc_format_display_rgb_only(struct kunit *test
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_YUV422);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1541,11 +1558,14 @@ static void drm_test_check_output_bpc_format_driver_8bpc_only(struct kunit *test
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1603,11 +1623,14 @@ static void drm_test_check_output_bpc_format_display_8bpc_only(struct kunit *tes
rate = drm_hdmi_compute_mode_clock(preferred, 12, HDMI_COLORSPACE_RGB);
KUNIT_ASSERT_LT(test, rate, info->max_tmds_clock * 1000);
drm_modeset_acquire_init(&ctx, 0);
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_EXPECT_EQ(test, ret, 0);
conn_state = conn->state;
KUNIT_ASSERT_NOT_NULL(test, conn_state);
@@ -1643,11 +1666,14 @@ static void drm_test_check_disable_connector(struct kunit *test)
preferred = find_preferred_mode(conn);
KUNIT_ASSERT_NOT_NULL(test, preferred);
drm = &priv->drm;
crtc = priv->crtc;
- ret = light_up_connector(test, drm, crtc, conn, preferred, &ctx);
+ ret = drm_kunit_helper_enable_crtc_connector(test, drm,
+ crtc, conn,
+ preferred,
+ &ctx);
KUNIT_ASSERT_EQ(test, ret, 0);
state = drm_kunit_helper_atomic_state_alloc(test, drm, &ctx);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 07/16] drm/tests: Create tests for drm_atomic
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (5 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 06/16] drm/tests: hdmi_state_helpers: Switch to new helper Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline Maxime Ripard
` (8 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
We don't have a set of kunit tests for the functions under drm_atomic.h.
Let's use the introduction of drm_atomic_get_connector_for_encoder() to
create some tests for it and thus create that set.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tests/Makefile | 1 +
drivers/gpu/drm/tests/drm_atomic_test.c | 153 ++++++++++++++++++++++++++++++++
2 files changed, 154 insertions(+)
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 6691c577d2d4581a4185bac2ce89a6b14b339b35..3afd6587df0831a0d10e91ff0a584af6ba1813e4 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -2,10 +2,11 @@
obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
drm_kunit_helpers.o
obj-$(CONFIG_DRM_KUNIT_TEST) += \
+ drm_atomic_test.o \
drm_atomic_state_test.o \
drm_bridge_test.o \
drm_buddy_test.o \
drm_cmdline_parser_test.o \
drm_connector_test.o \
diff --git a/drivers/gpu/drm/tests/drm_atomic_test.c b/drivers/gpu/drm/tests/drm_atomic_test.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea91bec6569e688ad33149d8ee6ecc3562b61254
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_atomic_test.c
@@ -0,0 +1,153 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for drm_atomic functions
+ */
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include <kunit/test.h>
+
+struct drm_atomic_test_priv {
+ struct drm_device drm;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct drm_encoder encoder;
+ struct drm_connector connector;
+};
+
+static const struct drm_connector_helper_funcs drm_atomic_init_connector_helper_funcs = {
+};
+
+static const struct drm_connector_funcs drm_atomic_init_connector_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .reset = drm_atomic_helper_connector_reset,
+};
+
+static struct drm_atomic_test_priv *create_device(struct kunit *test)
+{
+ struct drm_atomic_test_priv *priv;
+ struct drm_connector *connector;
+ struct drm_encoder *enc;
+ struct drm_device *drm;
+ struct drm_plane *plane;
+ struct drm_crtc *crtc;
+ struct device *dev;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ if (IS_ERR(dev))
+ return ERR_CAST(dev);
+
+ priv = drm_kunit_helper_alloc_drm_device(test, dev,
+ struct drm_atomic_test_priv, drm,
+ DRIVER_MODESET | DRIVER_ATOMIC);
+ if (IS_ERR(priv))
+ return ERR_CAST(priv);
+
+ drm = &priv->drm;
+ plane = drm_kunit_helper_create_primary_plane(test, drm,
+ NULL,
+ NULL,
+ NULL, 0,
+ NULL);
+ if (IS_ERR(plane))
+ return ERR_CAST(plane);
+ priv->plane = plane;
+
+ crtc = drm_kunit_helper_create_crtc(test, drm,
+ plane, NULL,
+ NULL,
+ NULL);
+ if (IS_ERR(crtc))
+ return ERR_CAST(crtc);
+ priv->crtc = crtc;
+
+ enc = &priv->encoder;
+ ret = drmm_encoder_init(drm, enc, NULL, DRM_MODE_ENCODER_TMDS, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ enc->possible_crtcs = drm_crtc_mask(crtc);
+
+ connector = &priv->connector;
+ ret = drmm_connector_init(drm, connector,
+ &drm_atomic_init_connector_funcs,
+ DRM_MODE_CONNECTOR_VIRTUAL,
+ NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ drm_connector_helper_add(connector, &drm_atomic_init_connector_helper_funcs);
+
+ drm_connector_attach_encoder(connector, enc);
+
+ drm_mode_config_reset(drm);
+
+ return priv;
+}
+
+static void drm_test_drm_atomic_get_connector_for_encoder(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_test_priv *priv;
+ struct drm_display_mode *mode;
+ struct drm_connector *curr_connector;
+ int ret;
+
+ priv = create_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_enable:
+ ret = drm_kunit_helper_enable_crtc_connector(test, &priv->drm,
+ priv->crtc, &priv->connector,
+ mode, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_enable;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_conn:
+ curr_connector = drm_atomic_get_connector_for_encoder(&priv->encoder,
+ &ctx);
+ if (PTR_ERR(curr_connector) == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_conn;
+ }
+ KUNIT_EXPECT_PTR_EQ(test, curr_connector, &priv->connector);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+}
+
+static struct kunit_case drm_atomic_get_connector_for_encoder_tests[] = {
+ KUNIT_CASE(drm_test_drm_atomic_get_connector_for_encoder),
+ { }
+};
+
+
+static struct kunit_suite drm_atomic_get_connector_for_encoder_test_suite = {
+ .name = "drm_test_atomic_get_connector_for_encoder",
+ .test_cases = drm_atomic_get_connector_for_encoder_tests,
+};
+
+kunit_test_suite(drm_atomic_get_connector_for_encoder_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
+MODULE_DESCRIPTION("Kunit test for drm_atomic functions");
+MODULE_LICENSE("GPL");
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (6 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 07/16] drm/tests: Create tests for drm_atomic Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-06 8:12 ` Herve Codina
2025-03-06 15:46 ` Simona Vetter
2025-03-04 11:10 ` [PATCH v5 09/16] drm/tests: bridge: Provide tests for drm_bridge_helper_reset_crtc Maxime Ripard
` (7 subsequent siblings)
15 siblings, 2 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Simona Vetter
Let's provide an helper to make it easier for bridge drivers to
power-cycle their bridge.
In order to avoid a circular dependency between that new helper and
drm_atomic_helper_reset_crtc(), this new helper will be in a
drm_bridge_helper.c file to follow the pattern we have for other
objects.
Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/Makefile | 1 +
drivers/gpu/drm/drm_bridge_helper.c | 55 +++++++++++++++++++++++++++++++++++++
include/drm/drm_bridge_helper.h | 12 ++++++++
3 files changed, 68 insertions(+)
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 4cd054188faf0b3dec442efd99ae52604541bce1..5a332f7d3ecccb6e5e1fb9fb811eab7aa5a84a21 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -131,10 +131,11 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
#
drm_kms_helper-y := \
drm_atomic_helper.o \
drm_atomic_state_helper.o \
+ drm_bridge_helper.o \
drm_crtc_helper.o \
drm_damage_helper.o \
drm_flip_work.o \
drm_format_helper.o \
drm_gem_atomic_helper.o \
diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
new file mode 100644
index 0000000000000000000000000000000000000000..521df9d5dcb3fef842a95cdb2865a8b8d09b0fbe
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge_helper.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_helper.h>
+#include <drm/drm_modeset_lock.h>
+
+/**
+ * drm_bridge_helper_reset_crtc - Reset the pipeline feeding a bridge
+ * @bridge: DRM bridge to reset
+ * @ctx: lock acquisition context
+ *
+ * Reset a @bridge pipeline. It will power-cycle all active components
+ * between the CRTC and connector that bridge is connected to.
+ *
+ * Returns:
+ *
+ * 0 on success or a negative error code on failure. If the error
+ * returned is EDEADLK, the whole atomic sequence must be restarted.
+ */
+int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
+ struct drm_modeset_acquire_ctx *ctx)
+{
+ struct drm_connector *connector;
+ struct drm_encoder *encoder = bridge->encoder;
+ struct drm_device *dev = encoder->dev;
+ struct drm_crtc *crtc;
+ int ret;
+
+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
+ if (ret)
+ return ret;
+
+ connector = drm_atomic_get_connector_for_encoder(encoder, ctx);
+ if (IS_ERR(connector)) {
+ ret = PTR_ERR(connector);
+ goto out;
+ }
+
+ if (!connector->state) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ crtc = connector->state->crtc;
+ ret = drm_atomic_helper_reset_crtc(crtc, ctx);
+ if (ret)
+ goto out;
+
+out:
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(drm_bridge_helper_reset_crtc);
diff --git a/include/drm/drm_bridge_helper.h b/include/drm/drm_bridge_helper.h
new file mode 100644
index 0000000000000000000000000000000000000000..6c35b479ec2a84aa43283351a6f18e49a9f9c177
--- /dev/null
+++ b/include/drm/drm_bridge_helper.h
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifndef __DRM_BRIDGE_HELPER_H_
+#define __DRM_BRIDGE_HELPER_H_
+
+struct drm_bridge;
+struct drm_modeset_acquire_ctx;
+
+int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
+ struct drm_modeset_acquire_ctx *ctx);
+
+#endif // __DRM_BRIDGE_HELPER_H_
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 09/16] drm/tests: bridge: Provide tests for drm_bridge_helper_reset_crtc
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (7 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc Maxime Ripard
` (6 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
Let's provide a bunch of kunit tests to make sure
drm_bridge_helper_reset_crtc() works as expected.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/tests/drm_bridge_test.c | 209 +++++++++++++++++++++++++++++++-
1 file changed, 208 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tests/drm_bridge_test.c b/drivers/gpu/drm/tests/drm_bridge_test.c
index c0a05c459d957c3f9d281957f002f6bd36cce367..ff88ec2e911c9cc9a718483f09d4c764f45f991a 100644
--- a/drivers/gpu/drm/tests/drm_bridge_test.c
+++ b/drivers/gpu/drm/tests/drm_bridge_test.c
@@ -3,10 +3,11 @@
* Kunit test for drm_bridge functions
*/
#include <drm/drm_atomic_state_helper.h>
#include <drm/drm_bridge.h>
#include <drm/drm_bridge_connector.h>
+#include <drm/drm_bridge_helper.h>
#include <drm/drm_kunit_helpers.h>
#include <kunit/test.h>
struct drm_bridge_init_priv {
@@ -14,16 +15,56 @@ struct drm_bridge_init_priv {
struct drm_plane *plane;
struct drm_crtc *crtc;
struct drm_encoder encoder;
struct drm_bridge bridge;
struct drm_connector *connector;
+ unsigned int enable_count;
+ unsigned int disable_count;
};
+static void drm_test_bridge_enable(struct drm_bridge *bridge)
+{
+ struct drm_bridge_init_priv *priv =
+ container_of(bridge, struct drm_bridge_init_priv, bridge);
+
+ priv->enable_count++;
+}
+
+static void drm_test_bridge_disable(struct drm_bridge *bridge)
+{
+ struct drm_bridge_init_priv *priv =
+ container_of(bridge, struct drm_bridge_init_priv, bridge);
+
+ priv->disable_count++;
+}
+
static const struct drm_bridge_funcs drm_test_bridge_legacy_funcs = {
+ .enable = drm_test_bridge_enable,
+ .disable = drm_test_bridge_disable,
};
+static void drm_test_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
+{
+ struct drm_bridge_init_priv *priv =
+ container_of(bridge, struct drm_bridge_init_priv, bridge);
+
+ priv->enable_count++;
+}
+
+static void drm_test_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
+{
+ struct drm_bridge_init_priv *priv =
+ container_of(bridge, struct drm_bridge_init_priv, bridge);
+
+ priv->disable_count++;
+}
+
static const struct drm_bridge_funcs drm_test_bridge_atomic_funcs = {
+ .atomic_enable = drm_test_bridge_atomic_enable,
+ .atomic_disable = drm_test_bridge_atomic_disable,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
};
@@ -201,10 +242,176 @@ static struct kunit_case drm_bridge_get_current_state_tests[] = {
static struct kunit_suite drm_bridge_get_current_state_test_suite = {
.name = "drm_test_bridge_get_current_state",
.test_cases = drm_bridge_get_current_state_tests,
};
-kunit_test_suite(drm_bridge_get_current_state_test_suite);
+/*
+ * Test that an atomic bridge is properly power-cycled when calling
+ * drm_bridge_helper_reset_crtc().
+ */
+static void drm_test_drm_bridge_helper_reset_crtc_atomic(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_init_priv *priv;
+ struct drm_display_mode *mode;
+ struct drm_bridge *bridge;
+ int ret;
+
+ priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_commit:
+ ret = drm_kunit_helper_enable_crtc_connector(test,
+ &priv->drm, priv->crtc,
+ priv->connector,
+ mode,
+ &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ bridge = &priv->bridge;
+ KUNIT_ASSERT_EQ(test, priv->enable_count, 1);
+ KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_reset:
+ ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_reset;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ KUNIT_EXPECT_EQ(test, priv->enable_count, 2);
+ KUNIT_EXPECT_EQ(test, priv->disable_count, 1);
+}
+
+/*
+ * Test that calling drm_bridge_helper_reset_crtc() on a disabled atomic
+ * bridge will fail and not call the enable / disable callbacks
+ */
+static void drm_test_drm_bridge_helper_reset_crtc_atomic_disabled(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_init_priv *priv;
+ struct drm_display_mode *mode;
+ struct drm_bridge *bridge;
+ int ret;
+
+ priv = drm_test_bridge_init(test, &drm_test_bridge_atomic_funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ bridge = &priv->bridge;
+ KUNIT_ASSERT_EQ(test, priv->enable_count, 0);
+ KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_reset:
+ ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_reset;
+ }
+ KUNIT_EXPECT_LT(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ KUNIT_EXPECT_EQ(test, priv->enable_count, 0);
+ KUNIT_EXPECT_EQ(test, priv->disable_count, 0);
+}
+
+/*
+ * Test that a non-atomic bridge is properly power-cycled when calling
+ * drm_bridge_helper_reset_crtc().
+ */
+static void drm_test_drm_bridge_helper_reset_crtc_legacy(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_bridge_init_priv *priv;
+ struct drm_display_mode *mode;
+ struct drm_bridge *bridge;
+ int ret;
+
+ priv = drm_test_bridge_init(test, &drm_test_bridge_legacy_funcs);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+
+ mode = drm_kunit_display_mode_from_cea_vic(test, &priv->drm, 16);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mode);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_commit:
+ ret = drm_kunit_helper_enable_crtc_connector(test,
+ &priv->drm, priv->crtc,
+ priv->connector,
+ mode,
+ &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_commit;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ bridge = &priv->bridge;
+ KUNIT_ASSERT_EQ(test, priv->enable_count, 1);
+ KUNIT_ASSERT_EQ(test, priv->disable_count, 0);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+retry_reset:
+ ret = drm_bridge_helper_reset_crtc(bridge, &ctx);
+ if (ret == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry_reset;
+ }
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ KUNIT_EXPECT_EQ(test, priv->enable_count, 2);
+ KUNIT_EXPECT_EQ(test, priv->disable_count, 1);
+}
+
+static struct kunit_case drm_bridge_helper_reset_crtc_tests[] = {
+ KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic),
+ KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_atomic_disabled),
+ KUNIT_CASE(drm_test_drm_bridge_helper_reset_crtc_legacy),
+ { }
+};
+
+static struct kunit_suite drm_bridge_helper_reset_crtc_test_suite = {
+ .name = "drm_test_bridge_helper_reset_crtc",
+ .test_cases = drm_bridge_helper_reset_crtc_tests,
+};
+
+kunit_test_suites(
+ &drm_bridge_get_current_state_test_suite,
+ &drm_bridge_helper_reset_crtc_test_suite,
+);
MODULE_AUTHOR("Maxime Ripard <mripard@kernel.org>");
MODULE_DESCRIPTION("Kunit test for drm_bridge functions");
MODULE_LICENSE("GPL");
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (8 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 09/16] drm/tests: bridge: Provide tests for drm_bridge_helper_reset_crtc Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-06 8:09 ` Herve Codina
2025-03-04 11:10 ` [PATCH v5 11/16] drm/bridge: Introduce drm_bridge_is_atomic() helper Maxime Ripard
` (5 subsequent siblings)
15 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
Now that we have a helper for bridge drivers to call to reset the output
pipeline, let's use it.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/ti-sn65dsi83.c | 28 +++++++++++-----------------
1 file changed, 11 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi83.c b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
index 7122a3ebd88399ed32420fcaf9f1f9384d031d2d..53cc4cfb0c884f6a410e3df2c4df4572f89c0768 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi83.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi83.c
@@ -38,11 +38,11 @@
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_bridge.h>
-#include <drm/drm_drv.h> /* DRM_MODESET_LOCK_ALL_BEGIN() needs drm_drv_uses_atomic_modeset() */
+#include <drm/drm_bridge_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_of.h>
#include <drm/drm_print.h>
#include <drm/drm_probe_helper.h>
@@ -369,11 +369,10 @@ static u8 sn65dsi83_get_dsi_div(struct sn65dsi83 *ctx)
return dsi_div - 1;
}
static int sn65dsi83_reset_pipe(struct sn65dsi83 *sn65dsi83)
{
- struct drm_device *dev = sn65dsi83->bridge.dev;
struct drm_modeset_acquire_ctx ctx;
int err;
/*
* Reset active outputs of the related CRTC.
@@ -384,30 +383,25 @@ static int sn65dsi83_reset_pipe(struct sn65dsi83 *sn65dsi83)
* bridge.
*
* Keep the lock during the whole operation to be atomic.
*/
- DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, 0, err);
-
- if (!sn65dsi83->bridge.encoder->crtc) {
- /*
- * No CRTC attached -> No CRTC active outputs to reset
- * This can happen when the SN65DSI83 is reset. Simply do
- * nothing without returning any errors.
- */
- err = 0;
- goto end;
- }
+ drm_modeset_acquire_init(&ctx, 0);
dev_warn(sn65dsi83->dev, "reset the pipe\n");
- err = drm_atomic_helper_reset_crtc(sn65dsi83->bridge.encoder->crtc, &ctx);
+retry:
+ err = drm_bridge_helper_reset_crtc(&sn65dsi83->bridge, &ctx);
+ if (err == -EDEADLK) {
+ drm_modeset_backoff(&ctx);
+ goto retry;
+ }
-end:
- DRM_MODESET_LOCK_ALL_END(dev, ctx, err);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
- return err;
+ return 0;
}
static void sn65dsi83_reset_work(struct work_struct *ws)
{
struct sn65dsi83 *ctx = container_of(ws, struct sn65dsi83, reset_work);
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 11/16] drm/bridge: Introduce drm_bridge_is_atomic() helper
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (9 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 12/16] drm/bridge: cdns-csi: Switch to atomic helpers Maxime Ripard
` (4 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
We test for whether the bridge is atomic in several places in the source
code, so let's consolidate them.
Suggested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/drm_bridge.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 8241c00e4506eceeb9bb4ba74a38d8f360c65d38..d2525d0b1324cc3a63e32f5bf6ca6c4f9034eb4e 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -278,10 +278,15 @@ drm_bridge_atomic_destroy_priv_state(struct drm_private_obj *obj,
static const struct drm_private_state_funcs drm_bridge_priv_state_funcs = {
.atomic_duplicate_state = drm_bridge_atomic_duplicate_priv_state,
.atomic_destroy_state = drm_bridge_atomic_destroy_priv_state,
};
+static bool drm_bridge_is_atomic(struct drm_bridge *bridge)
+{
+ return bridge->funcs->atomic_reset != NULL;
+}
+
/**
* drm_bridge_attach - attach the bridge to an encoder's chain
*
* @encoder: DRM encoder
* @bridge: bridge to attach
@@ -330,11 +335,11 @@ int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
ret = bridge->funcs->attach(bridge, encoder, flags);
if (ret < 0)
goto err_reset_bridge;
}
- if (bridge->funcs->atomic_reset) {
+ if (drm_bridge_is_atomic(bridge)) {
struct drm_bridge_state *state;
state = bridge->funcs->atomic_reset(bridge);
if (IS_ERR(state)) {
ret = PTR_ERR(state);
@@ -375,11 +380,11 @@ void drm_bridge_detach(struct drm_bridge *bridge)
return;
if (WARN_ON(!bridge->dev))
return;
- if (bridge->funcs->atomic_reset)
+ if (drm_bridge_is_atomic(bridge))
drm_atomic_private_obj_fini(&bridge->base);
if (bridge->funcs->detach)
bridge->funcs->detach(bridge);
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 12/16] drm/bridge: cdns-csi: Switch to atomic helpers
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (10 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 11/16] drm/bridge: Introduce drm_bridge_is_atomic() helper Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 13/16] drm/bridge: tc358775: Switch to atomic commit Maxime Ripard
` (3 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The Cadence DSI driver follows the drm_encoder->crtc pointer that is
deprecated and shouldn't be used by atomic drivers.
Fortunately, the atomic hooks provide the drm_atomic_state and we can
access our current CRTC from that, going from the bridge to its encoder,
to its connector, and to its CRTC.
Let's convert this bridge driver to atomic so we can get rid of the
drm_encoder->crtc dereference.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c | 31 ++++++++++++++++++--------
1 file changed, 22 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
index 8f54c034ac4f3e82c38607a0e52d4745654b571f..99d43944fb8fc685520b78732cd1181175ff7cc9 100644
--- a/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
+++ b/drivers/gpu/drm/bridge/cadence/cdns-dsi-core.c
@@ -654,11 +654,12 @@ cdns_dsi_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_BAD;
return MODE_OK;
}
-static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
u32 val;
@@ -674,11 +675,12 @@ static void cdns_dsi_bridge_disable(struct drm_bridge *bridge)
dsi->platform_ops->disable(dsi);
pm_runtime_put(dsi->base.dev);
}
-static void cdns_dsi_bridge_post_disable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
pm_runtime_put(dsi->base.dev);
@@ -751,17 +753,21 @@ static void cdns_dsi_init_link(struct cdns_dsi *dsi)
writel(val, dsi->regs + MCTL_MAIN_EN);
dsi->link_initialized = true;
}
-static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
struct cdns_dsi_output *output = &dsi->output;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
struct drm_display_mode *mode;
struct phy_configure_opts_mipi_dphy *phy_cfg = &output->phy_opts.mipi_dphy;
+ struct drm_connector *connector;
unsigned long tx_byte_period;
struct cdns_dsi_cfg dsi_cfg;
u32 tmp, reg_wakeup, div;
int nlanes;
@@ -769,11 +775,14 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
return;
if (dsi->platform_ops && dsi->platform_ops->enable)
dsi->platform_ops->enable(dsi);
- mode = &bridge->encoder->crtc->state->adjusted_mode;
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
nlanes = output->dev->lanes;
WARN_ON_ONCE(cdns_dsi_check_conf(dsi, mode, &dsi_cfg, false));
cdns_dsi_hs_init(dsi);
@@ -891,11 +900,12 @@ static void cdns_dsi_bridge_enable(struct drm_bridge *bridge)
tmp = readl(dsi->regs + MCTL_MAIN_EN) | IF_EN(input->id);
writel(tmp, dsi->regs + MCTL_MAIN_EN);
}
-static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge)
+static void cdns_dsi_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct cdns_dsi_input *input = bridge_to_cdns_dsi_input(bridge);
struct cdns_dsi *dsi = input_to_dsi(input);
if (WARN_ON(pm_runtime_get_sync(dsi->base.dev) < 0))
@@ -906,14 +916,17 @@ static void cdns_dsi_bridge_pre_enable(struct drm_bridge *bridge)
}
static const struct drm_bridge_funcs cdns_dsi_bridge_funcs = {
.attach = cdns_dsi_bridge_attach,
.mode_valid = cdns_dsi_bridge_mode_valid,
- .disable = cdns_dsi_bridge_disable,
- .pre_enable = cdns_dsi_bridge_pre_enable,
- .enable = cdns_dsi_bridge_enable,
- .post_disable = cdns_dsi_bridge_post_disable,
+ .atomic_disable = cdns_dsi_bridge_atomic_disable,
+ .atomic_pre_enable = cdns_dsi_bridge_atomic_pre_enable,
+ .atomic_enable = cdns_dsi_bridge_atomic_enable,
+ .atomic_post_disable = cdns_dsi_bridge_atomic_post_disable,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
};
static int cdns_dsi_attach(struct mipi_dsi_host *host,
struct mipi_dsi_device *dev)
{
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 13/16] drm/bridge: tc358775: Switch to atomic commit
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (11 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 12/16] drm/bridge: cdns-csi: Switch to atomic helpers Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable Maxime Ripard
` (2 subsequent siblings)
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The tc358775 driver follows the drm_encoder->crtc pointer that is
deprecated and shouldn't be used by atomic drivers.
Fortunately, the atomic hooks provide the drm_atomic_state and we can
access our current CRTC from that, going from the bridge to its encoder,
to its connector, and to its CRTC.
Let's convert this bridge driver to atomic so we can get rid of the
drm_encoder->crtc dereference.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/tc358775.c | 42 ++++++++++++++++++---------------------
1 file changed, 19 insertions(+), 23 deletions(-)
diff --git a/drivers/gpu/drm/bridge/tc358775.c b/drivers/gpu/drm/bridge/tc358775.c
index 13cd48e77d2d3f8dd646078fb7de95c420f29f73..1b10e6ee1724ffb4bb8946f86d2f18e53428381a 100644
--- a/drivers/gpu/drm/bridge/tc358775.c
+++ b/drivers/gpu/drm/bridge/tc358775.c
@@ -284,11 +284,12 @@ struct tc_data {
static inline struct tc_data *bridge_to_tc(struct drm_bridge *b)
{
return container_of(b, struct tc_data, bridge);
}
-static void tc_bridge_pre_enable(struct drm_bridge *bridge)
+static void tc_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc_data *tc = bridge_to_tc(bridge);
struct device *dev = &tc->dsi->dev;
int ret;
@@ -307,11 +308,12 @@ static void tc_bridge_pre_enable(struct drm_bridge *bridge)
gpiod_set_value(tc->reset_gpio, 0);
usleep_range(10, 20);
}
-static void tc_bridge_post_disable(struct drm_bridge *bridge)
+static void tc_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc_data *tc = bridge_to_tc(bridge);
struct device *dev = &tc->dsi->dev;
int ret;
@@ -366,34 +368,25 @@ static void d2l_write(struct i2c_client *i2c, u16 addr, u32 val)
if (ret < 0)
dev_err(&i2c->dev, "Error %d writing to subaddress 0x%x\n",
ret, addr);
}
-/* helper function to access bus_formats */
-static struct drm_connector *get_connector(struct drm_encoder *encoder)
-{
- struct drm_device *dev = encoder->dev;
- struct drm_connector *connector;
-
- list_for_each_entry(connector, &dev->mode_config.connector_list, head)
- if (connector->encoder == encoder)
- return connector;
-
- return NULL;
-}
-
-static void tc_bridge_enable(struct drm_bridge *bridge)
+static void tc_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc_data *tc = bridge_to_tc(bridge);
u32 hback_porch, hsync_len, hfront_porch, hactive, htime1, htime2;
u32 vback_porch, vsync_len, vfront_porch, vactive, vtime1, vtime2;
u32 val = 0;
u16 dsiclk, clkdiv, byteclk, t1, t2, t3, vsdelay;
- struct drm_display_mode *mode;
- struct drm_connector *connector = get_connector(bridge->encoder);
-
- mode = &bridge->encoder->crtc->state->adjusted_mode;
+ struct drm_connector *connector =
+ drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ struct drm_connector_state *conn_state =
+ drm_atomic_get_new_connector_state(state, connector);
+ struct drm_crtc_state *crtc_state =
+ drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ struct drm_display_mode *mode = &crtc_state->adjusted_mode;
hback_porch = mode->htotal - mode->hsync_end;
hsync_len = mode->hsync_end - mode->hsync_start;
vback_porch = mode->vtotal - mode->vsync_end;
vsync_len = mode->vsync_end - mode->vsync_start;
@@ -599,14 +592,17 @@ static int tc_bridge_attach(struct drm_bridge *bridge,
&tc->bridge, flags);
}
static const struct drm_bridge_funcs tc_bridge_funcs = {
.attach = tc_bridge_attach,
- .pre_enable = tc_bridge_pre_enable,
- .enable = tc_bridge_enable,
+ .atomic_pre_enable = tc_bridge_atomic_pre_enable,
+ .atomic_enable = tc_bridge_atomic_enable,
.mode_valid = tc_mode_valid,
- .post_disable = tc_bridge_post_disable,
+ .atomic_post_disable = tc_bridge_atomic_post_disable,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
};
static int tc_attach_host(struct tc_data *tc)
{
struct device *dev = &tc->i2c->dev;
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (12 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 13/16] drm/bridge: tc358775: Switch to atomic commit Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-06 15:48 ` Simona Vetter
2025-03-04 11:10 ` [PATCH v5 15/16] drm/bridge: tc358768: Convert to atomic helpers Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 16/16] drm/bridge: ti-sn65dsi86: Remove drm_encoder->crtc use Maxime Ripard
15 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The tc358768 bridge driver, if enabling it fails, tries to disable it.
This is pretty uncommon in bridge drivers, and also stands in the way
for further reworks.
Worse, since pre_enable and enable aren't expected to fail, disable and
post_disable might be called twice: once to handle the failure, and once
to actually disable the bridge.
Since post_disable uses regulators and clocks, this would lead to enable
count imbalances.
In order to prevent that imbalance, and to allow further reworks, let's
drop the calls to disable and post_disable, but keep the warning to let
users know about what's going on.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/tc358768.c | 10 ++--------
1 file changed, 2 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index 6db18d1e8824dd7d387211d6d1e668645cf88bbe..6b65ba8aed86012bc0f464bd5ee44325dae677c6 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -1075,15 +1075,12 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
val |= TC358768_DSI_CONTROL_DIS_MODE; /* DSI mode */
tc358768_write(priv, TC358768_DSI_CONFW, val);
ret = tc358768_clear_error(priv);
- if (ret) {
+ if (ret)
dev_err(dev, "Bridge pre_enable failed: %d\n", ret);
- tc358768_bridge_disable(bridge);
- tc358768_bridge_post_disable(bridge);
- }
}
static void tc358768_bridge_enable(struct drm_bridge *bridge)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
@@ -1099,15 +1096,12 @@ static void tc358768_bridge_enable(struct drm_bridge *bridge)
/* set PP_en */
tc358768_update_bits(priv, TC358768_CONFCTL, BIT(6), BIT(6));
ret = tc358768_clear_error(priv);
- if (ret) {
+ if (ret)
dev_err(priv->dev, "Bridge enable failed: %d\n", ret);
- tc358768_bridge_disable(bridge);
- tc358768_bridge_post_disable(bridge);
- }
}
#define MAX_INPUT_SEL_FORMATS 1
static u32 *
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 15/16] drm/bridge: tc358768: Convert to atomic helpers
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (13 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 16/16] drm/bridge: ti-sn65dsi86: Remove drm_encoder->crtc use Maxime Ripard
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard,
Dmitry Baryshkov
The tc358768 driver follows the drm_encoder->crtc pointer that is
deprecated and shouldn't be used by atomic drivers.
Fortunately, the atomic hooks provide the drm_atomic_state and we can
access our current CRTC from that, going from the bridge to its encoder,
to its connector, and to its CRTC.
Let's convert this bridge driver to atomic so we can get rid of the
drm_encoder->crtc dereference.
Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/tc358768.c | 28 +++++++++++++++++++---------
1 file changed, 19 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
index 6b65ba8aed86012bc0f464bd5ee44325dae677c6..063f217a17b6cf32e9793b8a96a5ac6128584098 100644
--- a/drivers/gpu/drm/bridge/tc358768.c
+++ b/drivers/gpu/drm/bridge/tc358768.c
@@ -579,11 +579,12 @@ tc358768_bridge_mode_valid(struct drm_bridge *bridge,
return MODE_CLOCK_RANGE;
return MODE_OK;
}
-static void tc358768_bridge_disable(struct drm_bridge *bridge)
+static void tc358768_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
int ret;
/* set FrmStop */
@@ -601,11 +602,12 @@ static void tc358768_bridge_disable(struct drm_bridge *bridge)
ret = tc358768_clear_error(priv);
if (ret)
dev_warn(priv->dev, "Software disable failed: %d\n", ret);
}
-static void tc358768_bridge_post_disable(struct drm_bridge *bridge)
+static void tc358768_bridge_atomic_post_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
tc358768_hw_disable(priv);
}
@@ -681,17 +683,21 @@ static u32 tc358768_dsi_bytes_to_ns(struct tc358768_priv *priv, u32 val)
u64 n = priv->dsiclk / 4 * priv->dsi_lanes;
return (u32)div_u64(m, n);
}
-static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
+static void tc358768_bridge_atomic_pre_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
struct mipi_dsi_device *dsi_dev = priv->output.dev;
unsigned long mode_flags = dsi_dev->mode_flags;
u32 val, val2, lptxcnt, hact, data_type;
s32 raw_val;
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *connector;
const struct drm_display_mode *mode;
u32 hsbyteclk_ps, dsiclk_ps, ui_ps;
u32 dsiclk, hsbyteclk;
int ret, i;
struct videomode vm;
@@ -718,11 +724,14 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
dev_err(dev, "Software reset failed: %d\n", ret);
tc358768_hw_disable(priv);
return;
}
- mode = &bridge->encoder->crtc->state->adjusted_mode;
+ connector = drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ mode = &crtc_state->adjusted_mode;
ret = tc358768_setup_pll(priv, mode);
if (ret) {
dev_err(dev, "PLL setup failed: %d\n", ret);
tc358768_hw_disable(priv);
return;
@@ -1079,11 +1088,12 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
ret = tc358768_clear_error(priv);
if (ret)
dev_err(dev, "Bridge pre_enable failed: %d\n", ret);
}
-static void tc358768_bridge_enable(struct drm_bridge *bridge)
+static void tc358768_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
{
struct tc358768_priv *priv = bridge_to_tc358768(bridge);
int ret;
if (!priv->enabled) {
@@ -1159,14 +1169,14 @@ static bool tc358768_mode_fixup(struct drm_bridge *bridge,
static const struct drm_bridge_funcs tc358768_bridge_funcs = {
.attach = tc358768_bridge_attach,
.mode_valid = tc358768_bridge_mode_valid,
.mode_fixup = tc358768_mode_fixup,
- .pre_enable = tc358768_bridge_pre_enable,
- .enable = tc358768_bridge_enable,
- .disable = tc358768_bridge_disable,
- .post_disable = tc358768_bridge_post_disable,
+ .atomic_pre_enable = tc358768_bridge_atomic_pre_enable,
+ .atomic_enable = tc358768_bridge_atomic_enable,
+ .atomic_disable = tc358768_bridge_atomic_disable,
+ .atomic_post_disable = tc358768_bridge_atomic_post_disable,
.atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
.atomic_reset = drm_atomic_helper_bridge_reset,
.atomic_get_input_bus_fmts = tc358768_atomic_get_input_bus_fmts,
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* [PATCH v5 16/16] drm/bridge: ti-sn65dsi86: Remove drm_encoder->crtc use
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
` (14 preceding siblings ...)
2025-03-04 11:10 ` [PATCH v5 15/16] drm/bridge: tc358768: Convert to atomic helpers Maxime Ripard
@ 2025-03-04 11:10 ` Maxime Ripard
15 siblings, 0 replies; 52+ messages in thread
From: Maxime Ripard @ 2025-03-04 11:10 UTC (permalink / raw)
To: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson
Cc: Herve Codina, dri-devel, linux-kernel, Maxime Ripard
The TI sn65dsi86 driver follows the drm_encoder->crtc pointer that is
deprecated and shouldn't be used by atomic drivers.
Fortunately, the atomic hooks provide the drm_atomic_state and we can
access our current CRTC from that, going from the bridge to its encoder,
to its connector, and to its CRTC.
This bridge driver uses the atomic hooks already, but dereferences the
drm_encoder->crtc pointer in functions that don't have access to it.
Let's rework the driver to pass the state where needed, and remove the
need for the drm_encoder->crtc dereference.
Reviewed-by: Douglas Anderson <dianders@chromium.org>
Tested-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Maxime Ripard <mripard@kernel.org>
---
drivers/gpu/drm/bridge/ti-sn65dsi86.c | 55 ++++++++++++++++++++++++-----------
1 file changed, 38 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index 190929a41abd1d8d6619e27bb9391f75145ed64a..fd68ad2e27186c24cef20dd4ae20decdd6da4a2e 100644
--- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c
+++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
@@ -241,15 +241,30 @@ static void ti_sn65dsi86_write_u16(struct ti_sn65dsi86 *pdata,
u8 buf[2] = { val & 0xff, val >> 8 };
regmap_bulk_write(pdata->regmap, reg, buf, ARRAY_SIZE(buf));
}
-static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn65dsi86 *pdata)
+static struct drm_display_mode *
+get_new_adjusted_display_mode(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
+{
+ struct drm_connector *connector =
+ drm_atomic_get_new_connector_for_encoder(state, bridge->encoder);
+ struct drm_connector_state *conn_state =
+ drm_atomic_get_new_connector_state(state, connector);
+ struct drm_crtc_state *crtc_state =
+ drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+
+ return &crtc_state->adjusted_mode;
+}
+
+static u32 ti_sn_bridge_get_dsi_freq(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state)
{
u32 bit_rate_khz, clk_freq_khz;
struct drm_display_mode *mode =
- &pdata->bridge.encoder->crtc->state->adjusted_mode;
+ get_new_adjusted_display_mode(&pdata->bridge, state);
bit_rate_khz = mode->clock *
mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
clk_freq_khz = bit_rate_khz / (pdata->dsi->lanes * 2);
@@ -272,11 +287,12 @@ static const u32 ti_sn_bridge_dsiclk_lut[] = {
416000000,
486000000,
460800000,
};
-static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata)
+static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state)
{
int i;
u32 refclk_rate;
const u32 *refclk_lut;
size_t refclk_lut_size;
@@ -285,11 +301,11 @@ static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata)
refclk_rate = clk_get_rate(pdata->refclk);
refclk_lut = ti_sn_bridge_refclk_lut;
refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_refclk_lut);
clk_prepare_enable(pdata->refclk);
} else {
- refclk_rate = ti_sn_bridge_get_dsi_freq(pdata) * 1000;
+ refclk_rate = ti_sn_bridge_get_dsi_freq(pdata, state) * 1000;
refclk_lut = ti_sn_bridge_dsiclk_lut;
refclk_lut_size = ARRAY_SIZE(ti_sn_bridge_dsiclk_lut);
}
/* for i equals to refclk_lut_size means default frequency */
@@ -309,16 +325,17 @@ static void ti_sn_bridge_set_refclk_freq(struct ti_sn65dsi86 *pdata)
* regardless of its actual sourcing.
*/
pdata->pwm_refclk_freq = ti_sn_bridge_refclk_lut[i];
}
-static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata)
+static void ti_sn65dsi86_enable_comms(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state)
{
mutex_lock(&pdata->comms_mutex);
/* configure bridge ref_clk */
- ti_sn_bridge_set_refclk_freq(pdata);
+ ti_sn_bridge_set_refclk_freq(pdata, state);
/*
* HPD on this bridge chip is a bit useless. This is an eDP bridge
* so the HPD is an internal signal that's only there to signal that
* the panel is done powering up. ...but the bridge chip debounces
@@ -374,11 +391,11 @@ static int __maybe_unused ti_sn65dsi86_resume(struct device *dev)
* so we can do it in resume which lets us read the EDID before
* pre_enable(). Without a reference clock we need the MIPI reference
* clock so reading early doesn't work.
*/
if (pdata->refclk)
- ti_sn65dsi86_enable_comms(pdata);
+ ti_sn65dsi86_enable_comms(pdata, NULL);
return ret;
}
static int __maybe_unused ti_sn65dsi86_suspend(struct device *dev)
@@ -820,16 +837,17 @@ static void ti_sn_bridge_atomic_disable(struct drm_bridge *bridge,
/* disable video stream */
regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE, 0);
}
-static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata)
+static void ti_sn_bridge_set_dsi_rate(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state)
{
unsigned int bit_rate_mhz, clk_freq_mhz;
unsigned int val;
struct drm_display_mode *mode =
- &pdata->bridge.encoder->crtc->state->adjusted_mode;
+ get_new_adjusted_display_mode(&pdata->bridge, state);
/* set DSIA clk frequency */
bit_rate_mhz = (mode->clock / 1000) *
mipi_dsi_pixel_format_to_bpp(pdata->dsi->format);
clk_freq_mhz = bit_rate_mhz / (pdata->dsi->lanes * 2);
@@ -855,16 +873,18 @@ static unsigned int ti_sn_bridge_get_bpp(struct drm_connector *connector)
*/
static const unsigned int ti_sn_bridge_dp_rate_lut[] = {
0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
};
-static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata, unsigned int bpp)
+static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state,
+ unsigned int bpp)
{
unsigned int bit_rate_khz, dp_rate_mhz;
unsigned int i;
struct drm_display_mode *mode =
- &pdata->bridge.encoder->crtc->state->adjusted_mode;
+ get_new_adjusted_display_mode(&pdata->bridge, state);
/* Calculate minimum bit rate based on our pixel clock. */
bit_rate_khz = mode->clock * bpp;
/* Calculate minimum DP data rate, taking 80% as per DP spec */
@@ -959,14 +979,15 @@ static unsigned int ti_sn_bridge_read_valid_rates(struct ti_sn65dsi86 *pdata)
}
return valid_rates;
}
-static void ti_sn_bridge_set_video_timings(struct ti_sn65dsi86 *pdata)
+static void ti_sn_bridge_set_video_timings(struct ti_sn65dsi86 *pdata,
+ struct drm_atomic_state *state)
{
struct drm_display_mode *mode =
- &pdata->bridge.encoder->crtc->state->adjusted_mode;
+ get_new_adjusted_display_mode(&pdata->bridge, state);
u8 hsync_polarity = 0, vsync_polarity = 0;
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
hsync_polarity = CHA_HSYNC_POLARITY;
if (mode->flags & DRM_MODE_FLAG_NVSYNC)
@@ -1104,11 +1125,11 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge,
regmap_write(pdata->regmap, SN_LN_ASSIGN_REG, pdata->ln_assign);
regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, LN_POLRS_MASK,
pdata->ln_polrs << LN_POLRS_OFFSET);
/* set dsi clk frequency value */
- ti_sn_bridge_set_dsi_rate(pdata);
+ ti_sn_bridge_set_dsi_rate(pdata, state);
/*
* The SN65DSI86 only supports ASSR Display Authentication method and
* this method is enabled for eDP panels. An eDP panel must support this
* authentication method. We need to enable this method in the eDP panel
@@ -1139,11 +1160,11 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge,
val);
valid_rates = ti_sn_bridge_read_valid_rates(pdata);
/* Train until we run out of rates */
- for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata, bpp);
+ for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata, state, bpp);
dp_rate_idx < ARRAY_SIZE(ti_sn_bridge_dp_rate_lut);
dp_rate_idx++) {
if (!(valid_rates & BIT(dp_rate_idx)))
continue;
@@ -1155,11 +1176,11 @@ static void ti_sn_bridge_atomic_enable(struct drm_bridge *bridge,
DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret);
return;
}
/* config video parameters */
- ti_sn_bridge_set_video_timings(pdata);
+ ti_sn_bridge_set_video_timings(pdata, state);
/* enable video stream */
regmap_update_bits(pdata->regmap, SN_ENH_FRAME_REG, VSTREAM_ENABLE,
VSTREAM_ENABLE);
}
@@ -1170,11 +1191,11 @@ static void ti_sn_bridge_atomic_pre_enable(struct drm_bridge *bridge,
struct ti_sn65dsi86 *pdata = bridge_to_ti_sn65dsi86(bridge);
pm_runtime_get_sync(pdata->dev);
if (!pdata->refclk)
- ti_sn65dsi86_enable_comms(pdata);
+ ti_sn65dsi86_enable_comms(pdata, state);
/* td7: min 100 us after enable before DSI data */
usleep_range(100, 110);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re:[PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
@ 2025-03-05 11:55 ` Andy Yan
2025-03-05 13:19 ` [PATCH " Maxime Ripard
2025-03-13 8:09 ` Andy Yan
2025-03-06 8:21 ` Herve Codina
2025-03-06 15:44 ` Simona Vetter
2 siblings, 2 replies; 52+ messages in thread
From: Andy Yan @ 2025-03-05 11:55 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter
Hi Maxime,
At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>With the bridges switching over to drm_bridge_connector, the direct
>association between a bridge driver and its connector was lost.
>
>This is mitigated for atomic bridge drivers by the fact you can access
>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>
>This was also made easier by providing drm_atomic_state directly to all
>atomic hooks bridges can implement.
>
>However, bridge drivers don't have a way to access drm_atomic_state
>outside of the modeset path, like from the hotplug interrupt path or any
>interrupt handler.
>
>Let's introduce a function to retrieve the connector currently assigned
>to an encoder, without using drm_atomic_state, to make these drivers'
>life easier.
>
>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>---
> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> include/drm/drm_atomic.h | 3 +++
> 2 files changed, 48 insertions(+)
>
>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>--- a/drivers/gpu/drm/drm_atomic.c
>+++ b/drivers/gpu/drm/drm_atomic.c
>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>
> return NULL;
> }
> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>
>+/**
>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>+ * @encoder: The encoder to find the connector of
>+ * @ctx: Modeset locking context
>+ *
>+ * This function finds and returns the connector currently assigned to
>+ * an @encoder.
>+ *
>+ * Returns:
>+ * The connector connected to @encoder, or an error pointer otherwise.
>+ * When the error is EDEADLK, a deadlock has been detected and the
>+ * sequence must be restarted.
>+ */
>+struct drm_connector *
>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>+ struct drm_modeset_acquire_ctx *ctx)
>+{
>+ struct drm_connector_list_iter conn_iter;
>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>+ struct drm_connector *connector;
>+ struct drm_device *dev = encoder->dev;
>+ int ret;
>+
>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>+ if (ret)
>+ return ERR_PTR(ret);
It seems that this will cause a deadlock when called from a hotplug handling path,
I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
which will hold connection_mutex first, so the deaklock happens:
drm_helper_probe_detect(struct drm_connector *connector,
struct drm_modeset_acquire_ctx *ctx,
bool force)
{
const struct drm_connector_helper_funcs *funcs = connector->helper_private;
struct drm_device *dev = connector->dev;
int ret;
if (!ctx)
return drm_helper_probe_detect_ctx(connector, force);
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
if (ret)
return ret;
if (funcs->detect_ctx)
ret = funcs->detect_ctx(connector, ctx, force);
else if (connector->funcs->detect)
ret = connector->funcs->detect(connector, force);
else
ret = connector_status_connected;
if (ret != connector->status)
connector->epoch_counter += 1;
So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>+
>+ drm_connector_list_iter_begin(dev, &conn_iter);
>+ drm_for_each_connector_iter(connector, &conn_iter) {
>+ if (!connector->state)
>+ continue;
>+
>+ if (encoder == connector->state->best_encoder) {
>+ out_connector = connector;
>+ break;
>+ }
>+ }
>+ drm_connector_list_iter_end(&conn_iter);
>+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
>+
>+ return out_connector;
>+}
>+EXPORT_SYMBOL(drm_atomic_get_connector_for_encoder);
>+
>+
> /**
> * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
> * @state: Atomic state
> * @encoder: The encoder to fetch the crtc state for
> *
>diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
>index 4c673f0698fef6b60f77db980378d5e88e0e250e..38636a593c9d98cadda85ccd67326cb152f0dd27 100644
>--- a/include/drm/drm_atomic.h
>+++ b/include/drm/drm_atomic.h
>@@ -623,10 +623,13 @@ struct drm_connector *
> drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
> struct drm_encoder *encoder);
> struct drm_connector *
> drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> struct drm_encoder *encoder);
>+struct drm_connector *
>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>+ struct drm_modeset_acquire_ctx *ctx);
>
> struct drm_crtc *
> drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
> struct drm_encoder *encoder);
> struct drm_crtc *
>
>--
>2.48.1
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach
2025-03-04 11:10 ` [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach Maxime Ripard
@ 2025-03-05 13:04 ` Luca Ceresoli
0 siblings, 0 replies; 52+ messages in thread
From: Luca Ceresoli @ 2025-03-05 13:04 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov
On Tue, 04 Mar 2025 12:10:44 +0100
Maxime Ripard <mripard@kernel.org> wrote:
> The drm_bridge structure contains an encoder pointer that is widely used
> by bridge drivers. This pattern is largely documented as deprecated in
> other KMS entities for atomic drivers.
>
> However, one of the main use of that pointer is done in attach to just
> call drm_bridge_attach on the next bridge to add it to the bridge list.
> While this dereferences the bridge->encoder pointer, it's effectively
> the same encoder the bridge was being attached to.
>
> We can make it more explicit by adding the encoder the bridge is
> attached to to the list of attach parameters. This also removes the need
> to dereference bridge->encoder in most drivers.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Reviewed-by: Douglas Anderson <dianders@chromium.org>
> Tested-by: Douglas Anderson <dianders@chromium.org>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Tested-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>
--
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-05 11:55 ` Andy Yan
@ 2025-03-05 13:19 ` Maxime Ripard
2025-03-05 20:13 ` Dmitry Baryshkov
2025-03-13 8:09 ` Andy Yan
1 sibling, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-05 13:19 UTC (permalink / raw)
To: Andy Yan
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter
[-- Attachment #1: Type: text/plain, Size: 4347 bytes --]
Hi Andy,
On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
> At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> >With the bridges switching over to drm_bridge_connector, the direct
> >association between a bridge driver and its connector was lost.
> >
> >This is mitigated for atomic bridge drivers by the fact you can access
> >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> >
> >This was also made easier by providing drm_atomic_state directly to all
> >atomic hooks bridges can implement.
> >
> >However, bridge drivers don't have a way to access drm_atomic_state
> >outside of the modeset path, like from the hotplug interrupt path or any
> >interrupt handler.
> >
> >Let's introduce a function to retrieve the connector currently assigned
> >to an encoder, without using drm_atomic_state, to make these drivers'
> >life easier.
> >
> >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> >Signed-off-by: Maxime Ripard <mripard@kernel.org>
> >---
> > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > include/drm/drm_atomic.h | 3 +++
> > 2 files changed, 48 insertions(+)
> >
> >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> >--- a/drivers/gpu/drm/drm_atomic.c
> >+++ b/drivers/gpu/drm/drm_atomic.c
> >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> >
> > return NULL;
> > }
> > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> >
> >+/**
> >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> >+ * @encoder: The encoder to find the connector of
> >+ * @ctx: Modeset locking context
> >+ *
> >+ * This function finds and returns the connector currently assigned to
> >+ * an @encoder.
> >+ *
> >+ * Returns:
> >+ * The connector connected to @encoder, or an error pointer otherwise.
> >+ * When the error is EDEADLK, a deadlock has been detected and the
> >+ * sequence must be restarted.
> >+ */
> >+struct drm_connector *
> >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> >+ struct drm_modeset_acquire_ctx *ctx)
> >+{
> >+ struct drm_connector_list_iter conn_iter;
> >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> >+ struct drm_connector *connector;
> >+ struct drm_device *dev = encoder->dev;
> >+ int ret;
> >+
> >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >+ if (ret)
> >+ return ERR_PTR(ret);
>
> It seems that this will cause a deadlock when called from a hotplug
> handling path, I have a WIP DP diver[0], which suggested by Dmitry to
> use this API from a &drm_bridge_funcs.detect callback to get the
> connector, as detect is called by drm_helper_probe_detect, which will
> hold connection_mutex first, so the deaklock happens:
>
> drm_helper_probe_detect(struct drm_connector *connector,
> struct drm_modeset_acquire_ctx *ctx,
> bool force)
> {
> const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> struct drm_device *dev = connector->dev;
> int ret;
>
> if (!ctx)
> return drm_helper_probe_detect_ctx(connector, force);
>
> ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> if (ret)
> return ret;
>
> if (funcs->detect_ctx)
> ret = funcs->detect_ctx(connector, ctx, force);
> else if (connector->funcs->detect)
> ret = connector->funcs->detect(connector, force);
> else
> ret = connector_status_connected;
>
> if (ret != connector->status)
> connector->epoch_counter += 1;
>
> So I wonder can we let drm_bridge_funcs.detect pass a connector for
> this case ?
Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
fine with reentrancy from the same context, so it should work just fine.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-05 13:19 ` [PATCH " Maxime Ripard
@ 2025-03-05 20:13 ` Dmitry Baryshkov
2025-03-06 1:16 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-05 20:13 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Simona Vetter
On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
> Hi Andy,
>
> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > >With the bridges switching over to drm_bridge_connector, the direct
> > >association between a bridge driver and its connector was lost.
> > >
> > >This is mitigated for atomic bridge drivers by the fact you can access
> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > >
> > >This was also made easier by providing drm_atomic_state directly to all
> > >atomic hooks bridges can implement.
> > >
> > >However, bridge drivers don't have a way to access drm_atomic_state
> > >outside of the modeset path, like from the hotplug interrupt path or any
> > >interrupt handler.
> > >
> > >Let's introduce a function to retrieve the connector currently assigned
> > >to an encoder, without using drm_atomic_state, to make these drivers'
> > >life easier.
> > >
> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > >---
> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > include/drm/drm_atomic.h | 3 +++
> > > 2 files changed, 48 insertions(+)
> > >
> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > >--- a/drivers/gpu/drm/drm_atomic.c
> > >+++ b/drivers/gpu/drm/drm_atomic.c
> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > >
> > > return NULL;
> > > }
> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > >
> > >+/**
> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > >+ * @encoder: The encoder to find the connector of
> > >+ * @ctx: Modeset locking context
> > >+ *
> > >+ * This function finds and returns the connector currently assigned to
> > >+ * an @encoder.
> > >+ *
> > >+ * Returns:
> > >+ * The connector connected to @encoder, or an error pointer otherwise.
> > >+ * When the error is EDEADLK, a deadlock has been detected and the
> > >+ * sequence must be restarted.
> > >+ */
> > >+struct drm_connector *
> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > >+ struct drm_modeset_acquire_ctx *ctx)
> > >+{
> > >+ struct drm_connector_list_iter conn_iter;
> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > >+ struct drm_connector *connector;
> > >+ struct drm_device *dev = encoder->dev;
> > >+ int ret;
> > >+
> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > >+ if (ret)
> > >+ return ERR_PTR(ret);
> >
> > It seems that this will cause a deadlock when called from a hotplug
> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
> > use this API from a &drm_bridge_funcs.detect callback to get the
> > connector, as detect is called by drm_helper_probe_detect, which will
> > hold connection_mutex first, so the deaklock happens:
> >
> > drm_helper_probe_detect(struct drm_connector *connector,
> > struct drm_modeset_acquire_ctx *ctx,
> > bool force)
> > {
> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > struct drm_device *dev = connector->dev;
> > int ret;
> >
> > if (!ctx)
> > return drm_helper_probe_detect_ctx(connector, force);
> >
> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > if (ret)
> > return ret;
> >
> > if (funcs->detect_ctx)
> > ret = funcs->detect_ctx(connector, ctx, force);
> > else if (connector->funcs->detect)
> > ret = connector->funcs->detect(connector, force);
> > else
> > ret = connector_status_connected;
> >
> > if (ret != connector->status)
> > connector->epoch_counter += 1;
> >
> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
> > this case ?
>
> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
> fine with reentrancy from the same context, so it should work just fine.
Andy, that probably means that you should use .detect_ctx() and pass the
context to drm_atomic_get_connector_for_encoder().
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-05 20:13 ` Dmitry Baryshkov
@ 2025-03-06 1:16 ` Andy Yan
2025-03-06 7:10 ` Maxime Ripard
0 siblings, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-03-06 1:16 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Maxime Ripard, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Simona Vetter
Hi Maxime and Dmitry:
At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
>On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
>> Hi Andy,
>>
>> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
>> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > >With the bridges switching over to drm_bridge_connector, the direct
>> > >association between a bridge driver and its connector was lost.
>> > >
>> > >This is mitigated for atomic bridge drivers by the fact you can access
>> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> > >
>> > >This was also made easier by providing drm_atomic_state directly to all
>> > >atomic hooks bridges can implement.
>> > >
>> > >However, bridge drivers don't have a way to access drm_atomic_state
>> > >outside of the modeset path, like from the hotplug interrupt path or any
>> > >interrupt handler.
>> > >
>> > >Let's introduce a function to retrieve the connector currently assigned
>> > >to an encoder, without using drm_atomic_state, to make these drivers'
>> > >life easier.
>> > >
>> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> > >---
>> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> > > include/drm/drm_atomic.h | 3 +++
>> > > 2 files changed, 48 insertions(+)
>> > >
>> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> > >--- a/drivers/gpu/drm/drm_atomic.c
>> > >+++ b/drivers/gpu/drm/drm_atomic.c
>> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> > >
>> > > return NULL;
>> > > }
>> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> > >
>> > >+/**
>> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> > >+ * @encoder: The encoder to find the connector of
>> > >+ * @ctx: Modeset locking context
>> > >+ *
>> > >+ * This function finds and returns the connector currently assigned to
>> > >+ * an @encoder.
>> > >+ *
>> > >+ * Returns:
>> > >+ * The connector connected to @encoder, or an error pointer otherwise.
>> > >+ * When the error is EDEADLK, a deadlock has been detected and the
>> > >+ * sequence must be restarted.
>> > >+ */
>> > >+struct drm_connector *
>> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> > >+ struct drm_modeset_acquire_ctx *ctx)
>> > >+{
>> > >+ struct drm_connector_list_iter conn_iter;
>> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> > >+ struct drm_connector *connector;
>> > >+ struct drm_device *dev = encoder->dev;
>> > >+ int ret;
>> > >+
>> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > >+ if (ret)
>> > >+ return ERR_PTR(ret);
>> >
>> > It seems that this will cause a deadlock when called from a hotplug
>> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
>> > use this API from a &drm_bridge_funcs.detect callback to get the
>> > connector, as detect is called by drm_helper_probe_detect, which will
>> > hold connection_mutex first, so the deaklock happens:
>> >
>> > drm_helper_probe_detect(struct drm_connector *connector,
>> > struct drm_modeset_acquire_ctx *ctx,
>> > bool force)
>> > {
>> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > struct drm_device *dev = connector->dev;
>> > int ret;
>> >
>> > if (!ctx)
>> > return drm_helper_probe_detect_ctx(connector, force);
>> >
>> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > if (ret)
>> > return ret;
>> >
>> > if (funcs->detect_ctx)
>> > ret = funcs->detect_ctx(connector, ctx, force);
>> > else if (connector->funcs->detect)
>> > ret = connector->funcs->detect(connector, force);
>> > else
>> > ret = connector_status_connected;
>> >
>> > if (ret != connector->status)
>> > connector->epoch_counter += 1;
>> >
>> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
>> > this case ?
>>
>> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
>> fine with reentrancy from the same context, so it should work just fine.
>
>Andy, that probably means that you should use .detect_ctx() and pass the
>context to drm_atomic_get_connector_for_encoder().
Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
The call chain is:
drm_helper_probe_detect
--> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
--> drm_bridge_funcs.detect(bridge)
The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
The connector got dropped when connector call it's bridege.detect
So I think the simplest solution is to have drm_bridge_funcs.detect directly pass the connector
>
>--
>With best wishes
>Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-06 1:16 ` Andy Yan
@ 2025-03-06 7:10 ` Maxime Ripard
2025-03-06 15:41 ` Simona Vetter
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-06 7:10 UTC (permalink / raw)
To: Andy Yan
Cc: Dmitry Baryshkov, Maarten Lankhorst, Thomas Zimmermann,
David Airlie, Simona Vetter, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Douglas Anderson, Herve Codina, dri-devel, linux-kernel,
Simona Vetter
[-- Attachment #1: Type: text/plain, Size: 5875 bytes --]
On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
>
> Hi Maxime and Dmitry:
>
> At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
> >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
> >> Hi Andy,
> >>
> >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
> >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> >> > >With the bridges switching over to drm_bridge_connector, the direct
> >> > >association between a bridge driver and its connector was lost.
> >> > >
> >> > >This is mitigated for atomic bridge drivers by the fact you can access
> >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> >> > >
> >> > >This was also made easier by providing drm_atomic_state directly to all
> >> > >atomic hooks bridges can implement.
> >> > >
> >> > >However, bridge drivers don't have a way to access drm_atomic_state
> >> > >outside of the modeset path, like from the hotplug interrupt path or any
> >> > >interrupt handler.
> >> > >
> >> > >Let's introduce a function to retrieve the connector currently assigned
> >> > >to an encoder, without using drm_atomic_state, to make these drivers'
> >> > >life easier.
> >> > >
> >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
> >> > >---
> >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> >> > > include/drm/drm_atomic.h | 3 +++
> >> > > 2 files changed, 48 insertions(+)
> >> > >
> >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> >> > >--- a/drivers/gpu/drm/drm_atomic.c
> >> > >+++ b/drivers/gpu/drm/drm_atomic.c
> >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> >> > >
> >> > > return NULL;
> >> > > }
> >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> >> > >
> >> > >+/**
> >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> >> > >+ * @encoder: The encoder to find the connector of
> >> > >+ * @ctx: Modeset locking context
> >> > >+ *
> >> > >+ * This function finds and returns the connector currently assigned to
> >> > >+ * an @encoder.
> >> > >+ *
> >> > >+ * Returns:
> >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
> >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
> >> > >+ * sequence must be restarted.
> >> > >+ */
> >> > >+struct drm_connector *
> >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> >> > >+ struct drm_modeset_acquire_ctx *ctx)
> >> > >+{
> >> > >+ struct drm_connector_list_iter conn_iter;
> >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> >> > >+ struct drm_connector *connector;
> >> > >+ struct drm_device *dev = encoder->dev;
> >> > >+ int ret;
> >> > >+
> >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >> > >+ if (ret)
> >> > >+ return ERR_PTR(ret);
> >> >
> >> > It seems that this will cause a deadlock when called from a hotplug
> >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
> >> > use this API from a &drm_bridge_funcs.detect callback to get the
> >> > connector, as detect is called by drm_helper_probe_detect, which will
> >> > hold connection_mutex first, so the deaklock happens:
> >> >
> >> > drm_helper_probe_detect(struct drm_connector *connector,
> >> > struct drm_modeset_acquire_ctx *ctx,
> >> > bool force)
> >> > {
> >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> >> > struct drm_device *dev = connector->dev;
> >> > int ret;
> >> >
> >> > if (!ctx)
> >> > return drm_helper_probe_detect_ctx(connector, force);
> >> >
> >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >> > if (ret)
> >> > return ret;
> >> >
> >> > if (funcs->detect_ctx)
> >> > ret = funcs->detect_ctx(connector, ctx, force);
> >> > else if (connector->funcs->detect)
> >> > ret = connector->funcs->detect(connector, force);
> >> > else
> >> > ret = connector_status_connected;
> >> >
> >> > if (ret != connector->status)
> >> > connector->epoch_counter += 1;
> >> >
> >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
> >> > this case ?
> >>
> >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
> >> fine with reentrancy from the same context, so it should work just fine.
> >
> >Andy, that probably means that you should use .detect_ctx() and pass the
> >context to drm_atomic_get_connector_for_encoder().
>
> Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
> The call chain is:
> drm_helper_probe_detect
> --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
> --> drm_bridge_funcs.detect(bridge)
> The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
> The connector got dropped when connector call it's bridege.detect
>
> So I think the simplest solution is to have drm_bridge_funcs.detect
> directly pass the connector
I don't disagree on principle, but I think a better first step would be
to provide a detect_ctx hook to bridges.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc
2025-03-04 11:10 ` [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc Maxime Ripard
@ 2025-03-06 8:09 ` Herve Codina
0 siblings, 0 replies; 52+ messages in thread
From: Herve Codina @ 2025-03-06 8:09 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, dri-devel,
linux-kernel, Dmitry Baryshkov
Hi Maxime,
On Tue, 04 Mar 2025 12:10:53 +0100
Maxime Ripard <mripard@kernel.org> wrote:
> Now that we have a helper for bridge drivers to call to reset the output
> pipeline, let's use it.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/bridge/ti-sn65dsi83.c | 28 +++++++++++-----------------
> 1 file changed, 11 insertions(+), 17 deletions(-)
>
Reviewed-by: Herve Codina <herve.codina@bootlin.com>
Also tested on my system with faults manually generated and no regressions
were observed in the driver recovery process. Works fine.
Tested-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline
2025-03-04 11:10 ` [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline Maxime Ripard
@ 2025-03-06 8:12 ` Herve Codina
2025-03-06 15:46 ` Simona Vetter
1 sibling, 0 replies; 52+ messages in thread
From: Herve Codina @ 2025-03-06 8:12 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, dri-devel,
linux-kernel, Simona Vetter
Hi Maxime,
On Tue, 04 Mar 2025 12:10:51 +0100
Maxime Ripard <mripard@kernel.org> wrote:
> Let's provide an helper to make it easier for bridge drivers to
> power-cycle their bridge.
>
> In order to avoid a circular dependency between that new helper and
> drm_atomic_helper_reset_crtc(), this new helper will be in a
> drm_bridge_helper.c file to follow the pattern we have for other
> objects.
>
> Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/drm_bridge_helper.c | 55 +++++++++++++++++++++++++++++++++++++
> include/drm/drm_bridge_helper.h | 12 ++++++++
> 3 files changed, 68 insertions(+)
>
Reviewed-by: Herve Codina <herve.codina@bootlin.com>
Also tested on my system using the ti-sn65dsi83 driver (updated in this series)
with faults manually generated on the hardware. No regressions were observed in
the driver recovery process. Works fine.
Tested-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
2025-03-05 11:55 ` Andy Yan
@ 2025-03-06 8:21 ` Herve Codina
2025-03-06 15:44 ` Simona Vetter
2 siblings, 0 replies; 52+ messages in thread
From: Herve Codina @ 2025-03-06 8:21 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, dri-devel,
linux-kernel, Dmitry Baryshkov, Simona Vetter
Hi Maxime,
Hi Maxime,
On Tue, 04 Mar 2025 12:10:47 +0100
Maxime Ripard <mripard@kernel.org> wrote:
> With the bridges switching over to drm_bridge_connector, the direct
> association between a bridge driver and its connector was lost.
>
> This is mitigated for atomic bridge drivers by the fact you can access
> the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>
> This was also made easier by providing drm_atomic_state directly to all
> atomic hooks bridges can implement.
>
> However, bridge drivers don't have a way to access drm_atomic_state
> outside of the modeset path, like from the hotplug interrupt path or any
> interrupt handler.
>
> Let's introduce a function to retrieve the connector currently assigned
> to an encoder, without using drm_atomic_state, to make these drivers'
> life easier.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> include/drm/drm_atomic.h | 3 +++
> 2 files changed, 48 insertions(+)
>
Tested the drm_atomic_get_connector_for_encoder() in the context of the
ti-sn65dsi83 driver recovery process (later modification in this series).
Tested-by: Herve Codina <herve.codina@bootlin.com>
Best regards,
Hervé
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-06 7:10 ` Maxime Ripard
@ 2025-03-06 15:41 ` Simona Vetter
2025-03-07 1:08 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Simona Vetter @ 2025-03-06 15:41 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Dmitry Baryshkov, Maarten Lankhorst, Thomas Zimmermann,
David Airlie, Simona Vetter, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Douglas Anderson, Herve Codina, dri-devel, linux-kernel,
Simona Vetter
On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote:
> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
> >
> > Hi Maxime and Dmitry:
> >
> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
> > >> Hi Andy,
> > >>
> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > >> > >With the bridges switching over to drm_bridge_connector, the direct
> > >> > >association between a bridge driver and its connector was lost.
> > >> > >
> > >> > >This is mitigated for atomic bridge drivers by the fact you can access
> > >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > >> > >
> > >> > >This was also made easier by providing drm_atomic_state directly to all
> > >> > >atomic hooks bridges can implement.
> > >> > >
> > >> > >However, bridge drivers don't have a way to access drm_atomic_state
> > >> > >outside of the modeset path, like from the hotplug interrupt path or any
> > >> > >interrupt handler.
> > >> > >
> > >> > >Let's introduce a function to retrieve the connector currently assigned
> > >> > >to an encoder, without using drm_atomic_state, to make these drivers'
> > >> > >life easier.
> > >> > >
> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > >> > >---
> > >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > >> > > include/drm/drm_atomic.h | 3 +++
> > >> > > 2 files changed, 48 insertions(+)
> > >> > >
> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > >> > >--- a/drivers/gpu/drm/drm_atomic.c
> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c
> > >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > >> > >
> > >> > > return NULL;
> > >> > > }
> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > >> > >
> > >> > >+/**
> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > >> > >+ * @encoder: The encoder to find the connector of
> > >> > >+ * @ctx: Modeset locking context
> > >> > >+ *
> > >> > >+ * This function finds and returns the connector currently assigned to
> > >> > >+ * an @encoder.
> > >> > >+ *
> > >> > >+ * Returns:
> > >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
> > >> > >+ * sequence must be restarted.
> > >> > >+ */
> > >> > >+struct drm_connector *
> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > >> > >+ struct drm_modeset_acquire_ctx *ctx)
> > >> > >+{
> > >> > >+ struct drm_connector_list_iter conn_iter;
> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > >> > >+ struct drm_connector *connector;
> > >> > >+ struct drm_device *dev = encoder->dev;
> > >> > >+ int ret;
> > >> > >+
> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > >> > >+ if (ret)
> > >> > >+ return ERR_PTR(ret);
> > >> >
> > >> > It seems that this will cause a deadlock when called from a hotplug
> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
> > >> > use this API from a &drm_bridge_funcs.detect callback to get the
> > >> > connector, as detect is called by drm_helper_probe_detect, which will
> > >> > hold connection_mutex first, so the deaklock happens:
> > >> >
> > >> > drm_helper_probe_detect(struct drm_connector *connector,
> > >> > struct drm_modeset_acquire_ctx *ctx,
> > >> > bool force)
> > >> > {
> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > >> > struct drm_device *dev = connector->dev;
> > >> > int ret;
> > >> >
> > >> > if (!ctx)
> > >> > return drm_helper_probe_detect_ctx(connector, force);
> > >> >
> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > >> > if (ret)
> > >> > return ret;
> > >> >
> > >> > if (funcs->detect_ctx)
> > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > >> > else if (connector->funcs->detect)
> > >> > ret = connector->funcs->detect(connector, force);
> > >> > else
> > >> > ret = connector_status_connected;
> > >> >
> > >> > if (ret != connector->status)
> > >> > connector->epoch_counter += 1;
> > >> >
> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
> > >> > this case ?
> > >>
> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
> > >> fine with reentrancy from the same context, so it should work just fine.
> > >
> > >Andy, that probably means that you should use .detect_ctx() and pass the
> > >context to drm_atomic_get_connector_for_encoder().
> >
> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
> > The call chain is:
> > drm_helper_probe_detect
> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
> > --> drm_bridge_funcs.detect(bridge)
> > The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
> > The connector got dropped when connector call it's bridege.detect
> >
> > So I think the simplest solution is to have drm_bridge_funcs.detect
> > directly pass the connector
>
> I don't disagree on principle, but I think a better first step would be
> to provide a detect_ctx hook to bridges.
Yup. There's other reasons you really want to get at the locking context
in detect callbacks, doing this special case by passing something for
everyone doesn't sound like the right approach to me.
-Sima
--
Simona Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
2025-03-05 11:55 ` Andy Yan
2025-03-06 8:21 ` Herve Codina
@ 2025-03-06 15:44 ` Simona Vetter
2 siblings, 0 replies; 52+ messages in thread
From: Simona Vetter @ 2025-03-06 15:44 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter
On Tue, Mar 04, 2025 at 12:10:47PM +0100, Maxime Ripard wrote:
> With the bridges switching over to drm_bridge_connector, the direct
> association between a bridge driver and its connector was lost.
>
> This is mitigated for atomic bridge drivers by the fact you can access
> the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>
> This was also made easier by providing drm_atomic_state directly to all
> atomic hooks bridges can implement.
>
> However, bridge drivers don't have a way to access drm_atomic_state
> outside of the modeset path, like from the hotplug interrupt path or any
> interrupt handler.
>
> Let's introduce a function to retrieve the connector currently assigned
> to an encoder, without using drm_atomic_state, to make these drivers'
> life easier.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> include/drm/drm_atomic.h | 3 +++
> 2 files changed, 48 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> --- a/drivers/gpu/drm/drm_atomic.c
> +++ b/drivers/gpu/drm/drm_atomic.c
> @@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>
> return NULL;
> }
> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>
> +/**
> + * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> + * @encoder: The encoder to find the connector of
> + * @ctx: Modeset locking context
> + *
> + * This function finds and returns the connector currently assigned to
> + * an @encoder.
I think it'd be good to link to the other atomic connector functions like
drm_atomic_get_old/new_connector_for_encoder and explain when to use them.
So also add links to the kerneldoc of these other functions pointing to
here.
- This function is for detect, link repair or anything else that comes
from the hardware. Or in general, anything that's not in atomic
commit/check code paths.
- In atomic check/commit code you want to use the other functions.
Otherwise people will have an even harder time finding the right variant
in this maze of look-alikes :-)
With the kerneldoc suitably polished:
Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Simona Vetter <simona.vetter@intel.com>
> + *
> + * Returns:
> + * The connector connected to @encoder, or an error pointer otherwise.
> + * When the error is EDEADLK, a deadlock has been detected and the
> + * sequence must be restarted.
> + */
> +struct drm_connector *
> +drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + struct drm_connector_list_iter conn_iter;
> + struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> + struct drm_connector *connector;
> + struct drm_device *dev = encoder->dev;
> + int ret;
> +
> + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + drm_connector_list_iter_begin(dev, &conn_iter);
> + drm_for_each_connector_iter(connector, &conn_iter) {
> + if (!connector->state)
> + continue;
> +
> + if (encoder == connector->state->best_encoder) {
> + out_connector = connector;
> + break;
> + }
> + }
> + drm_connector_list_iter_end(&conn_iter);
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> + return out_connector;
> +}
> +EXPORT_SYMBOL(drm_atomic_get_connector_for_encoder);
> +
> +
> /**
> * drm_atomic_get_old_crtc_for_encoder - Get old crtc for an encoder
> * @state: Atomic state
> * @encoder: The encoder to fetch the crtc state for
> *
> diff --git a/include/drm/drm_atomic.h b/include/drm/drm_atomic.h
> index 4c673f0698fef6b60f77db980378d5e88e0e250e..38636a593c9d98cadda85ccd67326cb152f0dd27 100644
> --- a/include/drm/drm_atomic.h
> +++ b/include/drm/drm_atomic.h
> @@ -623,10 +623,13 @@ struct drm_connector *
> drm_atomic_get_old_connector_for_encoder(const struct drm_atomic_state *state,
> struct drm_encoder *encoder);
> struct drm_connector *
> drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> struct drm_encoder *encoder);
> +struct drm_connector *
> +drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> + struct drm_modeset_acquire_ctx *ctx);
>
> struct drm_crtc *
> drm_atomic_get_old_crtc_for_encoder(struct drm_atomic_state *state,
> struct drm_encoder *encoder);
> struct drm_crtc *
>
> --
> 2.48.1
>
--
Simona Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline
2025-03-04 11:10 ` [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline Maxime Ripard
2025-03-06 8:12 ` Herve Codina
@ 2025-03-06 15:46 ` Simona Vetter
1 sibling, 0 replies; 52+ messages in thread
From: Simona Vetter @ 2025-03-06 15:46 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Simona Vetter
On Tue, Mar 04, 2025 at 12:10:51PM +0100, Maxime Ripard wrote:
> Let's provide an helper to make it easier for bridge drivers to
> power-cycle their bridge.
>
> In order to avoid a circular dependency between that new helper and
> drm_atomic_helper_reset_crtc(), this new helper will be in a
> drm_bridge_helper.c file to follow the pattern we have for other
> objects.
>
> Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
> ---
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/drm_bridge_helper.c | 55 +++++++++++++++++++++++++++++++++++++
> include/drm/drm_bridge_helper.h | 12 ++++++++
> 3 files changed, 68 insertions(+)
>
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 4cd054188faf0b3dec442efd99ae52604541bce1..5a332f7d3ecccb6e5e1fb9fb811eab7aa5a84a21 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -131,10 +131,11 @@ obj-$(CONFIG_DRM_TTM_HELPER) += drm_ttm_helper.o
> #
>
> drm_kms_helper-y := \
> drm_atomic_helper.o \
> drm_atomic_state_helper.o \
> + drm_bridge_helper.o \
> drm_crtc_helper.o \
> drm_damage_helper.o \
> drm_flip_work.o \
> drm_format_helper.o \
> drm_gem_atomic_helper.o \
> diff --git a/drivers/gpu/drm/drm_bridge_helper.c b/drivers/gpu/drm/drm_bridge_helper.c
> new file mode 100644
> index 0000000000000000000000000000000000000000..521df9d5dcb3fef842a95cdb2865a8b8d09b0fbe
> --- /dev/null
> +++ b/drivers/gpu/drm/drm_bridge_helper.c
> @@ -0,0 +1,55 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_bridge_helper.h>
> +#include <drm/drm_modeset_lock.h>
> +
> +/**
> + * drm_bridge_helper_reset_crtc - Reset the pipeline feeding a bridge
> + * @bridge: DRM bridge to reset
> + * @ctx: lock acquisition context
> + *
> + * Reset a @bridge pipeline. It will power-cycle all active components
> + * between the CRTC and connector that bridge is connected to.
You need to minimally add that the same caveats and limitations of
drm_atomic_helper_reset_crtc() apply to this function here.
Might also be good to link from that kerneldoc to here so people can find
stuff easier, or maybe the overview section I've asked for once that's
landed.
With the kerneldoc polished:
Reviewed-by: Simona Vetter <simona.vetter@ffwll.ch>
Signed-off-by: Simona Vetter <simona.vetter@intel.com>
> + *
> + * Returns:
> + *
> + * 0 on success or a negative error code on failure. If the error
> + * returned is EDEADLK, the whole atomic sequence must be restarted.
> + */
> +int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
> + struct drm_modeset_acquire_ctx *ctx)
> +{
> + struct drm_connector *connector;
> + struct drm_encoder *encoder = bridge->encoder;
> + struct drm_device *dev = encoder->dev;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> + if (ret)
> + return ret;
> +
> + connector = drm_atomic_get_connector_for_encoder(encoder, ctx);
> + if (IS_ERR(connector)) {
> + ret = PTR_ERR(connector);
> + goto out;
> + }
> +
> + if (!connector->state) {
> + ret = -EINVAL;
> + goto out;
> + }
> +
> + crtc = connector->state->crtc;
> + ret = drm_atomic_helper_reset_crtc(crtc, ctx);
> + if (ret)
> + goto out;
> +
> +out:
> + drm_modeset_unlock(&dev->mode_config.connection_mutex);
> + return ret;
> +}
> +EXPORT_SYMBOL(drm_bridge_helper_reset_crtc);
> diff --git a/include/drm/drm_bridge_helper.h b/include/drm/drm_bridge_helper.h
> new file mode 100644
> index 0000000000000000000000000000000000000000..6c35b479ec2a84aa43283351a6f18e49a9f9c177
> --- /dev/null
> +++ b/include/drm/drm_bridge_helper.h
> @@ -0,0 +1,12 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +#ifndef __DRM_BRIDGE_HELPER_H_
> +#define __DRM_BRIDGE_HELPER_H_
> +
> +struct drm_bridge;
> +struct drm_modeset_acquire_ctx;
> +
> +int drm_bridge_helper_reset_crtc(struct drm_bridge *bridge,
> + struct drm_modeset_acquire_ctx *ctx);
> +
> +#endif // __DRM_BRIDGE_HELPER_H_
>
> --
> 2.48.1
>
--
Simona Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable
2025-03-04 11:10 ` [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable Maxime Ripard
@ 2025-03-06 15:48 ` Simona Vetter
0 siblings, 0 replies; 52+ messages in thread
From: Simona Vetter @ 2025-03-06 15:48 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov
On Tue, Mar 04, 2025 at 12:10:57PM +0100, Maxime Ripard wrote:
> The tc358768 bridge driver, if enabling it fails, tries to disable it.
> This is pretty uncommon in bridge drivers, and also stands in the way
> for further reworks.
>
> Worse, since pre_enable and enable aren't expected to fail, disable and
> post_disable might be called twice: once to handle the failure, and once
> to actually disable the bridge.
>
> Since post_disable uses regulators and clocks, this would lead to enable
> count imbalances.
>
> In order to prevent that imbalance, and to allow further reworks, let's
> drop the calls to disable and post_disable, but keep the warning to let
> users know about what's going on.
>
> Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> Signed-off-by: Maxime Ripard <mripard@kernel.org>
Yeah proper way to clear these would be like any other link failure:
- Launch async worker to do a bridge reset with the fancy new helper.
- Set the link-status attribute if you can't automatically fix it and let
userspace sort out the mess.
Maybe we need to improve the docs a bit more?
-Sima
> ---
> drivers/gpu/drm/bridge/tc358768.c | 10 ++--------
> 1 file changed, 2 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/tc358768.c b/drivers/gpu/drm/bridge/tc358768.c
> index 6db18d1e8824dd7d387211d6d1e668645cf88bbe..6b65ba8aed86012bc0f464bd5ee44325dae677c6 100644
> --- a/drivers/gpu/drm/bridge/tc358768.c
> +++ b/drivers/gpu/drm/bridge/tc358768.c
> @@ -1075,15 +1075,12 @@ static void tc358768_bridge_pre_enable(struct drm_bridge *bridge)
> val = TC358768_DSI_CONFW_MODE_CLR | TC358768_DSI_CONFW_ADDR_DSI_CONTROL;
> val |= TC358768_DSI_CONTROL_DIS_MODE; /* DSI mode */
> tc358768_write(priv, TC358768_DSI_CONFW, val);
>
> ret = tc358768_clear_error(priv);
> - if (ret) {
> + if (ret)
> dev_err(dev, "Bridge pre_enable failed: %d\n", ret);
> - tc358768_bridge_disable(bridge);
> - tc358768_bridge_post_disable(bridge);
> - }
> }
>
> static void tc358768_bridge_enable(struct drm_bridge *bridge)
> {
> struct tc358768_priv *priv = bridge_to_tc358768(bridge);
> @@ -1099,15 +1096,12 @@ static void tc358768_bridge_enable(struct drm_bridge *bridge)
>
> /* set PP_en */
> tc358768_update_bits(priv, TC358768_CONFCTL, BIT(6), BIT(6));
>
> ret = tc358768_clear_error(priv);
> - if (ret) {
> + if (ret)
> dev_err(priv->dev, "Bridge enable failed: %d\n", ret);
> - tc358768_bridge_disable(bridge);
> - tc358768_bridge_post_disable(bridge);
> - }
> }
>
> #define MAX_INPUT_SEL_FORMATS 1
>
> static u32 *
>
> --
> 2.48.1
>
--
Simona Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-06 15:41 ` Simona Vetter
@ 2025-03-07 1:08 ` Andy Yan
2025-03-07 7:30 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-03-07 1:08 UTC (permalink / raw)
To: Simona Vetter
Cc: Maxime Ripard, Dmitry Baryshkov, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Douglas Anderson, Herve Codina, dri-devel,
linux-kernel
Hi All,
At 2025-03-06 23:41:24, "Simona Vetter" <simona.vetter@ffwll.ch> wrote:
>On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote:
>> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
>> >
>> > Hi Maxime and Dmitry:
>> >
>> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
>> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
>> > >> Hi Andy,
>> > >>
>> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
>> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > >> > >With the bridges switching over to drm_bridge_connector, the direct
>> > >> > >association between a bridge driver and its connector was lost.
>> > >> > >
>> > >> > >This is mitigated for atomic bridge drivers by the fact you can access
>> > >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> > >> > >
>> > >> > >This was also made easier by providing drm_atomic_state directly to all
>> > >> > >atomic hooks bridges can implement.
>> > >> > >
>> > >> > >However, bridge drivers don't have a way to access drm_atomic_state
>> > >> > >outside of the modeset path, like from the hotplug interrupt path or any
>> > >> > >interrupt handler.
>> > >> > >
>> > >> > >Let's introduce a function to retrieve the connector currently assigned
>> > >> > >to an encoder, without using drm_atomic_state, to make these drivers'
>> > >> > >life easier.
>> > >> > >
>> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> > >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> > >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> > >> > >---
>> > >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> > >> > > include/drm/drm_atomic.h | 3 +++
>> > >> > > 2 files changed, 48 insertions(+)
>> > >> > >
>> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> > >> > >--- a/drivers/gpu/drm/drm_atomic.c
>> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c
>> > >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> > >> > >
>> > >> > > return NULL;
>> > >> > > }
>> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> > >> > >
>> > >> > >+/**
>> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> > >> > >+ * @encoder: The encoder to find the connector of
>> > >> > >+ * @ctx: Modeset locking context
>> > >> > >+ *
>> > >> > >+ * This function finds and returns the connector currently assigned to
>> > >> > >+ * an @encoder.
>> > >> > >+ *
>> > >> > >+ * Returns:
>> > >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
>> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
>> > >> > >+ * sequence must be restarted.
>> > >> > >+ */
>> > >> > >+struct drm_connector *
>> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> > >> > >+ struct drm_modeset_acquire_ctx *ctx)
>> > >> > >+{
>> > >> > >+ struct drm_connector_list_iter conn_iter;
>> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> > >> > >+ struct drm_connector *connector;
>> > >> > >+ struct drm_device *dev = encoder->dev;
>> > >> > >+ int ret;
>> > >> > >+
>> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > >> > >+ if (ret)
>> > >> > >+ return ERR_PTR(ret);
>> > >> >
>> > >> > It seems that this will cause a deadlock when called from a hotplug
>> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
>> > >> > use this API from a &drm_bridge_funcs.detect callback to get the
>> > >> > connector, as detect is called by drm_helper_probe_detect, which will
>> > >> > hold connection_mutex first, so the deaklock happens:
>> > >> >
>> > >> > drm_helper_probe_detect(struct drm_connector *connector,
>> > >> > struct drm_modeset_acquire_ctx *ctx,
>> > >> > bool force)
>> > >> > {
>> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > >> > struct drm_device *dev = connector->dev;
>> > >> > int ret;
>> > >> >
>> > >> > if (!ctx)
>> > >> > return drm_helper_probe_detect_ctx(connector, force);
>> > >> >
>> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > >> > if (ret)
>> > >> > return ret;
>> > >> >
>> > >> > if (funcs->detect_ctx)
>> > >> > ret = funcs->detect_ctx(connector, ctx, force);
>> > >> > else if (connector->funcs->detect)
>> > >> > ret = connector->funcs->detect(connector, force);
>> > >> > else
>> > >> > ret = connector_status_connected;
>> > >> >
>> > >> > if (ret != connector->status)
>> > >> > connector->epoch_counter += 1;
>> > >> >
>> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
>> > >> > this case ?
>> > >>
>> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
>> > >> fine with reentrancy from the same context, so it should work just fine.
>> > >
>> > >Andy, that probably means that you should use .detect_ctx() and pass the
>> > >context to drm_atomic_get_connector_for_encoder().
>> >
>> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
>> > The call chain is:
>> > drm_helper_probe_detect
>> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>> > --> drm_bridge_funcs.detect(bridge)
>> > The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
>> > The connector got dropped when connector call it's bridege.detect
>> >
>> > So I think the simplest solution is to have drm_bridge_funcs.detect
>> > directly pass the connector
>>
>> I don't disagree on principle, but I think a better first step would be
>> to provide a detect_ctx hook to bridges.
>
>Yup. There's other reasons you really want to get at the locking context
>in detect callbacks, doing this special case by passing something for
>everyone doesn't sound like the right approach to me.
Ok, I will add a detect_ctx hook for bridge. Thanks for your advice.
Just confirm that can I send this add detect_ctx hook patch alone first?
I think this patch will be easy to merge, so it can help my WIP DP driver stay light on dependencies。
>-Sima
>--
>Simona Vetter
>Software Engineer, Intel Corporation
>http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-07 1:08 ` Andy Yan
@ 2025-03-07 7:30 ` Andy Yan
2025-03-07 13:25 ` Simona Vetter
0 siblings, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-03-07 7:30 UTC (permalink / raw)
To: Simona Vetter
Cc: Maxime Ripard, Dmitry Baryshkov, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Douglas Anderson, Herve Codina, dri-devel,
linux-kernel
Hi All,
At 2025-03-07 09:08:48, "Andy Yan" <andyshrk@163.com> wrote:
>Hi All,
>
>At 2025-03-06 23:41:24, "Simona Vetter" <simona.vetter@ffwll.ch> wrote:
>>On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote:
>>> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
>>> >
>>> > Hi Maxime and Dmitry:
>>> >
>>> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
>>> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
>>> > >> Hi Andy,
>>> > >>
>>> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
>>> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>>> > >> > >With the bridges switching over to drm_bridge_connector, the direct
>>> > >> > >association between a bridge driver and its connector was lost.
>>> > >> > >
>>> > >> > >This is mitigated for atomic bridge drivers by the fact you can access
>>> > >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>>> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>>> > >> > >
>>> > >> > >This was also made easier by providing drm_atomic_state directly to all
>>> > >> > >atomic hooks bridges can implement.
>>> > >> > >
>>> > >> > >However, bridge drivers don't have a way to access drm_atomic_state
>>> > >> > >outside of the modeset path, like from the hotplug interrupt path or any
>>> > >> > >interrupt handler.
>>> > >> > >
>>> > >> > >Let's introduce a function to retrieve the connector currently assigned
>>> > >> > >to an encoder, without using drm_atomic_state, to make these drivers'
>>> > >> > >life easier.
>>> > >> > >
>>> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>> > >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>>> > >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
>>> > >> > >---
>>> > >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>>> > >> > > include/drm/drm_atomic.h | 3 +++
>>> > >> > > 2 files changed, 48 insertions(+)
>>> > >> > >
>>> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>>> > >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>>> > >> > >--- a/drivers/gpu/drm/drm_atomic.c
>>> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c
>>> > >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>>> > >> > >
>>> > >> > > return NULL;
>>> > >> > > }
>>> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>>> > >> > >
>>> > >> > >+/**
>>> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>>> > >> > >+ * @encoder: The encoder to find the connector of
>>> > >> > >+ * @ctx: Modeset locking context
>>> > >> > >+ *
>>> > >> > >+ * This function finds and returns the connector currently assigned to
>>> > >> > >+ * an @encoder.
>>> > >> > >+ *
>>> > >> > >+ * Returns:
>>> > >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
>>> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
>>> > >> > >+ * sequence must be restarted.
>>> > >> > >+ */
>>> > >> > >+struct drm_connector *
>>> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>>> > >> > >+ struct drm_modeset_acquire_ctx *ctx)
>>> > >> > >+{
>>> > >> > >+ struct drm_connector_list_iter conn_iter;
>>> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>>> > >> > >+ struct drm_connector *connector;
>>> > >> > >+ struct drm_device *dev = encoder->dev;
>>> > >> > >+ int ret;
>>> > >> > >+
>>> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>>> > >> > >+ if (ret)
>>> > >> > >+ return ERR_PTR(ret);
>>> > >> >
>>> > >> > It seems that this will cause a deadlock when called from a hotplug
>>> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
>>> > >> > use this API from a &drm_bridge_funcs.detect callback to get the
>>> > >> > connector, as detect is called by drm_helper_probe_detect, which will
>>> > >> > hold connection_mutex first, so the deaklock happens:
>>> > >> >
>>> > >> > drm_helper_probe_detect(struct drm_connector *connector,
>>> > >> > struct drm_modeset_acquire_ctx *ctx,
>>> > >> > bool force)
>>> > >> > {
>>> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>>> > >> > struct drm_device *dev = connector->dev;
>>> > >> > int ret;
>>> > >> >
>>> > >> > if (!ctx)
>>> > >> > return drm_helper_probe_detect_ctx(connector, force);
>>> > >> >
>>> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>>> > >> > if (ret)
>>> > >> > return ret;
>>> > >> >
>>> > >> > if (funcs->detect_ctx)
>>> > >> > ret = funcs->detect_ctx(connector, ctx, force);
>>> > >> > else if (connector->funcs->detect)
>>> > >> > ret = connector->funcs->detect(connector, force);
>>> > >> > else
>>> > >> > ret = connector_status_connected;
>>> > >> >
>>> > >> > if (ret != connector->status)
>>> > >> > connector->epoch_counter += 1;
>>> > >> >
>>> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
>>> > >> > this case ?
>>> > >>
>>> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
>>> > >> fine with reentrancy from the same context, so it should work just fine.
>>> > >
>>> > >Andy, that probably means that you should use .detect_ctx() and pass the
>>> > >context to drm_atomic_get_connector_for_encoder().
>>> >
>>> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
>>> > The call chain is:
>>> > drm_helper_probe_detect
>>> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>>> > --> drm_bridge_funcs.detect(bridge)
>>> > The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
>>> > The connector got dropped when connector call it's bridege.detect
>>> >
>>> > So I think the simplest solution is to have drm_bridge_funcs.detect
>>> > directly pass the connector
>>>
>>> I don't disagree on principle, but I think a better first step would be
>>> to provide a detect_ctx hook to bridges.
>>
>>Yup. There's other reasons you really want to get at the locking context
>>in detect callbacks, doing this special case by passing something for
>>everyone doesn't sound like the right approach to me.
>
>Ok, I will add a detect_ctx hook for bridge. Thanks for your advice.
>
>Just confirm that can I send this add detect_ctx hook patch alone first?
>I think this patch will be easy to merge, so it can help my WIP DP driver stay light on dependencies。
When I try to add the detect_ctx hook to bridge, I found that there is still a case that there is no ctx to
pass to detect_ctx:
int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
uint32_t maxX, uint32_t maxY)
{
...............
struct drm_modeset_acquire_ctx ctx;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
drm_modeset_acquire_init(&ctx, 0);
drm_dbg_kms(dev, "[CONNECTOR:%d:%s]\n", connector->base.id,
connector->name);
retry:
ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);
...................
ret = drm_helper_probe_detect(connector, &ctx, true);
......................................
count = drm_helper_probe_get_modes(connector);
Then in drm_bridge_connector_get_modes:
static int drm_bridge_connector_get_modes(struct drm_connector *connector)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
struct drm_bridge *bridge;
...........................................
/*
* If display exposes EDID, then we parse that in the normal way to
* build table of supported modes.
*/
bridge = bridge_connector->bridge_edid;
if (bridge)
return drm_bridge_connector_get_modes_edid(connector, bridge);
static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
struct drm_bridge *bridge)
{
enum drm_connector_status status;
const struct drm_edid *drm_edid;
int n;
status = drm_bridge_connector_detect(connector, false);
......................
-drm_bridge_connector_detect(struct drm_connector *connector, bool force)
+drm_bridge_connector_detect(struct drm_connector *connector,
+ struct drm_modeset_acquire_ctx *ctx,
+ bool force)
{
struct drm_bridge_connector *bridge_connector =
to_drm_bridge_connector(connector);
@@ -186,7 +188,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force)
enum drm_connector_status status;
if (detect) {
status = detect->funcs->detect(detect, ctx);
There is still no ctx in this call chain.
So there will be deadlock if I use drm_atomic_get_new_connector_for_encoder to find connector in
my bridge detect_ctx hook.
>
>
>>-Sima
>>--
>>Simona Vetter
>>Software Engineer, Intel Corporation
>>http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-07 7:30 ` Andy Yan
@ 2025-03-07 13:25 ` Simona Vetter
2025-03-11 6:42 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Simona Vetter @ 2025-03-07 13:25 UTC (permalink / raw)
To: Andy Yan
Cc: Simona Vetter, Maxime Ripard, Dmitry Baryshkov, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Douglas Anderson, Herve Codina, dri-devel,
linux-kernel
On Fri, Mar 07, 2025 at 03:30:41PM +0800, Andy Yan wrote:
>
> Hi All,
> At 2025-03-07 09:08:48, "Andy Yan" <andyshrk@163.com> wrote:
> >Hi All,
> >
> >At 2025-03-06 23:41:24, "Simona Vetter" <simona.vetter@ffwll.ch> wrote:
> >>On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote:
> >>> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
> >>> >
> >>> > Hi Maxime and Dmitry:
> >>> >
> >>> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
> >>> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
> >>> > >> Hi Andy,
> >>> > >>
> >>> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
> >>> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> >>> > >> > >With the bridges switching over to drm_bridge_connector, the direct
> >>> > >> > >association between a bridge driver and its connector was lost.
> >>> > >> > >
> >>> > >> > >This is mitigated for atomic bridge drivers by the fact you can access
> >>> > >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> >>> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> >>> > >> > >
> >>> > >> > >This was also made easier by providing drm_atomic_state directly to all
> >>> > >> > >atomic hooks bridges can implement.
> >>> > >> > >
> >>> > >> > >However, bridge drivers don't have a way to access drm_atomic_state
> >>> > >> > >outside of the modeset path, like from the hotplug interrupt path or any
> >>> > >> > >interrupt handler.
> >>> > >> > >
> >>> > >> > >Let's introduce a function to retrieve the connector currently assigned
> >>> > >> > >to an encoder, without using drm_atomic_state, to make these drivers'
> >>> > >> > >life easier.
> >>> > >> > >
> >>> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>> > >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> >>> > >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
> >>> > >> > >---
> >>> > >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> >>> > >> > > include/drm/drm_atomic.h | 3 +++
> >>> > >> > > 2 files changed, 48 insertions(+)
> >>> > >> > >
> >>> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >>> > >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> >>> > >> > >--- a/drivers/gpu/drm/drm_atomic.c
> >>> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c
> >>> > >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> >>> > >> > >
> >>> > >> > > return NULL;
> >>> > >> > > }
> >>> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> >>> > >> > >
> >>> > >> > >+/**
> >>> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> >>> > >> > >+ * @encoder: The encoder to find the connector of
> >>> > >> > >+ * @ctx: Modeset locking context
> >>> > >> > >+ *
> >>> > >> > >+ * This function finds and returns the connector currently assigned to
> >>> > >> > >+ * an @encoder.
> >>> > >> > >+ *
> >>> > >> > >+ * Returns:
> >>> > >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
> >>> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
> >>> > >> > >+ * sequence must be restarted.
> >>> > >> > >+ */
> >>> > >> > >+struct drm_connector *
> >>> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> >>> > >> > >+ struct drm_modeset_acquire_ctx *ctx)
> >>> > >> > >+{
> >>> > >> > >+ struct drm_connector_list_iter conn_iter;
> >>> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> >>> > >> > >+ struct drm_connector *connector;
> >>> > >> > >+ struct drm_device *dev = encoder->dev;
> >>> > >> > >+ int ret;
> >>> > >> > >+
> >>> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >>> > >> > >+ if (ret)
> >>> > >> > >+ return ERR_PTR(ret);
> >>> > >> >
> >>> > >> > It seems that this will cause a deadlock when called from a hotplug
> >>> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
> >>> > >> > use this API from a &drm_bridge_funcs.detect callback to get the
> >>> > >> > connector, as detect is called by drm_helper_probe_detect, which will
> >>> > >> > hold connection_mutex first, so the deaklock happens:
> >>> > >> >
> >>> > >> > drm_helper_probe_detect(struct drm_connector *connector,
> >>> > >> > struct drm_modeset_acquire_ctx *ctx,
> >>> > >> > bool force)
> >>> > >> > {
> >>> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> >>> > >> > struct drm_device *dev = connector->dev;
> >>> > >> > int ret;
> >>> > >> >
> >>> > >> > if (!ctx)
> >>> > >> > return drm_helper_probe_detect_ctx(connector, force);
> >>> > >> >
> >>> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >>> > >> > if (ret)
> >>> > >> > return ret;
> >>> > >> >
> >>> > >> > if (funcs->detect_ctx)
> >>> > >> > ret = funcs->detect_ctx(connector, ctx, force);
> >>> > >> > else if (connector->funcs->detect)
> >>> > >> > ret = connector->funcs->detect(connector, force);
> >>> > >> > else
> >>> > >> > ret = connector_status_connected;
> >>> > >> >
> >>> > >> > if (ret != connector->status)
> >>> > >> > connector->epoch_counter += 1;
> >>> > >> >
> >>> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
> >>> > >> > this case ?
> >>> > >>
> >>> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
> >>> > >> fine with reentrancy from the same context, so it should work just fine.
> >>> > >
> >>> > >Andy, that probably means that you should use .detect_ctx() and pass the
> >>> > >context to drm_atomic_get_connector_for_encoder().
> >>> >
> >>> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
> >>> > The call chain is:
> >>> > drm_helper_probe_detect
> >>> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
> >>> > --> drm_bridge_funcs.detect(bridge)
> >>> > The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
> >>> > The connector got dropped when connector call it's bridege.detect
> >>> >
> >>> > So I think the simplest solution is to have drm_bridge_funcs.detect
> >>> > directly pass the connector
> >>>
> >>> I don't disagree on principle, but I think a better first step would be
> >>> to provide a detect_ctx hook to bridges.
> >>
> >>Yup. There's other reasons you really want to get at the locking context
> >>in detect callbacks, doing this special case by passing something for
> >>everyone doesn't sound like the right approach to me.
> >
> >Ok, I will add a detect_ctx hook for bridge. Thanks for your advice.
> >
> >Just confirm that can I send this add detect_ctx hook patch alone first?
> >I think this patch will be easy to merge, so it can help my WIP DP driver stay light on dependencies。
Yeah I think sending this prep work as a standalone thing is ok,
especially since it looks like there's going to be more work involved.
> When I try to add the detect_ctx hook to bridge, I found that there is still a case that there is no ctx to
> pass to detect_ctx:
>
> int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
> uint32_t maxX, uint32_t maxY)
> {
> ...............
> struct drm_modeset_acquire_ctx ctx;
>
> WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
>
> drm_modeset_acquire_init(&ctx, 0);
>
> drm_dbg_kms(dev, "[CONNECTOR:%d:%s]\n", connector->base.id,
> connector->name);
>
> retry:
> ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);
> ...................
> ret = drm_helper_probe_detect(connector, &ctx, true);
> ......................................
>
> count = drm_helper_probe_get_modes(connector);
>
> Then in drm_bridge_connector_get_modes:
>
> static int drm_bridge_connector_get_modes(struct drm_connector *connector)
> {
> struct drm_bridge_connector *bridge_connector =
> to_drm_bridge_connector(connector);
> struct drm_bridge *bridge;
>
> ...........................................
> /*
> * If display exposes EDID, then we parse that in the normal way to
> * build table of supported modes.
> */
> bridge = bridge_connector->bridge_edid;
> if (bridge)
> return drm_bridge_connector_get_modes_edid(connector, bridge);
>
> static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
> struct drm_bridge *bridge)
> {
> enum drm_connector_status status;
> const struct drm_edid *drm_edid;
> int n;
>
> status = drm_bridge_connector_detect(connector, false);
>
> ......................
>
> -drm_bridge_connector_detect(struct drm_connector *connector, bool force)
> +drm_bridge_connector_detect(struct drm_connector *connector,
> + struct drm_modeset_acquire_ctx *ctx,
> + bool force)
> {
> struct drm_bridge_connector *bridge_connector =
> to_drm_bridge_connector(connector);
> @@ -186,7 +188,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force)
> enum drm_connector_status status;
>
> if (detect) {
> status = detect->funcs->detect(detect, ctx);
>
> There is still no ctx in this call chain.
>
> So there will be deadlock if I use drm_atomic_get_new_connector_for_encoder to find connector in
> my bridge detect_ctx hook.
Hm yeah looks like bridge callchain isn't split up into ->detec and
->get_modes in exactly the same way as connectors. I think the clean
solution would be to pull drm_bridge_connector_detect() out from
drm_bridge_connector_get_modes(), but that might unravel a huge amount of
work. But wiring the ctx through all the get_mode functions might also not
work out great, hence why I'd try moving _detect() first.
Once you have bridge_connector_detect at the same split-up like any other
connectors, it should be possible to add the contect to
drm_bridge_connector_detect and have it everywhere. In general I think
calling drm_bridge_connector_detect with a NULL ctx should be a bug, and
we should catch that with a WARN_ON and bail out. Otherwise the locking is
going to be a complete mess.
And yeah definitely do this prep work as a separate series, I think the
need is clearly established, so we don't need a user right away to justify
this rework.
Cheers, Sima
>
>
>
> >
> >
> >>-Sima
> >>--
> >>Simona Vetter
> >>Software Engineer, Intel Corporation
> >>http://blog.ffwll.ch
--
Simona Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-07 13:25 ` Simona Vetter
@ 2025-03-11 6:42 ` Andy Yan
0 siblings, 0 replies; 52+ messages in thread
From: Andy Yan @ 2025-03-11 6:42 UTC (permalink / raw)
To: Simona Vetter
Cc: Maxime Ripard, Dmitry Baryshkov, Maarten Lankhorst,
Thomas Zimmermann, David Airlie, Simona Vetter, Andrzej Hajda,
Neil Armstrong, Robert Foss, Laurent Pinchart, Jonas Karlman,
Jernej Skrabec, Douglas Anderson, Herve Codina, dri-devel,
linux-kernel
Hi Simona and Laurent,
At 2025-03-07 21:25:02, "Simona Vetter" <simona.vetter@ffwll.ch> wrote:
>On Fri, Mar 07, 2025 at 03:30:41PM +0800, Andy Yan wrote:
>>
>> Hi All,
>> At 2025-03-07 09:08:48, "Andy Yan" <andyshrk@163.com> wrote:
>> >Hi All,
>> >
>> >At 2025-03-06 23:41:24, "Simona Vetter" <simona.vetter@ffwll.ch> wrote:
>> >>On Thu, Mar 06, 2025 at 08:10:16AM +0100, Maxime Ripard wrote:
>> >>> On Thu, Mar 06, 2025 at 09:16:24AM +0800, Andy Yan wrote:
>> >>> >
>> >>> > Hi Maxime and Dmitry:
>> >>> >
>> >>> > At 2025-03-06 04:13:53, "Dmitry Baryshkov" <dmitry.baryshkov@linaro.org> wrote:
>> >>> > >On Wed, Mar 05, 2025 at 02:19:36PM +0100, Maxime Ripard wrote:
>> >>> > >> Hi Andy,
>> >>> > >>
>> >>> > >> On Wed, Mar 05, 2025 at 07:55:19PM +0800, Andy Yan wrote:
>> >>> > >> > At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> >>> > >> > >With the bridges switching over to drm_bridge_connector, the direct
>> >>> > >> > >association between a bridge driver and its connector was lost.
>> >>> > >> > >
>> >>> > >> > >This is mitigated for atomic bridge drivers by the fact you can access
>> >>> > >> > >the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> >>> > >> > >drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> >>> > >> > >
>> >>> > >> > >This was also made easier by providing drm_atomic_state directly to all
>> >>> > >> > >atomic hooks bridges can implement.
>> >>> > >> > >
>> >>> > >> > >However, bridge drivers don't have a way to access drm_atomic_state
>> >>> > >> > >outside of the modeset path, like from the hotplug interrupt path or any
>> >>> > >> > >interrupt handler.
>> >>> > >> > >
>> >>> > >> > >Let's introduce a function to retrieve the connector currently assigned
>> >>> > >> > >to an encoder, without using drm_atomic_state, to make these drivers'
>> >>> > >> > >life easier.
>> >>> > >> > >
>> >>> > >> > >Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> >>> > >> > >Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> >>> > >> > >Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> >>> > >> > >---
>> >>> > >> > > drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> >>> > >> > > include/drm/drm_atomic.h | 3 +++
>> >>> > >> > > 2 files changed, 48 insertions(+)
>> >>> > >> > >
>> >>> > >> > >diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> >>> > >> > >index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> >>> > >> > >--- a/drivers/gpu/drm/drm_atomic.c
>> >>> > >> > >+++ b/drivers/gpu/drm/drm_atomic.c
>> >>> > >> > >@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> >>> > >> > >
>> >>> > >> > > return NULL;
>> >>> > >> > > }
>> >>> > >> > > EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> >>> > >> > >
>> >>> > >> > >+/**
>> >>> > >> > >+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> >>> > >> > >+ * @encoder: The encoder to find the connector of
>> >>> > >> > >+ * @ctx: Modeset locking context
>> >>> > >> > >+ *
>> >>> > >> > >+ * This function finds and returns the connector currently assigned to
>> >>> > >> > >+ * an @encoder.
>> >>> > >> > >+ *
>> >>> > >> > >+ * Returns:
>> >>> > >> > >+ * The connector connected to @encoder, or an error pointer otherwise.
>> >>> > >> > >+ * When the error is EDEADLK, a deadlock has been detected and the
>> >>> > >> > >+ * sequence must be restarted.
>> >>> > >> > >+ */
>> >>> > >> > >+struct drm_connector *
>> >>> > >> > >+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> >>> > >> > >+ struct drm_modeset_acquire_ctx *ctx)
>> >>> > >> > >+{
>> >>> > >> > >+ struct drm_connector_list_iter conn_iter;
>> >>> > >> > >+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> >>> > >> > >+ struct drm_connector *connector;
>> >>> > >> > >+ struct drm_device *dev = encoder->dev;
>> >>> > >> > >+ int ret;
>> >>> > >> > >+
>> >>> > >> > >+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> >>> > >> > >+ if (ret)
>> >>> > >> > >+ return ERR_PTR(ret);
>> >>> > >> >
>> >>> > >> > It seems that this will cause a deadlock when called from a hotplug
>> >>> > >> > handling path, I have a WIP DP diver[0], which suggested by Dmitry to
>> >>> > >> > use this API from a &drm_bridge_funcs.detect callback to get the
>> >>> > >> > connector, as detect is called by drm_helper_probe_detect, which will
>> >>> > >> > hold connection_mutex first, so the deaklock happens:
>> >>> > >> >
>> >>> > >> > drm_helper_probe_detect(struct drm_connector *connector,
>> >>> > >> > struct drm_modeset_acquire_ctx *ctx,
>> >>> > >> > bool force)
>> >>> > >> > {
>> >>> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> >>> > >> > struct drm_device *dev = connector->dev;
>> >>> > >> > int ret;
>> >>> > >> >
>> >>> > >> > if (!ctx)
>> >>> > >> > return drm_helper_probe_detect_ctx(connector, force);
>> >>> > >> >
>> >>> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> >>> > >> > if (ret)
>> >>> > >> > return ret;
>> >>> > >> >
>> >>> > >> > if (funcs->detect_ctx)
>> >>> > >> > ret = funcs->detect_ctx(connector, ctx, force);
>> >>> > >> > else if (connector->funcs->detect)
>> >>> > >> > ret = connector->funcs->detect(connector, force);
>> >>> > >> > else
>> >>> > >> > ret = connector_status_connected;
>> >>> > >> >
>> >>> > >> > if (ret != connector->status)
>> >>> > >> > connector->epoch_counter += 1;
>> >>> > >> >
>> >>> > >> > So I wonder can we let drm_bridge_funcs.detect pass a connector for
>> >>> > >> > this case ?
>> >>> > >>
>> >>> > >> Do you actually see a deadlock occurring? AFAIK, drm_modeset_lock is
>> >>> > >> fine with reentrancy from the same context, so it should work just fine.
>> >>> > >
>> >>> > >Andy, that probably means that you should use .detect_ctx() and pass the
>> >>> > >context to drm_atomic_get_connector_for_encoder().
>> >>> >
>> >>> > Unfortunately, the drm_bridge_funcs does not have a .detect_ctx() version .
>> >>> > The call chain is:
>> >>> > drm_helper_probe_detect
>> >>> > --> drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>> >>> > --> drm_bridge_funcs.detect(bridge)
>> >>> > The ctx got dropped when drm_helper_probe_detect call drm_bridge_connector_detect
>> >>> > The connector got dropped when connector call it's bridege.detect
>> >>> >
>> >>> > So I think the simplest solution is to have drm_bridge_funcs.detect
>> >>> > directly pass the connector
>> >>>
>> >>> I don't disagree on principle, but I think a better first step would be
>> >>> to provide a detect_ctx hook to bridges.
>> >>
>> >>Yup. There's other reasons you really want to get at the locking context
>> >>in detect callbacks, doing this special case by passing something for
>> >>everyone doesn't sound like the right approach to me.
>> >
>> >Ok, I will add a detect_ctx hook for bridge. Thanks for your advice.
>> >
>> >Just confirm that can I send this add detect_ctx hook patch alone first?
>> >I think this patch will be easy to merge, so it can help my WIP DP driver stay light on dependencies。
>
>Yeah I think sending this prep work as a standalone thing is ok,
>especially since it looks like there's going to be more work involved.
>
>> When I try to add the detect_ctx hook to bridge, I found that there is still a case that there is no ctx to
>> pass to detect_ctx:
>>
>> int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
>> uint32_t maxX, uint32_t maxY)
>> {
>> ...............
>> struct drm_modeset_acquire_ctx ctx;
>>
>> WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
>>
>> drm_modeset_acquire_init(&ctx, 0);
>>
>> drm_dbg_kms(dev, "[CONNECTOR:%d:%s]\n", connector->base.id,
>> connector->name);
>>
>> retry:
>> ret = drm_modeset_lock(&dev->mode_config.connection_mutex, &ctx);
>> ...................
>> ret = drm_helper_probe_detect(connector, &ctx, true);
>> ......................................
>>
>> count = drm_helper_probe_get_modes(connector);
>>
>> Then in drm_bridge_connector_get_modes:
>>
>> static int drm_bridge_connector_get_modes(struct drm_connector *connector)
>> {
>> struct drm_bridge_connector *bridge_connector =
>> to_drm_bridge_connector(connector);
>> struct drm_bridge *bridge;
>>
>> ...........................................
>> /*
>> * If display exposes EDID, then we parse that in the normal way to
>> * build table of supported modes.
>> */
>> bridge = bridge_connector->bridge_edid;
>> if (bridge)
>> return drm_bridge_connector_get_modes_edid(connector, bridge);
>>
>> static int drm_bridge_connector_get_modes_edid(struct drm_connector *connector,
>> struct drm_bridge *bridge)
>> {
>> enum drm_connector_status status;
>> const struct drm_edid *drm_edid;
>> int n;
>>
>> status = drm_bridge_connector_detect(connector, false);
>>
>> ......................
>>
>> -drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>> +drm_bridge_connector_detect(struct drm_connector *connector,
>> + struct drm_modeset_acquire_ctx *ctx,
>> + bool force)
>> {
>> struct drm_bridge_connector *bridge_connector =
>> to_drm_bridge_connector(connector);
>> @@ -186,7 +188,7 @@ drm_bridge_connector_detect(struct drm_connector *connector, bool force)
>> enum drm_connector_status status;
>>
>> if (detect) {
>> status = detect->funcs->detect(detect, ctx);
>>
>> There is still no ctx in this call chain.
>>
>> So there will be deadlock if I use drm_atomic_get_new_connector_for_encoder to find connector in
>> my bridge detect_ctx hook.
>
>Hm yeah looks like bridge callchain isn't split up into ->detec and
>->get_modes in exactly the same way as connectors. I think the clean
>solution would be to pull drm_bridge_connector_detect() out from
>drm_bridge_connector_get_modes(), but that might unravel a huge amount of
>work. But wiring the ctx through all the get_mode functions might also not
>work out great, hence why I'd try moving _detect() first.
Since drm_connector_helper_funcs.get_modes is called by drm_helper_probe_single_connector_modes,
which already called drm_helper_probe_detect to make sure the connector is at connected state, so
Can we directly remove drm_bridge_connector_detect within drm_bridge_connector_get_modes_edid?
>
>Once you have bridge_connector_detect at the same split-up like any other
>connectors, it should be possible to add the contect to
>drm_bridge_connector_detect and have it everywhere. In general I think
>calling drm_bridge_connector_detect with a NULL ctx should be a bug, and
>we should catch that with a WARN_ON and bail out. Otherwise the locking is
>going to be a complete mess.
>
>And yeah definitely do this prep work as a separate series, I think the
>need is clearly established, so we don't need a user right away to justify
>this rework.
>
>Cheers, Sima
>>
>>
>>
>> >
>> >
>> >>-Sima
>> >>--
>> >>Simona Vetter
>> >>Software Engineer, Intel Corporation
>> >>http://blog.ffwll.ch
>
>--
>Simona Vetter
>Software Engineer, Intel Corporation
>http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re:[PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-05 11:55 ` Andy Yan
2025-03-05 13:19 ` [PATCH " Maxime Ripard
@ 2025-03-13 8:09 ` Andy Yan
2025-03-13 11:55 ` [PATCH " Maxime Ripard
1 sibling, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-03-13 8:09 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter, lumag
Hi Maxime,
At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
>
>
>Hi Maxime,
>
>At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>>With the bridges switching over to drm_bridge_connector, the direct
>>association between a bridge driver and its connector was lost.
>>
>>This is mitigated for atomic bridge drivers by the fact you can access
>>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>>
>>This was also made easier by providing drm_atomic_state directly to all
>>atomic hooks bridges can implement.
>>
>>However, bridge drivers don't have a way to access drm_atomic_state
>>outside of the modeset path, like from the hotplug interrupt path or any
>>interrupt handler.
>>
>>Let's introduce a function to retrieve the connector currently assigned
>>to an encoder, without using drm_atomic_state, to make these drivers'
>>life easier.
>>
>>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>>---
>> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> include/drm/drm_atomic.h | 3 +++
>> 2 files changed, 48 insertions(+)
>>
>>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>>--- a/drivers/gpu/drm/drm_atomic.c
>>+++ b/drivers/gpu/drm/drm_atomic.c
>>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>>
>> return NULL;
>> }
>> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>>
>>+/**
>>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>>+ * @encoder: The encoder to find the connector of
>>+ * @ctx: Modeset locking context
>>+ *
>>+ * This function finds and returns the connector currently assigned to
>>+ * an @encoder.
>>+ *
>>+ * Returns:
>>+ * The connector connected to @encoder, or an error pointer otherwise.
>>+ * When the error is EDEADLK, a deadlock has been detected and the
>>+ * sequence must be restarted.
>>+ */
>>+struct drm_connector *
>>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>>+ struct drm_modeset_acquire_ctx *ctx)
>>+{
>>+ struct drm_connector_list_iter conn_iter;
>>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>>+ struct drm_connector *connector;
>>+ struct drm_device *dev = encoder->dev;
>>+ int ret;
>>+
>>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>>+ if (ret)
>>+ return ERR_PTR(ret);
>
>It seems that this will cause a deadlock when called from a hotplug handling path,
>I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
>&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
>which will hold connection_mutex first, so the deaklock happens:
>
>
>drm_helper_probe_detect(struct drm_connector *connector,
> struct drm_modeset_acquire_ctx *ctx,
> bool force)
>{
> const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> struct drm_device *dev = connector->dev;
> int ret;
>
> if (!ctx)
> return drm_helper_probe_detect_ctx(connector, force);
>
> ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> if (ret)
> return ret;
>
> if (funcs->detect_ctx)
> ret = funcs->detect_ctx(connector, ctx, force);
> else if (connector->funcs->detect)
> ret = connector->funcs->detect(connector, force);
> else
> ret = connector_status_connected;
>
> if (ret != connector->status)
> connector->epoch_counter += 1;
>
>So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
>
>
>
>[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>>+
>>+ drm_connector_list_iter_begin(dev, &conn_iter);
>>+ drm_for_each_connector_iter(connector, &conn_iter) {
>>+ if (!connector->state)
>>+ continue;
>>+
>>+ if (encoder == connector->state->best_encoder) {
>>+ out_connector = connector;
When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
[ 52.713030] Invalid return value -22 for connector detection
[ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
0x63c
[ 52.714568] Modules linked in:
[ 52.724546] Call trace:
[ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
[ 52.725319] drm_mode_getconnector+0x2a4/0x488
[ 52.725711] drm_ioctl_kernel+0xb4/0x11c
[ 52.726057] drm_ioctl+0x22c/0x544
[ 52.726358] __arm64_sys_ioctl+0xac/0xe0
[ 52.726706] invoke_syscall+0x44/0x100
[ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
This is because best_encoder is set by set_best_encoder, which is called from
drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
for the first time, the functions mentioned above have not been called yet,
then we can't match the encoder from connector->state->best_encoder for this case.
>>+ break;
>>+ }
>>+ }
>>+ drm_connector_list_iter_end(&conn_iter);
>>+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
>>+
>>+ return out_connector;
>>+}
>>+EXPORT_SYMBOL(drm_atomic_get_connector_for_encoder);
>>+
>>+
>> /**
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-13 8:09 ` Andy Yan
@ 2025-03-13 11:55 ` Maxime Ripard
2025-03-14 0:50 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-13 11:55 UTC (permalink / raw)
To: Andy Yan
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter, lumag
[-- Attachment #1: Type: text/plain, Size: 6171 bytes --]
Hi,
On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> >>With the bridges switching over to drm_bridge_connector, the direct
> >>association between a bridge driver and its connector was lost.
> >>
> >>This is mitigated for atomic bridge drivers by the fact you can access
> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> >>
> >>This was also made easier by providing drm_atomic_state directly to all
> >>atomic hooks bridges can implement.
> >>
> >>However, bridge drivers don't have a way to access drm_atomic_state
> >>outside of the modeset path, like from the hotplug interrupt path or any
> >>interrupt handler.
> >>
> >>Let's introduce a function to retrieve the connector currently assigned
> >>to an encoder, without using drm_atomic_state, to make these drivers'
> >>life easier.
> >>
> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> >>---
> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> >> include/drm/drm_atomic.h | 3 +++
> >> 2 files changed, 48 insertions(+)
> >>
> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> >>--- a/drivers/gpu/drm/drm_atomic.c
> >>+++ b/drivers/gpu/drm/drm_atomic.c
> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> >>
> >> return NULL;
> >> }
> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> >>
> >>+/**
> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> >>+ * @encoder: The encoder to find the connector of
> >>+ * @ctx: Modeset locking context
> >>+ *
> >>+ * This function finds and returns the connector currently assigned to
> >>+ * an @encoder.
> >>+ *
> >>+ * Returns:
> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> >>+ * sequence must be restarted.
> >>+ */
> >>+struct drm_connector *
> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> >>+ struct drm_modeset_acquire_ctx *ctx)
> >>+{
> >>+ struct drm_connector_list_iter conn_iter;
> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> >>+ struct drm_connector *connector;
> >>+ struct drm_device *dev = encoder->dev;
> >>+ int ret;
> >>+
> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >>+ if (ret)
> >>+ return ERR_PTR(ret);
> >
> >It seems that this will cause a deadlock when called from a hotplug handling path,
> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> >which will hold connection_mutex first, so the deaklock happens:
> >
> >
> >drm_helper_probe_detect(struct drm_connector *connector,
> > struct drm_modeset_acquire_ctx *ctx,
> > bool force)
> >{
> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > struct drm_device *dev = connector->dev;
> > int ret;
> >
> > if (!ctx)
> > return drm_helper_probe_detect_ctx(connector, force);
> >
> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > if (ret)
> > return ret;
> >
> > if (funcs->detect_ctx)
> > ret = funcs->detect_ctx(connector, ctx, force);
> > else if (connector->funcs->detect)
> > ret = connector->funcs->detect(connector, force);
> > else
> > ret = connector_status_connected;
> >
> > if (ret != connector->status)
> > connector->epoch_counter += 1;
> >
> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> >
> >
> >
> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> >>+
> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> >>+ if (!connector->state)
> >>+ continue;
> >>+
> >>+ if (encoder == connector->state->best_encoder) {
> >>+ out_connector = connector;
>
>
> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
>
> [ 52.713030] Invalid return value -22 for connector detection
> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> 0x63c
> [ 52.714568] Modules linked in:
>
> [ 52.724546] Call trace:
> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> [ 52.726057] drm_ioctl+0x22c/0x544
> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> [ 52.726706] invoke_syscall+0x44/0x100
> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
>
> This is because best_encoder is set by set_best_encoder, which is called from
> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> for the first time, the functions mentioned above have not been called yet,
> then we can't match the encoder from connector->state->best_encoder for this case.
As far as I'm concerned, it's by design. Encoders and connectors have
1:N relationship, and only once a connector has been enabled it has an
encoder.
If the connector is disabled, there's no associated encoder.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-13 11:55 ` [PATCH " Maxime Ripard
@ 2025-03-14 0:50 ` Andy Yan
2025-03-14 5:52 ` Dmitry Baryshkov
0 siblings, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-03-14 0:50 UTC (permalink / raw)
To: Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Dmitry Baryshkov, Simona Vetter, lumag
Hi Maxime and Simona,
At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
>Hi,
>
>On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
>> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
>> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> >>With the bridges switching over to drm_bridge_connector, the direct
>> >>association between a bridge driver and its connector was lost.
>> >>
>> >>This is mitigated for atomic bridge drivers by the fact you can access
>> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> >>
>> >>This was also made easier by providing drm_atomic_state directly to all
>> >>atomic hooks bridges can implement.
>> >>
>> >>However, bridge drivers don't have a way to access drm_atomic_state
>> >>outside of the modeset path, like from the hotplug interrupt path or any
>> >>interrupt handler.
>> >>
>> >>Let's introduce a function to retrieve the connector currently assigned
>> >>to an encoder, without using drm_atomic_state, to make these drivers'
>> >>life easier.
>> >>
>> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> >>---
>> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> >> include/drm/drm_atomic.h | 3 +++
>> >> 2 files changed, 48 insertions(+)
>> >>
>> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> >>--- a/drivers/gpu/drm/drm_atomic.c
>> >>+++ b/drivers/gpu/drm/drm_atomic.c
>> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> >>
>> >> return NULL;
>> >> }
>> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> >>
>> >>+/**
>> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> >>+ * @encoder: The encoder to find the connector of
>> >>+ * @ctx: Modeset locking context
>> >>+ *
>> >>+ * This function finds and returns the connector currently assigned to
>> >>+ * an @encoder.
>> >>+ *
>> >>+ * Returns:
>> >>+ * The connector connected to @encoder, or an error pointer otherwise.
>> >>+ * When the error is EDEADLK, a deadlock has been detected and the
>> >>+ * sequence must be restarted.
>> >>+ */
>> >>+struct drm_connector *
>> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> >>+ struct drm_modeset_acquire_ctx *ctx)
>> >>+{
>> >>+ struct drm_connector_list_iter conn_iter;
>> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> >>+ struct drm_connector *connector;
>> >>+ struct drm_device *dev = encoder->dev;
>> >>+ int ret;
>> >>+
>> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> >>+ if (ret)
>> >>+ return ERR_PTR(ret);
>> >
>> >It seems that this will cause a deadlock when called from a hotplug handling path,
>> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
>> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
>> >which will hold connection_mutex first, so the deaklock happens:
>> >
>> >
>> >drm_helper_probe_detect(struct drm_connector *connector,
>> > struct drm_modeset_acquire_ctx *ctx,
>> > bool force)
>> >{
>> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > struct drm_device *dev = connector->dev;
>> > int ret;
>> >
>> > if (!ctx)
>> > return drm_helper_probe_detect_ctx(connector, force);
>> >
>> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > if (ret)
>> > return ret;
>> >
>> > if (funcs->detect_ctx)
>> > ret = funcs->detect_ctx(connector, ctx, force);
>> > else if (connector->funcs->detect)
>> > ret = connector->funcs->detect(connector, force);
>> > else
>> > ret = connector_status_connected;
>> >
>> > if (ret != connector->status)
>> > connector->epoch_counter += 1;
>> >
>> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
>> >
>> >
>> >
>> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>> >>+
>> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
>> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
>> >>+ if (!connector->state)
>> >>+ continue;
>> >>+
>> >>+ if (encoder == connector->state->best_encoder) {
>> >>+ out_connector = connector;
>>
>>
>> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
>> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
>>
>> [ 52.713030] Invalid return value -22 for connector detection
>> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
>> 0x63c
>> [ 52.714568] Modules linked in:
>>
>> [ 52.724546] Call trace:
>> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
>> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
>> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
>> [ 52.726057] drm_ioctl+0x22c/0x544
>> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
>> [ 52.726706] invoke_syscall+0x44/0x100
>> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
>>
>> This is because best_encoder is set by set_best_encoder, which is called from
>> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
>> for the first time, the functions mentioned above have not been called yet,
>> then we can't match the encoder from connector->state->best_encoder for this case.
>
>As far as I'm concerned, it's by design. Encoders and connectors have
>1:N relationship, and only once a connector has been enabled it has an
>encoder.
>
>If the connector is disabled, there's no associated encoder.
Does this prove that this API is not suitable for my application scenario:
Get the connector in the bridge's .detect callback, so this means that I may
still need to modify the bridge's connector callback so that it can pass the connector ?
>
>Maxime
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 0:50 ` Andy Yan
@ 2025-03-14 5:52 ` Dmitry Baryshkov
2025-03-14 7:45 ` Maxime Ripard
0 siblings, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-14 5:52 UTC (permalink / raw)
To: Andy Yan
Cc: Maxime Ripard, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
>
> Hi Maxime and Simona,
>
>
> At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> >Hi,
> >
> >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> >> >>With the bridges switching over to drm_bridge_connector, the direct
> >> >>association between a bridge driver and its connector was lost.
> >> >>
> >> >>This is mitigated for atomic bridge drivers by the fact you can access
> >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> >> >>
> >> >>This was also made easier by providing drm_atomic_state directly to all
> >> >>atomic hooks bridges can implement.
> >> >>
> >> >>However, bridge drivers don't have a way to access drm_atomic_state
> >> >>outside of the modeset path, like from the hotplug interrupt path or any
> >> >>interrupt handler.
> >> >>
> >> >>Let's introduce a function to retrieve the connector currently assigned
> >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> >> >>life easier.
> >> >>
> >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> >> >>---
> >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> >> >> include/drm/drm_atomic.h | 3 +++
> >> >> 2 files changed, 48 insertions(+)
> >> >>
> >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> >> >>--- a/drivers/gpu/drm/drm_atomic.c
> >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> >> >>
> >> >> return NULL;
> >> >> }
> >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> >> >>
> >> >>+/**
> >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> >> >>+ * @encoder: The encoder to find the connector of
> >> >>+ * @ctx: Modeset locking context
> >> >>+ *
> >> >>+ * This function finds and returns the connector currently assigned to
> >> >>+ * an @encoder.
> >> >>+ *
> >> >>+ * Returns:
> >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> >> >>+ * sequence must be restarted.
> >> >>+ */
> >> >>+struct drm_connector *
> >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> >> >>+ struct drm_modeset_acquire_ctx *ctx)
> >> >>+{
> >> >>+ struct drm_connector_list_iter conn_iter;
> >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> >> >>+ struct drm_connector *connector;
> >> >>+ struct drm_device *dev = encoder->dev;
> >> >>+ int ret;
> >> >>+
> >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >> >>+ if (ret)
> >> >>+ return ERR_PTR(ret);
> >> >
> >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> >> >which will hold connection_mutex first, so the deaklock happens:
> >> >
> >> >
> >> >drm_helper_probe_detect(struct drm_connector *connector,
> >> > struct drm_modeset_acquire_ctx *ctx,
> >> > bool force)
> >> >{
> >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> >> > struct drm_device *dev = connector->dev;
> >> > int ret;
> >> >
> >> > if (!ctx)
> >> > return drm_helper_probe_detect_ctx(connector, force);
> >> >
> >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> >> > if (ret)
> >> > return ret;
> >> >
> >> > if (funcs->detect_ctx)
> >> > ret = funcs->detect_ctx(connector, ctx, force);
> >> > else if (connector->funcs->detect)
> >> > ret = connector->funcs->detect(connector, force);
> >> > else
> >> > ret = connector_status_connected;
> >> >
> >> > if (ret != connector->status)
> >> > connector->epoch_counter += 1;
> >> >
> >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> >> >
> >> >
> >> >
> >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> >> >>+
> >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> >> >>+ if (!connector->state)
> >> >>+ continue;
> >> >>+
> >> >>+ if (encoder == connector->state->best_encoder) {
> >> >>+ out_connector = connector;
> >>
> >>
> >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> >>
> >> [ 52.713030] Invalid return value -22 for connector detection
> >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> >> 0x63c
> >> [ 52.714568] Modules linked in:
> >>
> >> [ 52.724546] Call trace:
> >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> >> [ 52.726057] drm_ioctl+0x22c/0x544
> >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> >> [ 52.726706] invoke_syscall+0x44/0x100
> >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> >>
> >> This is because best_encoder is set by set_best_encoder, which is called from
> >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> >> for the first time, the functions mentioned above have not been called yet,
> >> then we can't match the encoder from connector->state->best_encoder for this case.
> >
> >As far as I'm concerned, it's by design. Encoders and connectors have
> >1:N relationship, and only once a connector has been enabled it has an
> >encoder.
> >
> >If the connector is disabled, there's no associated encoder.
>
> Does this prove that this API is not suitable for my application scenario:
> Get the connector in the bridge's .detect callback, so this means that I may
> still need to modify the bridge's connector callback so that it can pass the connector ?
I'd say, yes, please.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 5:52 ` Dmitry Baryshkov
@ 2025-03-14 7:45 ` Maxime Ripard
2025-03-14 7:59 ` Dmitry Baryshkov
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-14 7:45 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
[-- Attachment #1: Type: text/plain, Size: 8154 bytes --]
On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> >
> > Hi Maxime and Simona,
> >
> >
> > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > >Hi,
> > >
> > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > >> >>association between a bridge driver and its connector was lost.
> > >> >>
> > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > >> >>
> > >> >>This was also made easier by providing drm_atomic_state directly to all
> > >> >>atomic hooks bridges can implement.
> > >> >>
> > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > >> >>interrupt handler.
> > >> >>
> > >> >>Let's introduce a function to retrieve the connector currently assigned
> > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > >> >>life easier.
> > >> >>
> > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > >> >>---
> > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > >> >> include/drm/drm_atomic.h | 3 +++
> > >> >> 2 files changed, 48 insertions(+)
> > >> >>
> > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > >> >>
> > >> >> return NULL;
> > >> >> }
> > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > >> >>
> > >> >>+/**
> > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > >> >>+ * @encoder: The encoder to find the connector of
> > >> >>+ * @ctx: Modeset locking context
> > >> >>+ *
> > >> >>+ * This function finds and returns the connector currently assigned to
> > >> >>+ * an @encoder.
> > >> >>+ *
> > >> >>+ * Returns:
> > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > >> >>+ * sequence must be restarted.
> > >> >>+ */
> > >> >>+struct drm_connector *
> > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > >> >>+{
> > >> >>+ struct drm_connector_list_iter conn_iter;
> > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > >> >>+ struct drm_connector *connector;
> > >> >>+ struct drm_device *dev = encoder->dev;
> > >> >>+ int ret;
> > >> >>+
> > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > >> >>+ if (ret)
> > >> >>+ return ERR_PTR(ret);
> > >> >
> > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > >> >which will hold connection_mutex first, so the deaklock happens:
> > >> >
> > >> >
> > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > >> > struct drm_modeset_acquire_ctx *ctx,
> > >> > bool force)
> > >> >{
> > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > >> > struct drm_device *dev = connector->dev;
> > >> > int ret;
> > >> >
> > >> > if (!ctx)
> > >> > return drm_helper_probe_detect_ctx(connector, force);
> > >> >
> > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > >> > if (ret)
> > >> > return ret;
> > >> >
> > >> > if (funcs->detect_ctx)
> > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > >> > else if (connector->funcs->detect)
> > >> > ret = connector->funcs->detect(connector, force);
> > >> > else
> > >> > ret = connector_status_connected;
> > >> >
> > >> > if (ret != connector->status)
> > >> > connector->epoch_counter += 1;
> > >> >
> > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > >> >
> > >> >
> > >> >
> > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > >> >>+
> > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > >> >>+ if (!connector->state)
> > >> >>+ continue;
> > >> >>+
> > >> >>+ if (encoder == connector->state->best_encoder) {
> > >> >>+ out_connector = connector;
> > >>
> > >>
> > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > >>
> > >> [ 52.713030] Invalid return value -22 for connector detection
> > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > >> 0x63c
> > >> [ 52.714568] Modules linked in:
> > >>
> > >> [ 52.724546] Call trace:
> > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > >> [ 52.726706] invoke_syscall+0x44/0x100
> > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > >>
> > >> This is because best_encoder is set by set_best_encoder, which is called from
> > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > >> for the first time, the functions mentioned above have not been called yet,
> > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > >
> > >As far as I'm concerned, it's by design. Encoders and connectors have
> > >1:N relationship, and only once a connector has been enabled it has an
> > >encoder.
> > >
> > >If the connector is disabled, there's no associated encoder.
> >
> > Does this prove that this API is not suitable for my application scenario:
> > Get the connector in the bridge's .detect callback, so this means that I may
> > still need to modify the bridge's connector callback so that it can pass the connector ?
>
> I'd say, yes, please.
And I'd say no :)
There's no reason to deviate from the API other entities have here. It's
just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
completely thought through and it's one of the part where it shows.
We have two alternative solutions: Either the driver creates the
connector itself, since it doesn't seem to use any downstream bridge
anyway, or we need a new bridge helper to find the connector on a bridge
chain.
We have the iterator already, we just need a new accessor to retrieve
the (optional) connector of a bridge, and if there's none, go to the
next bridge and try again.
There's a decent amount of variations that ideally call for tests too,
but it should be pretty simple overall.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 7:45 ` Maxime Ripard
@ 2025-03-14 7:59 ` Dmitry Baryshkov
2025-03-14 17:40 ` Maxime Ripard
0 siblings, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-14 7:59 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > >
> > > Hi Maxime and Simona,
> > >
> > >
> > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > >Hi,
> > > >
> > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > >> >>association between a bridge driver and its connector was lost.
> > > >> >>
> > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > >> >>
> > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > >> >>atomic hooks bridges can implement.
> > > >> >>
> > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > >> >>interrupt handler.
> > > >> >>
> > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > >> >>life easier.
> > > >> >>
> > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > >> >>---
> > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > >> >> include/drm/drm_atomic.h | 3 +++
> > > >> >> 2 files changed, 48 insertions(+)
> > > >> >>
> > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > >> >>
> > > >> >> return NULL;
> > > >> >> }
> > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > >> >>
> > > >> >>+/**
> > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > >> >>+ * @encoder: The encoder to find the connector of
> > > >> >>+ * @ctx: Modeset locking context
> > > >> >>+ *
> > > >> >>+ * This function finds and returns the connector currently assigned to
> > > >> >>+ * an @encoder.
> > > >> >>+ *
> > > >> >>+ * Returns:
> > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > >> >>+ * sequence must be restarted.
> > > >> >>+ */
> > > >> >>+struct drm_connector *
> > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > >> >>+{
> > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > >> >>+ struct drm_connector *connector;
> > > >> >>+ struct drm_device *dev = encoder->dev;
> > > >> >>+ int ret;
> > > >> >>+
> > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > >> >>+ if (ret)
> > > >> >>+ return ERR_PTR(ret);
> > > >> >
> > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > >> >
> > > >> >
> > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > >> > bool force)
> > > >> >{
> > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > >> > struct drm_device *dev = connector->dev;
> > > >> > int ret;
> > > >> >
> > > >> > if (!ctx)
> > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > >> >
> > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > >> > if (ret)
> > > >> > return ret;
> > > >> >
> > > >> > if (funcs->detect_ctx)
> > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > >> > else if (connector->funcs->detect)
> > > >> > ret = connector->funcs->detect(connector, force);
> > > >> > else
> > > >> > ret = connector_status_connected;
> > > >> >
> > > >> > if (ret != connector->status)
> > > >> > connector->epoch_counter += 1;
> > > >> >
> > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > >> >
> > > >> >
> > > >> >
> > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > >> >>+
> > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > >> >>+ if (!connector->state)
> > > >> >>+ continue;
> > > >> >>+
> > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > >> >>+ out_connector = connector;
> > > >>
> > > >>
> > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > >>
> > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > >> 0x63c
> > > >> [ 52.714568] Modules linked in:
> > > >>
> > > >> [ 52.724546] Call trace:
> > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > >>
> > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > >> for the first time, the functions mentioned above have not been called yet,
> > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > >
> > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > >1:N relationship, and only once a connector has been enabled it has an
> > > >encoder.
> > > >
> > > >If the connector is disabled, there's no associated encoder.
> > >
> > > Does this prove that this API is not suitable for my application scenario:
> > > Get the connector in the bridge's .detect callback, so this means that I may
> > > still need to modify the bridge's connector callback so that it can pass the connector ?
> >
> > I'd say, yes, please.
>
> And I'd say no :)
Fair enough :-)
> There's no reason to deviate from the API other entities have here. It's
> just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> completely thought through and it's one of the part where it shows.
>
> We have two alternative solutions: Either the driver creates the
> connector itself, since it doesn't seem to use any downstream bridge
> anyway, or we need a new bridge helper to find the connector on a bridge
> chain.
>
> We have the iterator already, we just need a new accessor to retrieve
> the (optional) connector of a bridge, and if there's none, go to the
> next bridge and try again.
The problem is that there is no guarantee that the the created connector
is created for or linked to any bridge. For example, for msm driver I'm
waiting for several series to go in, but after that I plan to work on
moving connector creation to the generic code within the msm driver.
In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
perfectly legit not to have a bridge which has "connector of a bridge".
It is possible to create drm_bridge_connector on the drm_encoder's side
after the drm_bridge_attach() succeeds.
> There's a decent amount of variations that ideally call for tests too,
> but it should be pretty simple overall.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 7:59 ` Dmitry Baryshkov
@ 2025-03-14 17:40 ` Maxime Ripard
2025-03-14 18:28 ` Dmitry Baryshkov
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-14 17:40 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
[-- Attachment #1: Type: text/plain, Size: 9696 bytes --]
On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > >Hi,
> > > > >
> > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > >> >>association between a bridge driver and its connector was lost.
> > > > >> >>
> > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > >> >>
> > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > >> >>atomic hooks bridges can implement.
> > > > >> >>
> > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > >> >>interrupt handler.
> > > > >> >>
> > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > >> >>life easier.
> > > > >> >>
> > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > >> >>---
> > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > >> >> 2 files changed, 48 insertions(+)
> > > > >> >>
> > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > >> >>
> > > > >> >> return NULL;
> > > > >> >> }
> > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > >> >>
> > > > >> >>+/**
> > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > >> >>+ * @ctx: Modeset locking context
> > > > >> >>+ *
> > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > >> >>+ * an @encoder.
> > > > >> >>+ *
> > > > >> >>+ * Returns:
> > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > >> >>+ * sequence must be restarted.
> > > > >> >>+ */
> > > > >> >>+struct drm_connector *
> > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > >> >>+{
> > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > >> >>+ struct drm_connector *connector;
> > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > >> >>+ int ret;
> > > > >> >>+
> > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > >> >>+ if (ret)
> > > > >> >>+ return ERR_PTR(ret);
> > > > >> >
> > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > >> >
> > > > >> >
> > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > >> > bool force)
> > > > >> >{
> > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > >> > struct drm_device *dev = connector->dev;
> > > > >> > int ret;
> > > > >> >
> > > > >> > if (!ctx)
> > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > >> >
> > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > >> > if (ret)
> > > > >> > return ret;
> > > > >> >
> > > > >> > if (funcs->detect_ctx)
> > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > >> > else if (connector->funcs->detect)
> > > > >> > ret = connector->funcs->detect(connector, force);
> > > > >> > else
> > > > >> > ret = connector_status_connected;
> > > > >> >
> > > > >> > if (ret != connector->status)
> > > > >> > connector->epoch_counter += 1;
> > > > >> >
> > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > >> >
> > > > >> >
> > > > >> >
> > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > >> >>+
> > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > >> >>+ if (!connector->state)
> > > > >> >>+ continue;
> > > > >> >>+
> > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > >> >>+ out_connector = connector;
> > > > >>
> > > > >>
> > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > >>
> > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > >> 0x63c
> > > > >> [ 52.714568] Modules linked in:
> > > > >>
> > > > >> [ 52.724546] Call trace:
> > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > >>
> > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > >
> > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > >encoder.
> > > > >
> > > > >If the connector is disabled, there's no associated encoder.
> > > >
> > > > Does this prove that this API is not suitable for my application scenario:
> > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > >
> > > I'd say, yes, please.
> >
> > And I'd say no :)
>
> Fair enough :-)
>
> > There's no reason to deviate from the API other entities have here. It's
> > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > completely thought through and it's one of the part where it shows.
> >
> > We have two alternative solutions: Either the driver creates the
> > connector itself, since it doesn't seem to use any downstream bridge
> > anyway, or we need a new bridge helper to find the connector on a bridge
> > chain.
> >
> > We have the iterator already, we just need a new accessor to retrieve
> > the (optional) connector of a bridge, and if there's none, go to the
> > next bridge and try again.
>
> The problem is that there is no guarantee that the the created connector
> is created for or linked to any bridge. For example, for msm driver I'm
> waiting for several series to go in, but after that I plan to work on
> moving connector creation to the generic code within the msm driver.
>
> In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> perfectly legit not to have a bridge which has "connector of a bridge".
> It is possible to create drm_bridge_connector on the drm_encoder's side
> after the drm_bridge_attach() succeeds.
Sure, but then I'd expect detect and get_modes to only be called *after*
that connector has been created, right?
Returning NULL in the case where we don't have a connector (yet?) in
such a case would make total sense to me, just like we return NULL if
the connector is disabled and doesn't have an encoder here.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 17:40 ` Maxime Ripard
@ 2025-03-14 18:28 ` Dmitry Baryshkov
2025-03-18 15:51 ` Maxime Ripard
0 siblings, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-14 18:28 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > >Hi,
> > > > > >
> > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > >> >>
> > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > >> >>
> > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > >> >>atomic hooks bridges can implement.
> > > > > >> >>
> > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > >> >>interrupt handler.
> > > > > >> >>
> > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > >> >>life easier.
> > > > > >> >>
> > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > >> >>---
> > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > >> >>
> > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > >> >>
> > > > > >> >> return NULL;
> > > > > >> >> }
> > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > >> >>
> > > > > >> >>+/**
> > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > >> >>+ * @ctx: Modeset locking context
> > > > > >> >>+ *
> > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > >> >>+ * an @encoder.
> > > > > >> >>+ *
> > > > > >> >>+ * Returns:
> > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > >> >>+ * sequence must be restarted.
> > > > > >> >>+ */
> > > > > >> >>+struct drm_connector *
> > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > >> >>+{
> > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > >> >>+ struct drm_connector *connector;
> > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > >> >>+ int ret;
> > > > > >> >>+
> > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > >> >>+ if (ret)
> > > > > >> >>+ return ERR_PTR(ret);
> > > > > >> >
> > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > >> >
> > > > > >> >
> > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > >> > bool force)
> > > > > >> >{
> > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > >> > struct drm_device *dev = connector->dev;
> > > > > >> > int ret;
> > > > > >> >
> > > > > >> > if (!ctx)
> > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > >> >
> > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > >> > if (ret)
> > > > > >> > return ret;
> > > > > >> >
> > > > > >> > if (funcs->detect_ctx)
> > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > >> > else if (connector->funcs->detect)
> > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > >> > else
> > > > > >> > ret = connector_status_connected;
> > > > > >> >
> > > > > >> > if (ret != connector->status)
> > > > > >> > connector->epoch_counter += 1;
> > > > > >> >
> > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > >> >
> > > > > >> >
> > > > > >> >
> > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > >> >>+
> > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > >> >>+ if (!connector->state)
> > > > > >> >>+ continue;
> > > > > >> >>+
> > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > >> >>+ out_connector = connector;
> > > > > >>
> > > > > >>
> > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > >>
> > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > >> 0x63c
> > > > > >> [ 52.714568] Modules linked in:
> > > > > >>
> > > > > >> [ 52.724546] Call trace:
> > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > >>
> > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > >
> > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > >encoder.
> > > > > >
> > > > > >If the connector is disabled, there's no associated encoder.
> > > > >
> > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > >
> > > > I'd say, yes, please.
> > >
> > > And I'd say no :)
> >
> > Fair enough :-)
> >
> > > There's no reason to deviate from the API other entities have here. It's
> > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > completely thought through and it's one of the part where it shows.
> > >
> > > We have two alternative solutions: Either the driver creates the
> > > connector itself, since it doesn't seem to use any downstream bridge
> > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > chain.
> > >
> > > We have the iterator already, we just need a new accessor to retrieve
> > > the (optional) connector of a bridge, and if there's none, go to the
> > > next bridge and try again.
> >
> > The problem is that there is no guarantee that the the created connector
> > is created for or linked to any bridge. For example, for msm driver I'm
> > waiting for several series to go in, but after that I plan to work on
> > moving connector creation to the generic code within the msm driver.
> >
> > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > perfectly legit not to have a bridge which has "connector of a bridge".
> > It is possible to create drm_bridge_connector on the drm_encoder's side
> > after the drm_bridge_attach() succeeds.
>
> Sure, but then I'd expect detect and get_modes to only be called *after*
> that connector has been created, right?
Yes. But you can not get the connector by following bridge chain. Well,
unless you include encoder into the chain. If that's what you have had
in mind, then please excuse me, I didn't understand that from the
beginning.
But frankly speaking, I think it might be easier to pass down the
connector to the detect callback (as drm_connector_funcs.detect already
gets the connecor) rather than making bridge drivers go through the
chain to get the value that is already present in the caller function.
(For some other usecases I'd totally agree with you, especially if the
connector isn't already available on the caller side).
> Returning NULL in the case where we don't have a connector (yet?) in
> such a case would make total sense to me, just like we return NULL if
> the connector is disabled and doesn't have an encoder here.
>
> Maxime
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-14 18:28 ` Dmitry Baryshkov
@ 2025-03-18 15:51 ` Maxime Ripard
2025-03-18 19:00 ` Dmitry Baryshkov
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-18 15:51 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
[-- Attachment #1: Type: text/plain, Size: 11676 bytes --]
On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > >Hi,
> > > > > > >
> > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > >> >>
> > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > >> >>
> > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > >> >>atomic hooks bridges can implement.
> > > > > > >> >>
> > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > >> >>interrupt handler.
> > > > > > >> >>
> > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > >> >>life easier.
> > > > > > >> >>
> > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > >> >>---
> > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > >> >>
> > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > >> >>
> > > > > > >> >> return NULL;
> > > > > > >> >> }
> > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > >> >>
> > > > > > >> >>+/**
> > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > >> >>+ *
> > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > >> >>+ * an @encoder.
> > > > > > >> >>+ *
> > > > > > >> >>+ * Returns:
> > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > >> >>+ * sequence must be restarted.
> > > > > > >> >>+ */
> > > > > > >> >>+struct drm_connector *
> > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > >> >>+{
> > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > >> >>+ struct drm_connector *connector;
> > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > >> >>+ int ret;
> > > > > > >> >>+
> > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > >> >>+ if (ret)
> > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > >> >
> > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > >> >
> > > > > > >> >
> > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > >> > bool force)
> > > > > > >> >{
> > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > >> > int ret;
> > > > > > >> >
> > > > > > >> > if (!ctx)
> > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > >> >
> > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > >> > if (ret)
> > > > > > >> > return ret;
> > > > > > >> >
> > > > > > >> > if (funcs->detect_ctx)
> > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > >> > else if (connector->funcs->detect)
> > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > >> > else
> > > > > > >> > ret = connector_status_connected;
> > > > > > >> >
> > > > > > >> > if (ret != connector->status)
> > > > > > >> > connector->epoch_counter += 1;
> > > > > > >> >
> > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > >> >
> > > > > > >> >
> > > > > > >> >
> > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > >> >>+
> > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > >> >>+ if (!connector->state)
> > > > > > >> >>+ continue;
> > > > > > >> >>+
> > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > >> >>+ out_connector = connector;
> > > > > > >>
> > > > > > >>
> > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > >>
> > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > >> 0x63c
> > > > > > >> [ 52.714568] Modules linked in:
> > > > > > >>
> > > > > > >> [ 52.724546] Call trace:
> > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > >>
> > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > >
> > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > >encoder.
> > > > > > >
> > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > >
> > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > >
> > > > > I'd say, yes, please.
> > > >
> > > > And I'd say no :)
> > >
> > > Fair enough :-)
> > >
> > > > There's no reason to deviate from the API other entities have here. It's
> > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > completely thought through and it's one of the part where it shows.
> > > >
> > > > We have two alternative solutions: Either the driver creates the
> > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > chain.
> > > >
> > > > We have the iterator already, we just need a new accessor to retrieve
> > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > next bridge and try again.
> > >
> > > The problem is that there is no guarantee that the the created connector
> > > is created for or linked to any bridge. For example, for msm driver I'm
> > > waiting for several series to go in, but after that I plan to work on
> > > moving connector creation to the generic code within the msm driver.
> > >
> > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > after the drm_bridge_attach() succeeds.
> >
> > Sure, but then I'd expect detect and get_modes to only be called *after*
> > that connector has been created, right?
>
> Yes. But you can not get the connector by following bridge chain. Well,
> unless you include encoder into the chain. If that's what you have had
> in mind, then please excuse me, I didn't understand that from the
> beginning.
You can't include the encoder either, because the encoder doesn't have a
connector assigned yet at that time.
However, you can:
- Store the bridge attach flags in drm_bridge
- Create a hook that returns the connector a bridge creates, depending
on the attach flags.
- Create a helper that iterates over the next bridges until the
previous hook returns !NULL. If it doesn't find anything, return
NULL.
AFAIK, it solves all the problems being discussed here, while dealing
with legacy and new-style bridge drivers.
> But frankly speaking, I think it might be easier to pass down the
> connector to the detect callback (as drm_connector_funcs.detect already
> gets the connecor) rather than making bridge drivers go through the
> chain to get the value that is already present in the caller function.
>
> (For some other usecases I'd totally agree with you, especially if the
> connector isn't already available on the caller side).
Still, we've tried to converge to the same API for all entities, it
feels like a step backward to me.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-18 15:51 ` Maxime Ripard
@ 2025-03-18 19:00 ` Dmitry Baryshkov
2025-03-19 7:21 ` Andy Yan
2025-03-21 9:46 ` Maxime Ripard
0 siblings, 2 replies; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-18 19:00 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
> On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > >Hi,
> > > > > > > >
> > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > > >> >>
> > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > > >> >>
> > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > > >> >>atomic hooks bridges can implement.
> > > > > > > >> >>
> > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > > >> >>interrupt handler.
> > > > > > > >> >>
> > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > > >> >>life easier.
> > > > > > > >> >>
> > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > > >> >>---
> > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > > >> >>
> > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > > >> >>
> > > > > > > >> >> return NULL;
> > > > > > > >> >> }
> > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > > >> >>
> > > > > > > >> >>+/**
> > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > > >> >>+ *
> > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > > >> >>+ * an @encoder.
> > > > > > > >> >>+ *
> > > > > > > >> >>+ * Returns:
> > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > > >> >>+ * sequence must be restarted.
> > > > > > > >> >>+ */
> > > > > > > >> >>+struct drm_connector *
> > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > > >> >>+{
> > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > > >> >>+ struct drm_connector *connector;
> > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > > >> >>+ int ret;
> > > > > > > >> >>+
> > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > >> >>+ if (ret)
> > > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > > >> >
> > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > > >> >
> > > > > > > >> >
> > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > > >> > bool force)
> > > > > > > >> >{
> > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > > >> > int ret;
> > > > > > > >> >
> > > > > > > >> > if (!ctx)
> > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > > >> >
> > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > >> > if (ret)
> > > > > > > >> > return ret;
> > > > > > > >> >
> > > > > > > >> > if (funcs->detect_ctx)
> > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > > >> > else if (connector->funcs->detect)
> > > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > > >> > else
> > > > > > > >> > ret = connector_status_connected;
> > > > > > > >> >
> > > > > > > >> > if (ret != connector->status)
> > > > > > > >> > connector->epoch_counter += 1;
> > > > > > > >> >
> > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > > >> >
> > > > > > > >> >
> > > > > > > >> >
> > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > > >> >>+
> > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > > >> >>+ if (!connector->state)
> > > > > > > >> >>+ continue;
> > > > > > > >> >>+
> > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > > >> >>+ out_connector = connector;
> > > > > > > >>
> > > > > > > >>
> > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > > >>
> > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > > >> 0x63c
> > > > > > > >> [ 52.714568] Modules linked in:
> > > > > > > >>
> > > > > > > >> [ 52.724546] Call trace:
> > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > > >>
> > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > > >
> > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > > >encoder.
> > > > > > > >
> > > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > > >
> > > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > > >
> > > > > > I'd say, yes, please.
> > > > >
> > > > > And I'd say no :)
> > > >
> > > > Fair enough :-)
> > > >
> > > > > There's no reason to deviate from the API other entities have here. It's
> > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > > completely thought through and it's one of the part where it shows.
> > > > >
> > > > > We have two alternative solutions: Either the driver creates the
> > > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > > chain.
> > > > >
> > > > > We have the iterator already, we just need a new accessor to retrieve
> > > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > > next bridge and try again.
> > > >
> > > > The problem is that there is no guarantee that the the created connector
> > > > is created for or linked to any bridge. For example, for msm driver I'm
> > > > waiting for several series to go in, but after that I plan to work on
> > > > moving connector creation to the generic code within the msm driver.
> > > >
> > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > > after the drm_bridge_attach() succeeds.
> > >
> > > Sure, but then I'd expect detect and get_modes to only be called *after*
> > > that connector has been created, right?
> >
> > Yes. But you can not get the connector by following bridge chain. Well,
> > unless you include encoder into the chain. If that's what you have had
> > in mind, then please excuse me, I didn't understand that from the
> > beginning.
>
> You can't include the encoder either, because the encoder doesn't have a
> connector assigned yet at that time.
>
> However, you can:
>
> - Store the bridge attach flags in drm_bridge
>
> - Create a hook that returns the connector a bridge creates, depending
> on the attach flags.
>
> - Create a helper that iterates over the next bridges until the
> previous hook returns !NULL. If it doesn't find anything, return
> NULL.
>
> AFAIK, it solves all the problems being discussed here, while dealing
> with legacy and new-style bridge drivers.
I'm still fail to understand how does that solve the issue for new-style
bridges. How do we find the created drm_bridge_connector for them?
>
> > But frankly speaking, I think it might be easier to pass down the
> > connector to the detect callback (as drm_connector_funcs.detect already
> > gets the connecor) rather than making bridge drivers go through the
> > chain to get the value that is already present in the caller function.
> >
> > (For some other usecases I'd totally agree with you, especially if the
> > connector isn't already available on the caller side).
>
> Still, we've tried to converge to the same API for all entities, it
> feels like a step backward to me.
I'd argue here a bit. The drm_connector interface has connector here.
drm_bridge is an extension/subpart of the drm_connector, so it would be
logical to extend that interface.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-18 19:00 ` Dmitry Baryshkov
@ 2025-03-19 7:21 ` Andy Yan
2025-03-21 9:46 ` Maxime Ripard
1 sibling, 0 replies; 52+ messages in thread
From: Andy Yan @ 2025-03-19 7:21 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Maxime Ripard, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
Hello,
At 2025-03-19 03:00:29, "Dmitry Baryshkov" <dmitry.baryshkov@oss.qualcomm.com> wrote:
>On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
>> On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
>> > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
>> > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
>> > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
>> > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
>> > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
>> > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > >Hi,
>> > > > > > > >
>> > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
>> > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
>> > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
>> > > > > > > >> >>association between a bridge driver and its connector was lost.
>> > > > > > > >> >>
>> > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
>> > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> > > > > > > >> >>
>> > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
>> > > > > > > >> >>atomic hooks bridges can implement.
>> > > > > > > >> >>
>> > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
>> > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
>> > > > > > > >> >>interrupt handler.
>> > > > > > > >> >>
>> > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
>> > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
>> > > > > > > >> >>life easier.
>> > > > > > > >> >>
>> > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> > > > > > > >> >>---
>> > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
>> > > > > > > >> >> 2 files changed, 48 insertions(+)
>> > > > > > > >> >>
>> > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
>> > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> > > > > > > >> >>
>> > > > > > > >> >> return NULL;
>> > > > > > > >> >> }
>> > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> > > > > > > >> >>
>> > > > > > > >> >>+/**
>> > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> > > > > > > >> >>+ * @encoder: The encoder to find the connector of
>> > > > > > > >> >>+ * @ctx: Modeset locking context
>> > > > > > > >> >>+ *
>> > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
>> > > > > > > >> >>+ * an @encoder.
>> > > > > > > >> >>+ *
>> > > > > > > >> >>+ * Returns:
>> > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
>> > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
>> > > > > > > >> >>+ * sequence must be restarted.
>> > > > > > > >> >>+ */
>> > > > > > > >> >>+struct drm_connector *
>> > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
>> > > > > > > >> >>+{
>> > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
>> > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> > > > > > > >> >>+ struct drm_connector *connector;
>> > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
>> > > > > > > >> >>+ int ret;
>> > > > > > > >> >>+
>> > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > >> >>+ if (ret)
>> > > > > > > >> >>+ return ERR_PTR(ret);
>> > > > > > > >> >
>> > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
>> > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
>> > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
>> > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
>> > > > > > > >> >
>> > > > > > > >> >
>> > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
>> > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
>> > > > > > > >> > bool force)
>> > > > > > > >> >{
>> > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > > > > > > >> > struct drm_device *dev = connector->dev;
>> > > > > > > >> > int ret;
>> > > > > > > >> >
>> > > > > > > >> > if (!ctx)
>> > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
>> > > > > > > >> >
>> > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > >> > if (ret)
>> > > > > > > >> > return ret;
>> > > > > > > >> >
>> > > > > > > >> > if (funcs->detect_ctx)
>> > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
>> > > > > > > >> > else if (connector->funcs->detect)
>> > > > > > > >> > ret = connector->funcs->detect(connector, force);
>> > > > > > > >> > else
>> > > > > > > >> > ret = connector_status_connected;
>> > > > > > > >> >
>> > > > > > > >> > if (ret != connector->status)
>> > > > > > > >> > connector->epoch_counter += 1;
>> > > > > > > >> >
>> > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
>> > > > > > > >> >
>> > > > > > > >> >
>> > > > > > > >> >
>> > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>> > > > > > > >> >>+
>> > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
>> > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
>> > > > > > > >> >>+ if (!connector->state)
>> > > > > > > >> >>+ continue;
>> > > > > > > >> >>+
>> > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
>> > > > > > > >> >>+ out_connector = connector;
>> > > > > > > >>
>> > > > > > > >>
>> > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
>> > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
>> > > > > > > >>
>> > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
>> > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
>> > > > > > > >> 0x63c
>> > > > > > > >> [ 52.714568] Modules linked in:
>> > > > > > > >>
>> > > > > > > >> [ 52.724546] Call trace:
>> > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
>> > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
>> > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
>> > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
>> > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
>> > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
>> > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
>> > > > > > > >>
>> > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
>> > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
>> > > > > > > >> for the first time, the functions mentioned above have not been called yet,
>> > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
>> > > > > > > >
>> > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
>> > > > > > > >1:N relationship, and only once a connector has been enabled it has an
>> > > > > > > >encoder.
>> > > > > > > >
>> > > > > > > >If the connector is disabled, there's no associated encoder.
>> > > > > > >
>> > > > > > > Does this prove that this API is not suitable for my application scenario:
>> > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
>> > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
>> > > > > >
>> > > > > > I'd say, yes, please.
>> > > > >
>> > > > > And I'd say no :)
>> > > >
>> > > > Fair enough :-)
>> > > >
>> > > > > There's no reason to deviate from the API other entities have here. It's
>> > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
>> > > > > completely thought through and it's one of the part where it shows.
>> > > > >
>> > > > > We have two alternative solutions: Either the driver creates the
>> > > > > connector itself, since it doesn't seem to use any downstream bridge
>> > > > > anyway, or we need a new bridge helper to find the connector on a bridge
>> > > > > chain.
>> > > > >
>> > > > > We have the iterator already, we just need a new accessor to retrieve
>> > > > > the (optional) connector of a bridge, and if there's none, go to the
>> > > > > next bridge and try again.
>> > > >
>> > > > The problem is that there is no guarantee that the the created connector
>> > > > is created for or linked to any bridge. For example, for msm driver I'm
>> > > > waiting for several series to go in, but after that I plan to work on
>> > > > moving connector creation to the generic code within the msm driver.
>> > > >
>> > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
>> > > > perfectly legit not to have a bridge which has "connector of a bridge".
>> > > > It is possible to create drm_bridge_connector on the drm_encoder's side
>> > > > after the drm_bridge_attach() succeeds.
>> > >
>> > > Sure, but then I'd expect detect and get_modes to only be called *after*
>> > > that connector has been created, right?
>> >
>> > Yes. But you can not get the connector by following bridge chain. Well,
>> > unless you include encoder into the chain. If that's what you have had
>> > in mind, then please excuse me, I didn't understand that from the
>> > beginning.
>>
>> You can't include the encoder either, because the encoder doesn't have a
>> connector assigned yet at that time.
>>
>> However, you can:
>>
>> - Store the bridge attach flags in drm_bridge
>>
>> - Create a hook that returns the connector a bridge creates, depending
>> on the attach flags.
>>
>> - Create a helper that iterates over the next bridges until the
>> previous hook returns !NULL. If it doesn't find anything, return
>> NULL.
>>
>> AFAIK, it solves all the problems being discussed here, while dealing
>> with legacy and new-style bridge drivers.
>
>I'm still fail to understand how does that solve the issue for new-style
>bridges. How do we find the created drm_bridge_connector for them?
>
>>
>> > But frankly speaking, I think it might be easier to pass down the
>> > connector to the detect callback (as drm_connector_funcs.detect already
>> > gets the connecor) rather than making bridge drivers go through the
>> > chain to get the value that is already present in the caller function.
>> >
>> > (For some other usecases I'd totally agree with you, especially if the
>> > connector isn't already available on the caller side).
>>
>> Still, we've tried to converge to the same API for all entities, it
>> feels like a step backward to me.
>
>I'd argue here a bit. The drm_connector interface has connector here.
>drm_bridge is an extension/subpart of the drm_connector, so it would be
>logical to extend that interface.
Yes, since all the calls to drm_bridge_funcs.detect are initiated by the connecter,
I think it is reasonable to pass this connecter to the corresponding bridge.
And this can prevent iterates failures caused by various complex bridge connection logic changes.
>
>
>--
>With best wishes
>Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-18 19:00 ` Dmitry Baryshkov
2025-03-19 7:21 ` Andy Yan
@ 2025-03-21 9:46 ` Maxime Ripard
2025-03-23 2:22 ` Dmitry Baryshkov
1 sibling, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-03-21 9:46 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
[-- Attachment #1: Type: text/plain, Size: 13752 bytes --]
On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
> On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
> > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > >Hi,
> > > > > > > > >
> > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > > > >> >>
> > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > > > >> >>
> > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > > > >> >>atomic hooks bridges can implement.
> > > > > > > > >> >>
> > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > > > >> >>interrupt handler.
> > > > > > > > >> >>
> > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > > > >> >>life easier.
> > > > > > > > >> >>
> > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > > > >> >>---
> > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > > > >> >>
> > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > > > >> >>
> > > > > > > > >> >> return NULL;
> > > > > > > > >> >> }
> > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > > > >> >>
> > > > > > > > >> >>+/**
> > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > > > >> >>+ *
> > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > > > >> >>+ * an @encoder.
> > > > > > > > >> >>+ *
> > > > > > > > >> >>+ * Returns:
> > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > > > >> >>+ * sequence must be restarted.
> > > > > > > > >> >>+ */
> > > > > > > > >> >>+struct drm_connector *
> > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > > > >> >>+{
> > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > > > >> >>+ struct drm_connector *connector;
> > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > > > >> >>+ int ret;
> > > > > > > > >> >>+
> > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > >> >>+ if (ret)
> > > > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > > > >> >
> > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > > > >> >
> > > > > > > > >> >
> > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > > > >> > bool force)
> > > > > > > > >> >{
> > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > > > >> > int ret;
> > > > > > > > >> >
> > > > > > > > >> > if (!ctx)
> > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > > > >> >
> > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > >> > if (ret)
> > > > > > > > >> > return ret;
> > > > > > > > >> >
> > > > > > > > >> > if (funcs->detect_ctx)
> > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > > > >> > else if (connector->funcs->detect)
> > > > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > > > >> > else
> > > > > > > > >> > ret = connector_status_connected;
> > > > > > > > >> >
> > > > > > > > >> > if (ret != connector->status)
> > > > > > > > >> > connector->epoch_counter += 1;
> > > > > > > > >> >
> > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > > > >> >
> > > > > > > > >> >
> > > > > > > > >> >
> > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > > > >> >>+
> > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > > > >> >>+ if (!connector->state)
> > > > > > > > >> >>+ continue;
> > > > > > > > >> >>+
> > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > > > >> >>+ out_connector = connector;
> > > > > > > > >>
> > > > > > > > >>
> > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > > > >>
> > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > > > >> 0x63c
> > > > > > > > >> [ 52.714568] Modules linked in:
> > > > > > > > >>
> > > > > > > > >> [ 52.724546] Call trace:
> > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > > > >>
> > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > > > >
> > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > > > >encoder.
> > > > > > > > >
> > > > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > > > >
> > > > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > > > >
> > > > > > > I'd say, yes, please.
> > > > > >
> > > > > > And I'd say no :)
> > > > >
> > > > > Fair enough :-)
> > > > >
> > > > > > There's no reason to deviate from the API other entities have here. It's
> > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > > > completely thought through and it's one of the part where it shows.
> > > > > >
> > > > > > We have two alternative solutions: Either the driver creates the
> > > > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > > > chain.
> > > > > >
> > > > > > We have the iterator already, we just need a new accessor to retrieve
> > > > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > > > next bridge and try again.
> > > > >
> > > > > The problem is that there is no guarantee that the the created connector
> > > > > is created for or linked to any bridge. For example, for msm driver I'm
> > > > > waiting for several series to go in, but after that I plan to work on
> > > > > moving connector creation to the generic code within the msm driver.
> > > > >
> > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > > > after the drm_bridge_attach() succeeds.
> > > >
> > > > Sure, but then I'd expect detect and get_modes to only be called *after*
> > > > that connector has been created, right?
> > >
> > > Yes. But you can not get the connector by following bridge chain. Well,
> > > unless you include encoder into the chain. If that's what you have had
> > > in mind, then please excuse me, I didn't understand that from the
> > > beginning.
> >
> > You can't include the encoder either, because the encoder doesn't have a
> > connector assigned yet at that time.
> >
> > However, you can:
> >
> > - Store the bridge attach flags in drm_bridge
> >
> > - Create a hook that returns the connector a bridge creates, depending
> > on the attach flags.
> >
> > - Create a helper that iterates over the next bridges until the
> > previous hook returns !NULL. If it doesn't find anything, return
> > NULL.
> >
> > AFAIK, it solves all the problems being discussed here, while dealing
> > with legacy and new-style bridge drivers.
>
> I'm still fail to understand how does that solve the issue for new-style
> bridges. How do we find the created drm_bridge_connector for them?
Sigh, for some reason I was remembering that drm_bridge_connector was a
bridge itself, which it isn't. My bad. But I guess it still applies. If
we make drm_bridge_connector a bridge, then it works, doesn't it?
> >
> > > But frankly speaking, I think it might be easier to pass down the
> > > connector to the detect callback (as drm_connector_funcs.detect already
> > > gets the connecor) rather than making bridge drivers go through the
> > > chain to get the value that is already present in the caller function.
> > >
> > > (For some other usecases I'd totally agree with you, especially if the
> > > connector isn't already available on the caller side).
> >
> > Still, we've tried to converge to the same API for all entities, it
> > feels like a step backward to me.
>
> I'd argue here a bit. The drm_connector interface has connector here.
> drm_bridge is an extension/subpart of the drm_connector, so it would be
> logical to extend that interface.
The drm_connector interface has the connector because it's a connector.
Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
pointer to drm_bridge atomic_check.
I still think it goes against the trend and work we've been doing over
the years. And we should at least *try* something different instead of
just taking the easy way out. Or accepting to duplicate the helpers that
started the discussion, or to create a connector directyl instead of
using drm_bridge_connector for that driver.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-21 9:46 ` Maxime Ripard
@ 2025-03-23 2:22 ` Dmitry Baryshkov
2025-04-08 3:44 ` Andy Yan
2025-05-24 8:09 ` Dmitry Baryshkov
0 siblings, 2 replies; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-03-23 2:22 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
On Fri, Mar 21, 2025 at 10:46:56AM +0100, Maxime Ripard wrote:
> On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
> > On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
> > > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> > > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > >Hi,
> > > > > > > > > >
> > > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > > > > >> >>
> > > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > > > > >> >>
> > > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > > > > >> >>atomic hooks bridges can implement.
> > > > > > > > > >> >>
> > > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > > > > >> >>interrupt handler.
> > > > > > > > > >> >>
> > > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > > > > >> >>life easier.
> > > > > > > > > >> >>
> > > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > > > > >> >>---
> > > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > > > > >> >>
> > > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > > > > >> >>
> > > > > > > > > >> >> return NULL;
> > > > > > > > > >> >> }
> > > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > > > > >> >>
> > > > > > > > > >> >>+/**
> > > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > > > > >> >>+ *
> > > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > > > > >> >>+ * an @encoder.
> > > > > > > > > >> >>+ *
> > > > > > > > > >> >>+ * Returns:
> > > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > > > > >> >>+ * sequence must be restarted.
> > > > > > > > > >> >>+ */
> > > > > > > > > >> >>+struct drm_connector *
> > > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > > > > >> >>+{
> > > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > > > > >> >>+ struct drm_connector *connector;
> > > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > > > > >> >>+ int ret;
> > > > > > > > > >> >>+
> > > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > >> >>+ if (ret)
> > > > > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > > > > >> >
> > > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > > > > >> >
> > > > > > > > > >> >
> > > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > > > > >> > bool force)
> > > > > > > > > >> >{
> > > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > > > > >> > int ret;
> > > > > > > > > >> >
> > > > > > > > > >> > if (!ctx)
> > > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > > > > >> >
> > > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > >> > if (ret)
> > > > > > > > > >> > return ret;
> > > > > > > > > >> >
> > > > > > > > > >> > if (funcs->detect_ctx)
> > > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > > > > >> > else if (connector->funcs->detect)
> > > > > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > > > > >> > else
> > > > > > > > > >> > ret = connector_status_connected;
> > > > > > > > > >> >
> > > > > > > > > >> > if (ret != connector->status)
> > > > > > > > > >> > connector->epoch_counter += 1;
> > > > > > > > > >> >
> > > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > > > > >> >
> > > > > > > > > >> >
> > > > > > > > > >> >
> > > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > > > > >> >>+
> > > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > > > > >> >>+ if (!connector->state)
> > > > > > > > > >> >>+ continue;
> > > > > > > > > >> >>+
> > > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > > > > >> >>+ out_connector = connector;
> > > > > > > > > >>
> > > > > > > > > >>
> > > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > > > > >>
> > > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > > > > >> 0x63c
> > > > > > > > > >> [ 52.714568] Modules linked in:
> > > > > > > > > >>
> > > > > > > > > >> [ 52.724546] Call trace:
> > > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > > > > >>
> > > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > > > > >
> > > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > > > > >encoder.
> > > > > > > > > >
> > > > > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > > > > >
> > > > > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > > > > >
> > > > > > > > I'd say, yes, please.
> > > > > > >
> > > > > > > And I'd say no :)
> > > > > >
> > > > > > Fair enough :-)
> > > > > >
> > > > > > > There's no reason to deviate from the API other entities have here. It's
> > > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > > > > completely thought through and it's one of the part where it shows.
> > > > > > >
> > > > > > > We have two alternative solutions: Either the driver creates the
> > > > > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > > > > chain.
> > > > > > >
> > > > > > > We have the iterator already, we just need a new accessor to retrieve
> > > > > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > > > > next bridge and try again.
> > > > > >
> > > > > > The problem is that there is no guarantee that the the created connector
> > > > > > is created for or linked to any bridge. For example, for msm driver I'm
> > > > > > waiting for several series to go in, but after that I plan to work on
> > > > > > moving connector creation to the generic code within the msm driver.
> > > > > >
> > > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > > > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > > > > after the drm_bridge_attach() succeeds.
> > > > >
> > > > > Sure, but then I'd expect detect and get_modes to only be called *after*
> > > > > that connector has been created, right?
> > > >
> > > > Yes. But you can not get the connector by following bridge chain. Well,
> > > > unless you include encoder into the chain. If that's what you have had
> > > > in mind, then please excuse me, I didn't understand that from the
> > > > beginning.
> > >
> > > You can't include the encoder either, because the encoder doesn't have a
> > > connector assigned yet at that time.
> > >
> > > However, you can:
> > >
> > > - Store the bridge attach flags in drm_bridge
> > >
> > > - Create a hook that returns the connector a bridge creates, depending
> > > on the attach flags.
> > >
> > > - Create a helper that iterates over the next bridges until the
> > > previous hook returns !NULL. If it doesn't find anything, return
> > > NULL.
> > >
> > > AFAIK, it solves all the problems being discussed here, while dealing
> > > with legacy and new-style bridge drivers.
> >
> > I'm still fail to understand how does that solve the issue for new-style
> > bridges. How do we find the created drm_bridge_connector for them?
>
> Sigh, for some reason I was remembering that drm_bridge_connector was a
> bridge itself, which it isn't. My bad. But I guess it still applies. If
> we make drm_bridge_connector a bridge, then it works, doesn't it?
I'd rather not. This would complicate other bridges using
drm_bridge_connector (e.g. ite-it6263, ti-sn65dsi86)
> > > > But frankly speaking, I think it might be easier to pass down the
> > > > connector to the detect callback (as drm_connector_funcs.detect already
> > > > gets the connecor) rather than making bridge drivers go through the
> > > > chain to get the value that is already present in the caller function.
> > > >
> > > > (For some other usecases I'd totally agree with you, especially if the
> > > > connector isn't already available on the caller side).
> > >
> > > Still, we've tried to converge to the same API for all entities, it
> > > feels like a step backward to me.
> >
> > I'd argue here a bit. The drm_connector interface has connector here.
> > drm_bridge is an extension/subpart of the drm_connector, so it would be
> > logical to extend that interface.
>
> The drm_connector interface has the connector because it's a connector.
> Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
> pointer to drm_bridge atomic_check.
>
> I still think it goes against the trend and work we've been doing over
> the years. And we should at least *try* something different instead of
> just taking the easy way out. Or accepting to duplicate the helpers that
> started the discussion, or to create a connector directyl instead of
> using drm_bridge_connector for that driver.
I think passing drm_connector and drm_bridge matches the pattern started
by edid_read() and several hdmi_audio_*() callbacks. They are receiving
both the bridge and the connector for exactly the same reason - the
callbacks needs both _and_ the connector is well known in the calling
code.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-23 2:22 ` Dmitry Baryshkov
@ 2025-04-08 3:44 ` Andy Yan
2025-05-24 8:09 ` Dmitry Baryshkov
1 sibling, 0 replies; 52+ messages in thread
From: Andy Yan @ 2025-04-08 3:44 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Maxime Ripard, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Dmitry Baryshkov,
Simona Vetter, lumag
Hello Maxime and Dmitry,
At 2025-03-23 10:22:27, "Dmitry Baryshkov" <dmitry.baryshkov@oss.qualcomm.com> wrote:
>On Fri, Mar 21, 2025 at 10:46:56AM +0100, Maxime Ripard wrote:
>> On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
>> > On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
>> > > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
>> > > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
>> > > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
>> > > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
>> > > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
>> > > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
>> > > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > > > >Hi,
>> > > > > > > > > >
>> > > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
>> > > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
>> > > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
>> > > > > > > > > >> >>association between a bridge driver and its connector was lost.
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
>> > > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> > > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
>> > > > > > > > > >> >>atomic hooks bridges can implement.
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
>> > > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
>> > > > > > > > > >> >>interrupt handler.
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
>> > > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
>> > > > > > > > > >> >>life easier.
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> > > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> > > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> > > > > > > > > >> >>---
>> > > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> > > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
>> > > > > > > > > >> >> 2 files changed, 48 insertions(+)
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> > > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> > > > > > > > > >> >>
>> > > > > > > > > >> >> return NULL;
>> > > > > > > > > >> >> }
>> > > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> > > > > > > > > >> >>
>> > > > > > > > > >> >>+/**
>> > > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> > > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
>> > > > > > > > > >> >>+ * @ctx: Modeset locking context
>> > > > > > > > > >> >>+ *
>> > > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
>> > > > > > > > > >> >>+ * an @encoder.
>> > > > > > > > > >> >>+ *
>> > > > > > > > > >> >>+ * Returns:
>> > > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
>> > > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
>> > > > > > > > > >> >>+ * sequence must be restarted.
>> > > > > > > > > >> >>+ */
>> > > > > > > > > >> >>+struct drm_connector *
>> > > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> > > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
>> > > > > > > > > >> >>+{
>> > > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
>> > > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> > > > > > > > > >> >>+ struct drm_connector *connector;
>> > > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
>> > > > > > > > > >> >>+ int ret;
>> > > > > > > > > >> >>+
>> > > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > > > >> >>+ if (ret)
>> > > > > > > > > >> >>+ return ERR_PTR(ret);
>> > > > > > > > > >> >
>> > > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
>> > > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
>> > > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
>> > > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
>> > > > > > > > > >> >
>> > > > > > > > > >> >
>> > > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
>> > > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
>> > > > > > > > > >> > bool force)
>> > > > > > > > > >> >{
>> > > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > > > > > > > > >> > struct drm_device *dev = connector->dev;
>> > > > > > > > > >> > int ret;
>> > > > > > > > > >> >
>> > > > > > > > > >> > if (!ctx)
>> > > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
>> > > > > > > > > >> >
>> > > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > > > >> > if (ret)
>> > > > > > > > > >> > return ret;
>> > > > > > > > > >> >
>> > > > > > > > > >> > if (funcs->detect_ctx)
>> > > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
>> > > > > > > > > >> > else if (connector->funcs->detect)
>> > > > > > > > > >> > ret = connector->funcs->detect(connector, force);
>> > > > > > > > > >> > else
>> > > > > > > > > >> > ret = connector_status_connected;
>> > > > > > > > > >> >
>> > > > > > > > > >> > if (ret != connector->status)
>> > > > > > > > > >> > connector->epoch_counter += 1;
>> > > > > > > > > >> >
>> > > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
>> > > > > > > > > >> >
>> > > > > > > > > >> >
>> > > > > > > > > >> >
>> > > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>> > > > > > > > > >> >>+
>> > > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
>> > > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
>> > > > > > > > > >> >>+ if (!connector->state)
>> > > > > > > > > >> >>+ continue;
>> > > > > > > > > >> >>+
>> > > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
>> > > > > > > > > >> >>+ out_connector = connector;
>> > > > > > > > > >>
>> > > > > > > > > >>
>> > > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
>> > > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
>> > > > > > > > > >>
>> > > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
>> > > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
>> > > > > > > > > >> 0x63c
>> > > > > > > > > >> [ 52.714568] Modules linked in:
>> > > > > > > > > >>
>> > > > > > > > > >> [ 52.724546] Call trace:
>> > > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
>> > > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
>> > > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
>> > > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
>> > > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
>> > > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
>> > > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
>> > > > > > > > > >>
>> > > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
>> > > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
>> > > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
>> > > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
>> > > > > > > > > >
>> > > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
>> > > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
>> > > > > > > > > >encoder.
>> > > > > > > > > >
>> > > > > > > > > >If the connector is disabled, there's no associated encoder.
>> > > > > > > > >
>> > > > > > > > > Does this prove that this API is not suitable for my application scenario:
>> > > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
>> > > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
>> > > > > > > >
>> > > > > > > > I'd say, yes, please.
>> > > > > > >
>> > > > > > > And I'd say no :)
>> > > > > >
>> > > > > > Fair enough :-)
>> > > > > >
>> > > > > > > There's no reason to deviate from the API other entities have here. It's
>> > > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
>> > > > > > > completely thought through and it's one of the part where it shows.
>> > > > > > >
>> > > > > > > We have two alternative solutions: Either the driver creates the
>> > > > > > > connector itself, since it doesn't seem to use any downstream bridge
>> > > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
>> > > > > > > chain.
>> > > > > > >
>> > > > > > > We have the iterator already, we just need a new accessor to retrieve
>> > > > > > > the (optional) connector of a bridge, and if there's none, go to the
>> > > > > > > next bridge and try again.
>> > > > > >
>> > > > > > The problem is that there is no guarantee that the the created connector
>> > > > > > is created for or linked to any bridge. For example, for msm driver I'm
>> > > > > > waiting for several series to go in, but after that I plan to work on
>> > > > > > moving connector creation to the generic code within the msm driver.
>> > > > > >
>> > > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
>> > > > > > perfectly legit not to have a bridge which has "connector of a bridge".
>> > > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
>> > > > > > after the drm_bridge_attach() succeeds.
>> > > > >
>> > > > > Sure, but then I'd expect detect and get_modes to only be called *after*
>> > > > > that connector has been created, right?
>> > > >
>> > > > Yes. But you can not get the connector by following bridge chain. Well,
>> > > > unless you include encoder into the chain. If that's what you have had
>> > > > in mind, then please excuse me, I didn't understand that from the
>> > > > beginning.
>> > >
>> > > You can't include the encoder either, because the encoder doesn't have a
>> > > connector assigned yet at that time.
>> > >
>> > > However, you can:
>> > >
>> > > - Store the bridge attach flags in drm_bridge
>> > >
>> > > - Create a hook that returns the connector a bridge creates, depending
>> > > on the attach flags.
>> > >
>> > > - Create a helper that iterates over the next bridges until the
>> > > previous hook returns !NULL. If it doesn't find anything, return
>> > > NULL.
>> > >
>> > > AFAIK, it solves all the problems being discussed here, while dealing
>> > > with legacy and new-style bridge drivers.
>> >
>> > I'm still fail to understand how does that solve the issue for new-style
>> > bridges. How do we find the created drm_bridge_connector for them?
>>
>> Sigh, for some reason I was remembering that drm_bridge_connector was a
>> bridge itself, which it isn't. My bad. But I guess it still applies. If
>> we make drm_bridge_connector a bridge, then it works, doesn't it?
>
>I'd rather not. This would complicate other bridges using
>drm_bridge_connector (e.g. ite-it6263, ti-sn65dsi86)
>
>> > > > But frankly speaking, I think it might be easier to pass down the
>> > > > connector to the detect callback (as drm_connector_funcs.detect already
>> > > > gets the connecor) rather than making bridge drivers go through the
>> > > > chain to get the value that is already present in the caller function.
>> > > >
>> > > > (For some other usecases I'd totally agree with you, especially if the
>> > > > connector isn't already available on the caller side).
>> > >
>> > > Still, we've tried to converge to the same API for all entities, it
>> > > feels like a step backward to me.
>> >
>> > I'd argue here a bit. The drm_connector interface has connector here.
>> > drm_bridge is an extension/subpart of the drm_connector, so it would be
>> > logical to extend that interface.
>>
>> The drm_connector interface has the connector because it's a connector.
>> Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
>> pointer to drm_bridge atomic_check.
>>
>> I still think it goes against the trend and work we've been doing over
>> the years. And we should at least *try* something different instead of
>> just taking the easy way out. Or accepting to duplicate the helpers that
>> started the discussion, or to create a connector directyl instead of
>> using drm_bridge_connector for that driver.
>
>I think passing drm_connector and drm_bridge matches the pattern started
>by edid_read() and several hdmi_audio_*() callbacks. They are receiving
>both the bridge and the connector for exactly the same reason - the
>callbacks needs both _and_ the connector is well known in the calling
>code.
Can we have a closure here, and continue to move forward along the direction proposed by Dmitry?
>
>--
>With best wishes
>Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-03-23 2:22 ` Dmitry Baryshkov
2025-04-08 3:44 ` Andy Yan
@ 2025-05-24 8:09 ` Dmitry Baryshkov
2025-06-19 13:09 ` Maxime Ripard
1 sibling, 1 reply; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-05-24 8:09 UTC (permalink / raw)
To: Maxime Ripard
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Simona Vetter
On Sun, Mar 23, 2025 at 04:22:27AM +0200, Dmitry Baryshkov wrote:
> On Fri, Mar 21, 2025 at 10:46:56AM +0100, Maxime Ripard wrote:
> > On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
> > > On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
> > > > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> > > > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > > > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > > >Hi,
> > > > > > > > > > >
> > > > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > > > > > >> >>atomic hooks bridges can implement.
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > > > > > >> >>interrupt handler.
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > > > > > >> >>life easier.
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > > > > > >> >>---
> > > > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > > > > > >> >>
> > > > > > > > > > >> >> return NULL;
> > > > > > > > > > >> >> }
> > > > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > > > > > >> >>
> > > > > > > > > > >> >>+/**
> > > > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > > > > > >> >>+ *
> > > > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > > > > > >> >>+ * an @encoder.
> > > > > > > > > > >> >>+ *
> > > > > > > > > > >> >>+ * Returns:
> > > > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > > > > > >> >>+ * sequence must be restarted.
> > > > > > > > > > >> >>+ */
> > > > > > > > > > >> >>+struct drm_connector *
> > > > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > > > > > >> >>+{
> > > > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > > > > > >> >>+ struct drm_connector *connector;
> > > > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > > > > > >> >>+ int ret;
> > > > > > > > > > >> >>+
> > > > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > > >> >>+ if (ret)
> > > > > > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > > > > > >> >
> > > > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > > > > > >> >
> > > > > > > > > > >> >
> > > > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > > > > > >> > bool force)
> > > > > > > > > > >> >{
> > > > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > > > > > >> > int ret;
> > > > > > > > > > >> >
> > > > > > > > > > >> > if (!ctx)
> > > > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > > > > > >> >
> > > > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > > >> > if (ret)
> > > > > > > > > > >> > return ret;
> > > > > > > > > > >> >
> > > > > > > > > > >> > if (funcs->detect_ctx)
> > > > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > > > > > >> > else if (connector->funcs->detect)
> > > > > > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > > > > > >> > else
> > > > > > > > > > >> > ret = connector_status_connected;
> > > > > > > > > > >> >
> > > > > > > > > > >> > if (ret != connector->status)
> > > > > > > > > > >> > connector->epoch_counter += 1;
> > > > > > > > > > >> >
> > > > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > > > > > >> >
> > > > > > > > > > >> >
> > > > > > > > > > >> >
> > > > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > > > > > >> >>+
> > > > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > > > > > >> >>+ if (!connector->state)
> > > > > > > > > > >> >>+ continue;
> > > > > > > > > > >> >>+
> > > > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > > > > > >> >>+ out_connector = connector;
> > > > > > > > > > >>
> > > > > > > > > > >>
> > > > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > > > > > >>
> > > > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > > > > > >> 0x63c
> > > > > > > > > > >> [ 52.714568] Modules linked in:
> > > > > > > > > > >>
> > > > > > > > > > >> [ 52.724546] Call trace:
> > > > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > > > > > >>
> > > > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > > > > > >
> > > > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > > > > > >encoder.
> > > > > > > > > > >
> > > > > > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > > > > > >
> > > > > > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > > > > > >
> > > > > > > > > I'd say, yes, please.
> > > > > > > >
> > > > > > > > And I'd say no :)
> > > > > > >
> > > > > > > Fair enough :-)
> > > > > > >
> > > > > > > > There's no reason to deviate from the API other entities have here. It's
> > > > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > > > > > completely thought through and it's one of the part where it shows.
> > > > > > > >
> > > > > > > > We have two alternative solutions: Either the driver creates the
> > > > > > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > > > > > chain.
> > > > > > > >
> > > > > > > > We have the iterator already, we just need a new accessor to retrieve
> > > > > > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > > > > > next bridge and try again.
> > > > > > >
> > > > > > > The problem is that there is no guarantee that the the created connector
> > > > > > > is created for or linked to any bridge. For example, for msm driver I'm
> > > > > > > waiting for several series to go in, but after that I plan to work on
> > > > > > > moving connector creation to the generic code within the msm driver.
> > > > > > >
> > > > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > > > > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > > > > > after the drm_bridge_attach() succeeds.
> > > > > >
> > > > > > Sure, but then I'd expect detect and get_modes to only be called *after*
> > > > > > that connector has been created, right?
> > > > >
> > > > > Yes. But you can not get the connector by following bridge chain. Well,
> > > > > unless you include encoder into the chain. If that's what you have had
> > > > > in mind, then please excuse me, I didn't understand that from the
> > > > > beginning.
> > > >
> > > > You can't include the encoder either, because the encoder doesn't have a
> > > > connector assigned yet at that time.
> > > >
> > > > However, you can:
> > > >
> > > > - Store the bridge attach flags in drm_bridge
> > > >
> > > > - Create a hook that returns the connector a bridge creates, depending
> > > > on the attach flags.
> > > >
> > > > - Create a helper that iterates over the next bridges until the
> > > > previous hook returns !NULL. If it doesn't find anything, return
> > > > NULL.
> > > >
> > > > AFAIK, it solves all the problems being discussed here, while dealing
> > > > with legacy and new-style bridge drivers.
> > >
> > > I'm still fail to understand how does that solve the issue for new-style
> > > bridges. How do we find the created drm_bridge_connector for them?
> >
> > Sigh, for some reason I was remembering that drm_bridge_connector was a
> > bridge itself, which it isn't. My bad. But I guess it still applies. If
> > we make drm_bridge_connector a bridge, then it works, doesn't it?
>
> I'd rather not. This would complicate other bridges using
> drm_bridge_connector (e.g. ite-it6263, ti-sn65dsi86)
I should have probably explained this a bit more.
Currently each bridge has a link to the next bridge, obtained by lookup.
All bridges are attached, then we create a connector. Adding drm_bridge
into drm_bridge_connector would mean that the chain is mutated after all
bridges are attached. The bridge that assumes that is the last bridge in
the chain won't be the last one anymore.
Next, we get an immediate issue with DP bridge chains. In some cases
they rely on connector's fwnode being the fwnode of the last bridge so
that displayport AltMode driver can deliver HPD events properly via a
call to drm_connector_oob_hotplug_event(). Pushing one extra bridge
would raise a question, which OF node should be specified in that bridge
(and why), how will connector receive HPD calls, etc.
Last, but not least, we have bridge drivers which create
drm_bridge_connector on their own if DRM_BRIDGE_ATTACH_NO_CONNECTOR
wasn't specified. Adding one extra bridge might surprise them.
Generally I feel that while this looks appealing, it turns the framework
upside down and makes it more fragile.
>
> > > > > But frankly speaking, I think it might be easier to pass down the
> > > > > connector to the detect callback (as drm_connector_funcs.detect already
> > > > > gets the connecor) rather than making bridge drivers go through the
> > > > > chain to get the value that is already present in the caller function.
> > > > >
> > > > > (For some other usecases I'd totally agree with you, especially if the
> > > > > connector isn't already available on the caller side).
> > > >
> > > > Still, we've tried to converge to the same API for all entities, it
> > > > feels like a step backward to me.
> > >
> > > I'd argue here a bit. The drm_connector interface has connector here.
> > > drm_bridge is an extension/subpart of the drm_connector, so it would be
> > > logical to extend that interface.
> >
> > The drm_connector interface has the connector because it's a connector.
> > Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
> > pointer to drm_bridge atomic_check.
I wouldn't pass CRTC pointer, because drm_bridge isn't a part of the
CRTC. However it is clear that bridges reside between encoder and
connector. As I wrote later, there are enough drm_bridge calls which
recieve connector as an argument: get_modes(), edid_read(), all
hdmi_audio_*() and dp_audio_*() calls. Not passing connector to those
calls would make them much more complicated, especially in spite of
Luca's work on hot-pluggable DRM bridges.
> >
> > I still think it goes against the trend and work we've been doing over
> > the years. And we should at least *try* something different instead of
> > just taking the easy way out. Or accepting to duplicate the helpers that
> > started the discussion,
What kind of duplication do you have in mind? The helper in question had
an issue of causing a deadlock.
> or to create a connector directyl instead of
> > using drm_bridge_connector for that driver.
I'd rather not follow this path. I tend to assume that bridge drivers
are like bricks in a wall. We have been moving towards making all of
them accept DRM_BRIDGE_ATTACH_NO_CONNECTOR. Making a bridge fail to
attach with that flag would be a huuuge step backwards to me.
> I think passing drm_connector and drm_bridge matches the pattern started
> by edid_read() and several hdmi_audio_*() callbacks. They are receiving
> both the bridge and the connector for exactly the same reason - the
> callbacks needs both _and_ the connector is well known in the calling
> code.
Let's settle on some decision here.
--
With best wishes
uDmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-05-24 8:09 ` Dmitry Baryshkov
@ 2025-06-19 13:09 ` Maxime Ripard
2025-07-01 6:21 ` Andy Yan
0 siblings, 1 reply; 52+ messages in thread
From: Maxime Ripard @ 2025-06-19 13:09 UTC (permalink / raw)
To: Dmitry Baryshkov
Cc: Andy Yan, Maarten Lankhorst, Thomas Zimmermann, David Airlie,
Simona Vetter, Andrzej Hajda, Neil Armstrong, Robert Foss,
Laurent Pinchart, Jonas Karlman, Jernej Skrabec, Douglas Anderson,
Herve Codina, dri-devel, linux-kernel, Simona Vetter
[-- Attachment #1: Type: text/plain, Size: 17519 bytes --]
On Sat, May 24, 2025 at 11:09:48AM +0300, Dmitry Baryshkov wrote:
> On Sun, Mar 23, 2025 at 04:22:27AM +0200, Dmitry Baryshkov wrote:
> > On Fri, Mar 21, 2025 at 10:46:56AM +0100, Maxime Ripard wrote:
> > > On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
> > > > On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
> > > > > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
> > > > > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
> > > > > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
> > > > > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
> > > > > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
> > > > > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
> > > > > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > > > >Hi,
> > > > > > > > > > > >
> > > > > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
> > > > > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
> > > > > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
> > > > > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
> > > > > > > > > > > >> >>association between a bridge driver and its connector was lost.
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
> > > > > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
> > > > > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
> > > > > > > > > > > >> >>atomic hooks bridges can implement.
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
> > > > > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
> > > > > > > > > > > >> >>interrupt handler.
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
> > > > > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
> > > > > > > > > > > >> >>life easier.
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
> > > > > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
> > > > > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
> > > > > > > > > > > >> >>---
> > > > > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
> > > > > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
> > > > > > > > > > > >> >> 2 files changed, 48 insertions(+)
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
> > > > > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
> > > > > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >> return NULL;
> > > > > > > > > > > >> >> }
> > > > > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
> > > > > > > > > > > >> >>
> > > > > > > > > > > >> >>+/**
> > > > > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
> > > > > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
> > > > > > > > > > > >> >>+ * @ctx: Modeset locking context
> > > > > > > > > > > >> >>+ *
> > > > > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
> > > > > > > > > > > >> >>+ * an @encoder.
> > > > > > > > > > > >> >>+ *
> > > > > > > > > > > >> >>+ * Returns:
> > > > > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
> > > > > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
> > > > > > > > > > > >> >>+ * sequence must be restarted.
> > > > > > > > > > > >> >>+ */
> > > > > > > > > > > >> >>+struct drm_connector *
> > > > > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
> > > > > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
> > > > > > > > > > > >> >>+{
> > > > > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
> > > > > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
> > > > > > > > > > > >> >>+ struct drm_connector *connector;
> > > > > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
> > > > > > > > > > > >> >>+ int ret;
> > > > > > > > > > > >> >>+
> > > > > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > > > >> >>+ if (ret)
> > > > > > > > > > > >> >>+ return ERR_PTR(ret);
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
> > > > > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
> > > > > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
> > > > > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
> > > > > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
> > > > > > > > > > > >> > bool force)
> > > > > > > > > > > >> >{
> > > > > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
> > > > > > > > > > > >> > struct drm_device *dev = connector->dev;
> > > > > > > > > > > >> > int ret;
> > > > > > > > > > > >> >
> > > > > > > > > > > >> > if (!ctx)
> > > > > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
> > > > > > > > > > > >> >
> > > > > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
> > > > > > > > > > > >> > if (ret)
> > > > > > > > > > > >> > return ret;
> > > > > > > > > > > >> >
> > > > > > > > > > > >> > if (funcs->detect_ctx)
> > > > > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
> > > > > > > > > > > >> > else if (connector->funcs->detect)
> > > > > > > > > > > >> > ret = connector->funcs->detect(connector, force);
> > > > > > > > > > > >> > else
> > > > > > > > > > > >> > ret = connector_status_connected;
> > > > > > > > > > > >> >
> > > > > > > > > > > >> > if (ret != connector->status)
> > > > > > > > > > > >> > connector->epoch_counter += 1;
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >
> > > > > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
> > > > > > > > > > > >> >>+
> > > > > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
> > > > > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
> > > > > > > > > > > >> >>+ if (!connector->state)
> > > > > > > > > > > >> >>+ continue;
> > > > > > > > > > > >> >>+
> > > > > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
> > > > > > > > > > > >> >>+ out_connector = connector;
> > > > > > > > > > > >>
> > > > > > > > > > > >>
> > > > > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
> > > > > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
> > > > > > > > > > > >>
> > > > > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
> > > > > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
> > > > > > > > > > > >> 0x63c
> > > > > > > > > > > >> [ 52.714568] Modules linked in:
> > > > > > > > > > > >>
> > > > > > > > > > > >> [ 52.724546] Call trace:
> > > > > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
> > > > > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
> > > > > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
> > > > > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
> > > > > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
> > > > > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
> > > > > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
> > > > > > > > > > > >>
> > > > > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
> > > > > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
> > > > > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
> > > > > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
> > > > > > > > > > > >
> > > > > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
> > > > > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
> > > > > > > > > > > >encoder.
> > > > > > > > > > > >
> > > > > > > > > > > >If the connector is disabled, there's no associated encoder.
> > > > > > > > > > >
> > > > > > > > > > > Does this prove that this API is not suitable for my application scenario:
> > > > > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
> > > > > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
> > > > > > > > > >
> > > > > > > > > > I'd say, yes, please.
> > > > > > > > >
> > > > > > > > > And I'd say no :)
> > > > > > > >
> > > > > > > > Fair enough :-)
> > > > > > > >
> > > > > > > > > There's no reason to deviate from the API other entities have here. It's
> > > > > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
> > > > > > > > > completely thought through and it's one of the part where it shows.
> > > > > > > > >
> > > > > > > > > We have two alternative solutions: Either the driver creates the
> > > > > > > > > connector itself, since it doesn't seem to use any downstream bridge
> > > > > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
> > > > > > > > > chain.
> > > > > > > > >
> > > > > > > > > We have the iterator already, we just need a new accessor to retrieve
> > > > > > > > > the (optional) connector of a bridge, and if there's none, go to the
> > > > > > > > > next bridge and try again.
> > > > > > > >
> > > > > > > > The problem is that there is no guarantee that the the created connector
> > > > > > > > is created for or linked to any bridge. For example, for msm driver I'm
> > > > > > > > waiting for several series to go in, but after that I plan to work on
> > > > > > > > moving connector creation to the generic code within the msm driver.
> > > > > > > >
> > > > > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
> > > > > > > > perfectly legit not to have a bridge which has "connector of a bridge".
> > > > > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
> > > > > > > > after the drm_bridge_attach() succeeds.
> > > > > > >
> > > > > > > Sure, but then I'd expect detect and get_modes to only be called *after*
> > > > > > > that connector has been created, right?
> > > > > >
> > > > > > Yes. But you can not get the connector by following bridge chain. Well,
> > > > > > unless you include encoder into the chain. If that's what you have had
> > > > > > in mind, then please excuse me, I didn't understand that from the
> > > > > > beginning.
> > > > >
> > > > > You can't include the encoder either, because the encoder doesn't have a
> > > > > connector assigned yet at that time.
> > > > >
> > > > > However, you can:
> > > > >
> > > > > - Store the bridge attach flags in drm_bridge
> > > > >
> > > > > - Create a hook that returns the connector a bridge creates, depending
> > > > > on the attach flags.
> > > > >
> > > > > - Create a helper that iterates over the next bridges until the
> > > > > previous hook returns !NULL. If it doesn't find anything, return
> > > > > NULL.
> > > > >
> > > > > AFAIK, it solves all the problems being discussed here, while dealing
> > > > > with legacy and new-style bridge drivers.
> > > >
> > > > I'm still fail to understand how does that solve the issue for new-style
> > > > bridges. How do we find the created drm_bridge_connector for them?
> > >
> > > Sigh, for some reason I was remembering that drm_bridge_connector was a
> > > bridge itself, which it isn't. My bad. But I guess it still applies. If
> > > we make drm_bridge_connector a bridge, then it works, doesn't it?
> >
> > I'd rather not. This would complicate other bridges using
> > drm_bridge_connector (e.g. ite-it6263, ti-sn65dsi86)
>
> I should have probably explained this a bit more.
>
> Currently each bridge has a link to the next bridge, obtained by lookup.
> All bridges are attached, then we create a connector. Adding drm_bridge
> into drm_bridge_connector would mean that the chain is mutated after all
> bridges are attached. The bridge that assumes that is the last bridge in
> the chain won't be the last one anymore.
>
> Next, we get an immediate issue with DP bridge chains. In some cases
> they rely on connector's fwnode being the fwnode of the last bridge so
> that displayport AltMode driver can deliver HPD events properly via a
> call to drm_connector_oob_hotplug_event(). Pushing one extra bridge
> would raise a question, which OF node should be specified in that bridge
> (and why), how will connector receive HPD calls, etc.
>
> Last, but not least, we have bridge drivers which create
> drm_bridge_connector on their own if DRM_BRIDGE_ATTACH_NO_CONNECTOR
> wasn't specified. Adding one extra bridge might surprise them.
>
> Generally I feel that while this looks appealing, it turns the framework
> upside down and makes it more fragile.
>
> >
> > > > > > But frankly speaking, I think it might be easier to pass down the
> > > > > > connector to the detect callback (as drm_connector_funcs.detect already
> > > > > > gets the connecor) rather than making bridge drivers go through the
> > > > > > chain to get the value that is already present in the caller function.
> > > > > >
> > > > > > (For some other usecases I'd totally agree with you, especially if the
> > > > > > connector isn't already available on the caller side).
> > > > >
> > > > > Still, we've tried to converge to the same API for all entities, it
> > > > > feels like a step backward to me.
> > > >
> > > > I'd argue here a bit. The drm_connector interface has connector here.
> > > > drm_bridge is an extension/subpart of the drm_connector, so it would be
> > > > logical to extend that interface.
> > >
> > > The drm_connector interface has the connector because it's a connector.
> > > Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
> > > pointer to drm_bridge atomic_check.
>
> I wouldn't pass CRTC pointer, because drm_bridge isn't a part of the
> CRTC. However it is clear that bridges reside between encoder and
> connector. As I wrote later, there are enough drm_bridge calls which
> recieve connector as an argument: get_modes(), edid_read(), all
> hdmi_audio_*() and dp_audio_*() calls. Not passing connector to those
> calls would make them much more complicated, especially in spite of
> Luca's work on hot-pluggable DRM bridges.
The counterpoints being atomic_check, or
atomic_get_input/output_bus_fmts where having the crtc_state and
connector state just don't make sense. You can get them through
drm_atomic_state, and that's what we should be doing.
We basically have two cases: the hooks that have access to
drm_atomic_state, and the ones that don't. The former should just get
drm_bridge and drm_atomic_state. They don't need anything more.
For the latter, I guess you've convinced me and we could indeed pass the
connector. However, I'd still like the parameters to be consistent, and
hdmi_audio_* have the reversed order compared to get_modes and
edid_read. Could you make sure the audio callbacks are using the same
order doing so?
Thanks
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 273 bytes --]
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re:Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-06-19 13:09 ` Maxime Ripard
@ 2025-07-01 6:21 ` Andy Yan
2025-07-01 7:16 ` Dmitry Baryshkov
0 siblings, 1 reply; 52+ messages in thread
From: Andy Yan @ 2025-07-01 6:21 UTC (permalink / raw)
To: Maxime Ripard
Cc: Dmitry Baryshkov, Maarten Lankhorst, Thomas Zimmermann,
David Airlie, Simona Vetter, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
Douglas Anderson, Herve Codina, dri-devel, linux-kernel,
Simona Vetter
Hello all,
At 2025-06-19 21:09:09, "Maxime Ripard" <mripard@kernel.org> wrote:
>On Sat, May 24, 2025 at 11:09:48AM +0300, Dmitry Baryshkov wrote:
>> On Sun, Mar 23, 2025 at 04:22:27AM +0200, Dmitry Baryshkov wrote:
>> > On Fri, Mar 21, 2025 at 10:46:56AM +0100, Maxime Ripard wrote:
>> > > On Tue, Mar 18, 2025 at 09:00:29PM +0200, Dmitry Baryshkov wrote:
>> > > > On Tue, Mar 18, 2025 at 04:51:19PM +0100, Maxime Ripard wrote:
>> > > > > On Fri, Mar 14, 2025 at 08:28:22PM +0200, Dmitry Baryshkov wrote:
>> > > > > > On Fri, Mar 14, 2025 at 06:40:24PM +0100, Maxime Ripard wrote:
>> > > > > > > On Fri, Mar 14, 2025 at 09:59:36AM +0200, Dmitry Baryshkov wrote:
>> > > > > > > > On Fri, Mar 14, 2025 at 08:45:17AM +0100, Maxime Ripard wrote:
>> > > > > > > > > On Fri, Mar 14, 2025 at 07:52:35AM +0200, Dmitry Baryshkov wrote:
>> > > > > > > > > > On Fri, Mar 14, 2025 at 08:50:29AM +0800, Andy Yan wrote:
>> > > > > > > > > > > At 2025-03-13 19:55:33, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > > > > > >Hi,
>> > > > > > > > > > > >
>> > > > > > > > > > > >On Thu, Mar 13, 2025 at 04:09:54PM +0800, Andy Yan wrote:
>> > > > > > > > > > > >> At 2025-03-05 19:55:19, "Andy Yan" <andyshrk@163.com> wrote:
>> > > > > > > > > > > >> >At 2025-03-04 19:10:47, "Maxime Ripard" <mripard@kernel.org> wrote:
>> > > > > > > > > > > >> >>With the bridges switching over to drm_bridge_connector, the direct
>> > > > > > > > > > > >> >>association between a bridge driver and its connector was lost.
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>This is mitigated for atomic bridge drivers by the fact you can access
>> > > > > > > > > > > >> >>the encoder, and then call drm_atomic_get_old_connector_for_encoder() or
>> > > > > > > > > > > >> >>drm_atomic_get_new_connector_for_encoder() with drm_atomic_state.
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>This was also made easier by providing drm_atomic_state directly to all
>> > > > > > > > > > > >> >>atomic hooks bridges can implement.
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>However, bridge drivers don't have a way to access drm_atomic_state
>> > > > > > > > > > > >> >>outside of the modeset path, like from the hotplug interrupt path or any
>> > > > > > > > > > > >> >>interrupt handler.
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>Let's introduce a function to retrieve the connector currently assigned
>> > > > > > > > > > > >> >>to an encoder, without using drm_atomic_state, to make these drivers'
>> > > > > > > > > > > >> >>life easier.
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
>> > > > > > > > > > > >> >>Co-developed-by: Simona Vetter <simona.vetter@ffwll.ch>
>> > > > > > > > > > > >> >>Signed-off-by: Maxime Ripard <mripard@kernel.org>
>> > > > > > > > > > > >> >>---
>> > > > > > > > > > > >> >> drivers/gpu/drm/drm_atomic.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
>> > > > > > > > > > > >> >> include/drm/drm_atomic.h | 3 +++
>> > > > > > > > > > > >> >> 2 files changed, 48 insertions(+)
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > > > >> >>index 9ea2611770f43ce7ccba410406d5f2c528aab022..b926b132590e78f8d41d48eb4da4bccf170ee236 100644
>> > > > > > > > > > > >> >>--- a/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > > > >> >>+++ b/drivers/gpu/drm/drm_atomic.c
>> > > > > > > > > > > >> >>@@ -985,10 +985,55 @@ drm_atomic_get_new_connector_for_encoder(const struct drm_atomic_state *state,
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >> return NULL;
>> > > > > > > > > > > >> >> }
>> > > > > > > > > > > >> >> EXPORT_SYMBOL(drm_atomic_get_new_connector_for_encoder);
>> > > > > > > > > > > >> >>
>> > > > > > > > > > > >> >>+/**
>> > > > > > > > > > > >> >>+ * drm_atomic_get_connector_for_encoder - Get connector currently assigned to an encoder
>> > > > > > > > > > > >> >>+ * @encoder: The encoder to find the connector of
>> > > > > > > > > > > >> >>+ * @ctx: Modeset locking context
>> > > > > > > > > > > >> >>+ *
>> > > > > > > > > > > >> >>+ * This function finds and returns the connector currently assigned to
>> > > > > > > > > > > >> >>+ * an @encoder.
>> > > > > > > > > > > >> >>+ *
>> > > > > > > > > > > >> >>+ * Returns:
>> > > > > > > > > > > >> >>+ * The connector connected to @encoder, or an error pointer otherwise.
>> > > > > > > > > > > >> >>+ * When the error is EDEADLK, a deadlock has been detected and the
>> > > > > > > > > > > >> >>+ * sequence must be restarted.
>> > > > > > > > > > > >> >>+ */
>> > > > > > > > > > > >> >>+struct drm_connector *
>> > > > > > > > > > > >> >>+drm_atomic_get_connector_for_encoder(const struct drm_encoder *encoder,
>> > > > > > > > > > > >> >>+ struct drm_modeset_acquire_ctx *ctx)
>> > > > > > > > > > > >> >>+{
>> > > > > > > > > > > >> >>+ struct drm_connector_list_iter conn_iter;
>> > > > > > > > > > > >> >>+ struct drm_connector *out_connector = ERR_PTR(-EINVAL);
>> > > > > > > > > > > >> >>+ struct drm_connector *connector;
>> > > > > > > > > > > >> >>+ struct drm_device *dev = encoder->dev;
>> > > > > > > > > > > >> >>+ int ret;
>> > > > > > > > > > > >> >>+
>> > > > > > > > > > > >> >>+ ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > > > > > >> >>+ if (ret)
>> > > > > > > > > > > >> >>+ return ERR_PTR(ret);
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >It seems that this will cause a deadlock when called from a hotplug handling path,
>> > > > > > > > > > > >> >I have a WIP DP diver[0], which suggested by Dmitry to use this API from a
>> > > > > > > > > > > >> >&drm_bridge_funcs.detect callback to get the connector, as detect is called by drm_helper_probe_detect,
>> > > > > > > > > > > >> >which will hold connection_mutex first, so the deaklock happens:
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >drm_helper_probe_detect(struct drm_connector *connector,
>> > > > > > > > > > > >> > struct drm_modeset_acquire_ctx *ctx,
>> > > > > > > > > > > >> > bool force)
>> > > > > > > > > > > >> >{
>> > > > > > > > > > > >> > const struct drm_connector_helper_funcs *funcs = connector->helper_private;
>> > > > > > > > > > > >> > struct drm_device *dev = connector->dev;
>> > > > > > > > > > > >> > int ret;
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> > if (!ctx)
>> > > > > > > > > > > >> > return drm_helper_probe_detect_ctx(connector, force);
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> > ret = drm_modeset_lock(&dev->mode_config.connection_mutex, ctx);
>> > > > > > > > > > > >> > if (ret)
>> > > > > > > > > > > >> > return ret;
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> > if (funcs->detect_ctx)
>> > > > > > > > > > > >> > ret = funcs->detect_ctx(connector, ctx, force);
>> > > > > > > > > > > >> > else if (connector->funcs->detect)
>> > > > > > > > > > > >> > ret = connector->funcs->detect(connector, force);
>> > > > > > > > > > > >> > else
>> > > > > > > > > > > >> > ret = connector_status_connected;
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> > if (ret != connector->status)
>> > > > > > > > > > > >> > connector->epoch_counter += 1;
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >So I wonder can we let drm_bridge_funcs.detect pass a connector for this case ?
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >
>> > > > > > > > > > > >> >[0]https://lore.kernel.org/linux-rockchip/047EECFC-7E55-44EC-896F-13FE04333E4D@gmail.com/T/#m25bc53b79f5cc7bddfcb7aae5656f68df396f094
>> > > > > > > > > > > >> >>+
>> > > > > > > > > > > >> >>+ drm_connector_list_iter_begin(dev, &conn_iter);
>> > > > > > > > > > > >> >>+ drm_for_each_connector_iter(connector, &conn_iter) {
>> > > > > > > > > > > >> >>+ if (!connector->state)
>> > > > > > > > > > > >> >>+ continue;
>> > > > > > > > > > > >> >>+
>> > > > > > > > > > > >> >>+ if (encoder == connector->state->best_encoder) {
>> > > > > > > > > > > >> >>+ out_connector = connector;
>> > > > > > > > > > > >>
>> > > > > > > > > > > >>
>> > > > > > > > > > > >> When try to use this patch in my bridge driver, I found that the connector->state->best_encoder
>> > > > > > > > > > > >> maybe NULL when drm_bridge_funcs.detect or drm_bridge_funcs.detect_ctx is called:
>> > > > > > > > > > > >>
>> > > > > > > > > > > >> [ 52.713030] Invalid return value -22 for connector detection
>> > > > > > > > > > > >> [ 52.713539] WARNING: CPU: 7 PID: 288 at drivers/gpu/drm/drm_probe_helper.c:602 drm_helper_probe_single_connector_modes+0x5e0/
>> > > > > > > > > > > >> 0x63c
>> > > > > > > > > > > >> [ 52.714568] Modules linked in:
>> > > > > > > > > > > >>
>> > > > > > > > > > > >> [ 52.724546] Call trace:
>> > > > > > > > > > > >> [ 52.724762] drm_helper_probe_single_connector_modes+0x5e0/0x63c (P)
>> > > > > > > > > > > >> [ 52.725319] drm_mode_getconnector+0x2a4/0x488
>> > > > > > > > > > > >> [ 52.725711] drm_ioctl_kernel+0xb4/0x11c
>> > > > > > > > > > > >> [ 52.726057] drm_ioctl+0x22c/0x544
>> > > > > > > > > > > >> [ 52.726358] __arm64_sys_ioctl+0xac/0xe0
>> > > > > > > > > > > >> [ 52.726706] invoke_syscall+0x44/0x100
>> > > > > > > > > > > >> [ 52.727039] el0_svc_common.constprop.0+0x3c/0xd4
>> > > > > > > > > > > >>
>> > > > > > > > > > > >> This is because best_encoder is set by set_best_encoder, which is called from
>> > > > > > > > > > > >> drm_atomic_helper_check_modeset. When we call drm_mode_getconnector
>> > > > > > > > > > > >> for the first time, the functions mentioned above have not been called yet,
>> > > > > > > > > > > >> then we can't match the encoder from connector->state->best_encoder for this case.
>> > > > > > > > > > > >
>> > > > > > > > > > > >As far as I'm concerned, it's by design. Encoders and connectors have
>> > > > > > > > > > > >1:N relationship, and only once a connector has been enabled it has an
>> > > > > > > > > > > >encoder.
>> > > > > > > > > > > >
>> > > > > > > > > > > >If the connector is disabled, there's no associated encoder.
>> > > > > > > > > > >
>> > > > > > > > > > > Does this prove that this API is not suitable for my application scenario:
>> > > > > > > > > > > Get the connector in the bridge's .detect callback, so this means that I may
>> > > > > > > > > > > still need to modify the bridge's connector callback so that it can pass the connector ?
>> > > > > > > > > >
>> > > > > > > > > > I'd say, yes, please.
>> > > > > > > > >
>> > > > > > > > > And I'd say no :)
>> > > > > > > >
>> > > > > > > > Fair enough :-)
>> > > > > > > >
>> > > > > > > > > There's no reason to deviate from the API other entities have here. It's
>> > > > > > > > > just that the switch to DRM_BRIDGE_ATTACH_NO_CONNECTOR hasn't been
>> > > > > > > > > completely thought through and it's one of the part where it shows.
>> > > > > > > > >
>> > > > > > > > > We have two alternative solutions: Either the driver creates the
>> > > > > > > > > connector itself, since it doesn't seem to use any downstream bridge
>> > > > > > > > > anyway, or we need a new bridge helper to find the connector on a bridge
>> > > > > > > > > chain.
>> > > > > > > > >
>> > > > > > > > > We have the iterator already, we just need a new accessor to retrieve
>> > > > > > > > > the (optional) connector of a bridge, and if there's none, go to the
>> > > > > > > > > next bridge and try again.
>> > > > > > > >
>> > > > > > > > The problem is that there is no guarantee that the the created connector
>> > > > > > > > is created for or linked to any bridge. For example, for msm driver I'm
>> > > > > > > > waiting for several series to go in, but after that I plan to work on
>> > > > > > > > moving connector creation to the generic code within the msm driver.
>> > > > > > > >
>> > > > > > > > In other words, with DRM_BRIDGE_ATTACH_NO_CONNECTOR in place it is
>> > > > > > > > perfectly legit not to have a bridge which has "connector of a bridge".
>> > > > > > > > It is possible to create drm_bridge_connector on the drm_encoder's side
>> > > > > > > > after the drm_bridge_attach() succeeds.
>> > > > > > >
>> > > > > > > Sure, but then I'd expect detect and get_modes to only be called *after*
>> > > > > > > that connector has been created, right?
>> > > > > >
>> > > > > > Yes. But you can not get the connector by following bridge chain. Well,
>> > > > > > unless you include encoder into the chain. If that's what you have had
>> > > > > > in mind, then please excuse me, I didn't understand that from the
>> > > > > > beginning.
>> > > > >
>> > > > > You can't include the encoder either, because the encoder doesn't have a
>> > > > > connector assigned yet at that time.
>> > > > >
>> > > > > However, you can:
>> > > > >
>> > > > > - Store the bridge attach flags in drm_bridge
>> > > > >
>> > > > > - Create a hook that returns the connector a bridge creates, depending
>> > > > > on the attach flags.
>> > > > >
>> > > > > - Create a helper that iterates over the next bridges until the
>> > > > > previous hook returns !NULL. If it doesn't find anything, return
>> > > > > NULL.
>> > > > >
>> > > > > AFAIK, it solves all the problems being discussed here, while dealing
>> > > > > with legacy and new-style bridge drivers.
>> > > >
>> > > > I'm still fail to understand how does that solve the issue for new-style
>> > > > bridges. How do we find the created drm_bridge_connector for them?
>> > >
>> > > Sigh, for some reason I was remembering that drm_bridge_connector was a
>> > > bridge itself, which it isn't. My bad. But I guess it still applies. If
>> > > we make drm_bridge_connector a bridge, then it works, doesn't it?
>> >
>> > I'd rather not. This would complicate other bridges using
>> > drm_bridge_connector (e.g. ite-it6263, ti-sn65dsi86)
>>
>> I should have probably explained this a bit more.
>>
>> Currently each bridge has a link to the next bridge, obtained by lookup.
>> All bridges are attached, then we create a connector. Adding drm_bridge
>> into drm_bridge_connector would mean that the chain is mutated after all
>> bridges are attached. The bridge that assumes that is the last bridge in
>> the chain won't be the last one anymore.
>>
>> Next, we get an immediate issue with DP bridge chains. In some cases
>> they rely on connector's fwnode being the fwnode of the last bridge so
>> that displayport AltMode driver can deliver HPD events properly via a
>> call to drm_connector_oob_hotplug_event(). Pushing one extra bridge
>> would raise a question, which OF node should be specified in that bridge
>> (and why), how will connector receive HPD calls, etc.
>>
>> Last, but not least, we have bridge drivers which create
>> drm_bridge_connector on their own if DRM_BRIDGE_ATTACH_NO_CONNECTOR
>> wasn't specified. Adding one extra bridge might surprise them.
>>
>> Generally I feel that while this looks appealing, it turns the framework
>> upside down and makes it more fragile.
>>
>> >
>> > > > > > But frankly speaking, I think it might be easier to pass down the
>> > > > > > connector to the detect callback (as drm_connector_funcs.detect already
>> > > > > > gets the connecor) rather than making bridge drivers go through the
>> > > > > > chain to get the value that is already present in the caller function.
>> > > > > >
>> > > > > > (For some other usecases I'd totally agree with you, especially if the
>> > > > > > connector isn't already available on the caller side).
>> > > > >
>> > > > > Still, we've tried to converge to the same API for all entities, it
>> > > > > feels like a step backward to me.
>> > > >
>> > > > I'd argue here a bit. The drm_connector interface has connector here.
>> > > > drm_bridge is an extension/subpart of the drm_connector, so it would be
>> > > > logical to extend that interface.
>> > >
>> > > The drm_connector interface has the connector because it's a connector.
>> > > Just like CRTC atomic_check has a crtc, but you wouldn't pass the crtc
>> > > pointer to drm_bridge atomic_check.
>>
>> I wouldn't pass CRTC pointer, because drm_bridge isn't a part of the
>> CRTC. However it is clear that bridges reside between encoder and
>> connector. As I wrote later, there are enough drm_bridge calls which
>> recieve connector as an argument: get_modes(), edid_read(), all
>> hdmi_audio_*() and dp_audio_*() calls. Not passing connector to those
>> calls would make them much more complicated, especially in spite of
>> Luca's work on hot-pluggable DRM bridges.
>
>The counterpoints being atomic_check, or
>atomic_get_input/output_bus_fmts where having the crtc_state and
>connector state just don't make sense. You can get them through
>drm_atomic_state, and that's what we should be doing.
>
>We basically have two cases: the hooks that have access to
>drm_atomic_state, and the ones that don't. The former should just get
>drm_bridge and drm_atomic_state. They don't need anything more.
>
>For the latter, I guess you've convinced me and we could indeed pass the
>connector. However, I'd still like the parameters to be consistent, and
Does this mean that we have the meaningful closure to the discussion
and we can go on with this PATCH[0]
>hdmi_audio_* have the reversed order compared to get_modes and
>edid_read. Could you make sure the audio callbacks are using the same
>order doing so?
And for the parameters order, Dmitry, if you agree, I can send a patch
to make them consistent.
[0]https://lore.kernel.org/dri-devel/20250321085345.136380-2-andyshrk@163.com/
[0]
>
>Thanks
>
>Maxime
^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder
2025-07-01 6:21 ` Andy Yan
@ 2025-07-01 7:16 ` Dmitry Baryshkov
0 siblings, 0 replies; 52+ messages in thread
From: Dmitry Baryshkov @ 2025-07-01 7:16 UTC (permalink / raw)
To: Andy Yan, Maxime Ripard
Cc: Maarten Lankhorst, Thomas Zimmermann, David Airlie, Simona Vetter,
Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, Douglas Anderson, Herve Codina,
dri-devel, linux-kernel, Simona Vetter
On 01/07/2025 09:21, Andy Yan wrote:
> Hello all,
>
> At 2025-06-19 21:09:09, "Maxime Ripard" <mripard@kernel.org> wrote:
>> hdmi_audio_* have the reversed order compared to get_modes and
>> edid_read. Could you make sure the audio callbacks are using the same
>> order doing so?
>
> And for the parameters order, Dmitry, if you agree, I can send a patch
> to make them consistent.
Yes, please.
--
With best wishes
Dmitry
^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2025-07-01 7:16 UTC | newest]
Thread overview: 52+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-04 11:10 [PATCH v5 00/16] drm/bridge: Various quality of life improvements Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 01/16] drm/bridge: Add encoder parameter to drm_bridge_funcs.attach Maxime Ripard
2025-03-05 13:04 ` Luca Ceresoli
2025-03-04 11:10 ` [PATCH v5 02/16] drm/bridge: Provide a helper to retrieve current bridge state Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 03/16] drm/tests: Add kunit tests for bridges Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 04/16] drm/atomic: Introduce helper to lookup connector by encoder Maxime Ripard
2025-03-05 11:55 ` Andy Yan
2025-03-05 13:19 ` [PATCH " Maxime Ripard
2025-03-05 20:13 ` Dmitry Baryshkov
2025-03-06 1:16 ` Andy Yan
2025-03-06 7:10 ` Maxime Ripard
2025-03-06 15:41 ` Simona Vetter
2025-03-07 1:08 ` Andy Yan
2025-03-07 7:30 ` Andy Yan
2025-03-07 13:25 ` Simona Vetter
2025-03-11 6:42 ` Andy Yan
2025-03-13 8:09 ` Andy Yan
2025-03-13 11:55 ` [PATCH " Maxime Ripard
2025-03-14 0:50 ` Andy Yan
2025-03-14 5:52 ` Dmitry Baryshkov
2025-03-14 7:45 ` Maxime Ripard
2025-03-14 7:59 ` Dmitry Baryshkov
2025-03-14 17:40 ` Maxime Ripard
2025-03-14 18:28 ` Dmitry Baryshkov
2025-03-18 15:51 ` Maxime Ripard
2025-03-18 19:00 ` Dmitry Baryshkov
2025-03-19 7:21 ` Andy Yan
2025-03-21 9:46 ` Maxime Ripard
2025-03-23 2:22 ` Dmitry Baryshkov
2025-04-08 3:44 ` Andy Yan
2025-05-24 8:09 ` Dmitry Baryshkov
2025-06-19 13:09 ` Maxime Ripard
2025-07-01 6:21 ` Andy Yan
2025-07-01 7:16 ` Dmitry Baryshkov
2025-03-06 8:21 ` Herve Codina
2025-03-06 15:44 ` Simona Vetter
2025-03-04 11:10 ` [PATCH v5 05/16] drm/tests: helpers: Create new helper to enable output Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 06/16] drm/tests: hdmi_state_helpers: Switch to new helper Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 07/16] drm/tests: Create tests for drm_atomic Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 08/16] drm/bridge: Add helper to reset bridge pipeline Maxime Ripard
2025-03-06 8:12 ` Herve Codina
2025-03-06 15:46 ` Simona Vetter
2025-03-04 11:10 ` [PATCH v5 09/16] drm/tests: bridge: Provide tests for drm_bridge_helper_reset_crtc Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 10/16] drm/bridge: ti-sn65dsi83: Switch to drm_bridge_helper_reset_crtc Maxime Ripard
2025-03-06 8:09 ` Herve Codina
2025-03-04 11:10 ` [PATCH v5 11/16] drm/bridge: Introduce drm_bridge_is_atomic() helper Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 12/16] drm/bridge: cdns-csi: Switch to atomic helpers Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 13/16] drm/bridge: tc358775: Switch to atomic commit Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 14/16] drm/bridge: tc358768: Stop disabling when failing to enable Maxime Ripard
2025-03-06 15:48 ` Simona Vetter
2025-03-04 11:10 ` [PATCH v5 15/16] drm/bridge: tc358768: Convert to atomic helpers Maxime Ripard
2025-03-04 11:10 ` [PATCH v5 16/16] drm/bridge: ti-sn65dsi86: Remove drm_encoder->crtc use Maxime Ripard
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).