* [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 9:04 ` Laurent Pinchart
0 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 9:04 UTC (permalink / raw)
To: dri-devel
Cc: linux-renesas-soc, Archit Taneja, Boris Brezillon, Jingoo Han,
Inki Dae, Joonyoung Shim, Seung-Woo Kim, Kyungmin Park,
Stefan Agner, Alison Wang, Xinliang Liu, Rongrong Zou,
Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu, Rob Clark,
Benjamin Gaignard, Vincent Abriou, Ma
Instead of linking encoders and bridges in every driver (and getting it
wrong half of the time, as many drivers forget to set the drm_bridge
encoder pointer), do so in core code. The drm_bridge_attach() function
needs the encoder and optional previous bridge to perform that task,
update all the callers.
Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
---
drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
drivers/gpu/drm/imx/imx-ldb.c | 6 +--
drivers/gpu/drm/imx/parallel-display.c | 4 +-
drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
drivers/gpu/drm/sti/sti_dvo.c | 3 +-
drivers/gpu/drm/sti/sti_hda.c | 3 +-
drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
include/drm/drm_bridge.h | 3 +-
23 files changed, 83 insertions(+), 103 deletions(-)
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
index 6119b5085501..e7799b6ee829 100644
--- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
of_node_put(np);
if (bridge) {
- output->encoder.bridge = bridge;
- bridge->encoder = &output->encoder;
- ret = drm_bridge_attach(dev, bridge);
+ ret = drm_bridge_attach(&output->encoder, bridge, NULL);
if (!ret)
return 0;
}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 6e0447f329a2..1835f1fdad19 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
dp->bridge = bridge;
- dp->encoder->bridge = bridge;
bridge->driver_private = dp;
- bridge->encoder = dp->encoder;
bridge->funcs = &analogix_dp_bridge_funcs;
- ret = drm_bridge_attach(drm_dev, bridge);
+ ret = drm_bridge_attach(dp->encoder, bridge, NULL);
if (ret) {
DRM_ERROR("failed to attach drm bridge\n");
return -EINVAL;
diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
index b71088dab268..432e0e3fff72 100644
--- a/drivers/gpu/drm/bridge/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/dw-hdmi.c
@@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
hdmi->bridge = bridge;
bridge->driver_private = hdmi;
bridge->funcs = &dw_hdmi_bridge_funcs;
- ret = drm_bridge_attach(drm, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return -EINVAL;
}
- encoder->bridge = bridge;
hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
drm_connector_helper_add(&hdmi->connector,
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
index 0ee052b7c21a..850bd6509ef1 100644
--- a/drivers/gpu/drm/drm_bridge.c
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -26,6 +26,7 @@
#include <linux/mutex.h>
#include <drm/drm_bridge.h>
+#include <drm/drm_encoder.h>
/**
* DOC: overview
@@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
EXPORT_SYMBOL(drm_bridge_remove);
/**
- * drm_bridge_attach - associate given bridge to our DRM device
+ * drm_bridge_attach - attach the bridge to an encoder's chain
*
- * @dev: DRM device
- * @bridge: bridge control structure
+ * @encoder: DRM encoder
+ * @bridge: bridge to attach
+ * @previous: previous bridge in the chain (optional)
*
- * Called by a kms driver to link one of our encoder/bridge to the given
- * bridge.
+ * Called by a kms driver to link the bridge to an encoder's chain. The previous
+ * argument specifies the previous bridge in the chain. If NULL, the bridge is
+ * linked directly at the encoder's output. Otherwise it is linked at the
+ * previous bridge's output.
*
- * Note that setting up links between the bridge and our encoder/bridge
- * objects needs to be handled by the kms driver itself.
+ * If non-NULL the previous bridge must be already attached by a call to this
+ * function.
*
* RETURNS:
* Zero on success, error code on failure
*/
-int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
+ struct drm_bridge *previous)
{
- if (!dev || !bridge)
+ int ret;
+
+ if (!encoder || !bridge)
+ return -EINVAL;
+
+ if (previous && (!previous->dev || previous->encoder != encoder))
return -EINVAL;
if (bridge->dev)
return -EBUSY;
- bridge->dev = dev;
+ bridge->dev = encoder->dev;
+ bridge->encoder = encoder;
+
+ if (bridge->funcs->attach) {
+ ret = bridge->funcs->attach(bridge);
+ if (ret < 0) {
+ bridge->dev = NULL;
+ bridge->encoder = NULL;
+ return ret;
+ }
+ }
- if (bridge->funcs->attach)
- return bridge->funcs->attach(bridge);
+ if (previous)
+ previous->next = bridge;
+ else
+ encoder->bridge = bridge;
return 0;
}
diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
index 7bae08c2bf0a..ba7be6169339 100644
--- a/drivers/gpu/drm/drm_simple_kms_helper.c
+++ b/drivers/gpu/drm/drm_simple_kms_helper.c
@@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
struct drm_bridge *bridge)
{
- bridge->encoder = &pipe->encoder;
- pipe->encoder.bridge = bridge;
- return drm_bridge_attach(pipe->encoder.dev, bridge);
+ return drm_bridge_attach(&pipe->encoder, bridge, NULL);
}
EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
index 528229faffe4..1ef0be338b85 100644
--- a/drivers/gpu/drm/exynos/exynos_dp.c
+++ b/drivers/gpu/drm/exynos/exynos_dp.c
@@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
struct drm_connector *connector)
{
struct exynos_dp_device *dp = to_dp(plat_data);
- struct drm_encoder *encoder = &dp->encoder;
int ret;
drm_connector_register(connector);
@@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
/* Pre-empt DP connector creation if there's a bridge */
if (dp->ptn_bridge) {
- bridge->next = dp->ptn_bridge;
- dp->ptn_bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
+ ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
if (ret) {
DRM_ERROR("Failed to attach bridge to drm\n");
bridge->next = NULL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
index e07cb1fe4860..812e2ec0761d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
@@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
}
bridge = of_drm_find_bridge(dsi->bridge_node);
- if (bridge) {
- encoder->bridge = bridge;
- drm_bridge_attach(drm_dev, bridge);
- }
+ if (bridge)
+ drm_bridge_attach(encoder, bridge, NULL);
return mipi_dsi_host_register(&dsi->dsi_host);
}
diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
index e1dd75b18118..3ad76423c60d 100644
--- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
+++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
@@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
if (!bridge)
return -ENODEV;
- fsl_dev->encoder.bridge = bridge;
- bridge->encoder = &fsl_dev->encoder;
-
- return drm_bridge_attach(fsl_dev->drm, bridge);
+ return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
}
int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
index 998452ad0fcb..1737e98bc10a 100644
--- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
+++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
@@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
int ret;
/* associate the bridge to dsi encoder */
- encoder->bridge = bridge;
- bridge->encoder = encoder;
-
- ret = drm_bridge_attach(dev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
DRM_ERROR("failed to attach external bridge\n");
return ret;
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index b300998dce7d..2fcb579f5489 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
DRM_MODE_ENCODER_LVDS, NULL);
if (imx_ldb_ch->bridge) {
- imx_ldb_ch->bridge->encoder = encoder;
-
- imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
- ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
+ ret = drm_bridge_attach(&imx_ldb_ch->encoder,
+ imx_ldb_ch->bridge, NULL);
if (ret) {
DRM_ERROR("Failed to initialize bridge with drm\n");
return ret;
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index d796ada2a47a..2d80c769f56b 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
drm_panel_attach(imxpd->panel, &imxpd->connector);
if (imxpd->bridge) {
- imxpd->bridge->encoder = encoder;
- encoder->bridge = imxpd->bridge;
- ret = drm_bridge_attach(drm, imxpd->bridge);
+ ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
if (ret < 0) {
dev_err(imxpd->dev, "failed to attach bridge: %d\n",
ret);
diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
index 0186e500d2a5..3cced1c522fd 100644
--- a/drivers/gpu/drm/mediatek/mtk_dpi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
@@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
struct mtk_dpi {
struct mtk_ddp_comp ddp_comp;
struct drm_encoder encoder;
+ struct drm_bridge *bridge;
void __iomem *regs;
struct device *dev;
struct clk *engine_clk;
@@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
/* Currently DPI0 is fixed to be driven by OVL1 */
dpi->encoder.possible_crtcs = BIT(1);
- dpi->encoder.bridge->encoder = &dpi->encoder;
- ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
+ ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
if (ret) {
dev_err(dev, "Failed to attach bridge: %d\n", ret);
goto err_cleanup;
@@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
- dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
+ dpi->bridge = of_drm_find_bridge(bridge_node);
of_node_put(bridge_node);
- if (!dpi->encoder.bridge)
+ if (!dpi->bridge)
return -EPROBE_DEFER;
comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
index 28b2044ed9f2..2ac0f1abba86 100644
--- a/drivers/gpu/drm/mediatek/mtk_dsi.c
+++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
@@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
.get_modes = mtk_dsi_connector_get_modes,
};
-static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
- struct drm_encoder *encoder)
-{
- int ret;
-
- if (!bridge)
- return -ENOENT;
-
- encoder->bridge = bridge;
- bridge->encoder = encoder;
- ret = drm_bridge_attach(encoder->dev, bridge);
- if (ret) {
- DRM_ERROR("Failed to attach bridge to drm\n");
- encoder->bridge = NULL;
- bridge->encoder = NULL;
- }
-
- return ret;
-}
-
static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
{
int ret;
@@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
dsi->encoder.possible_crtcs = 1;
/* If there's a bridge, attach to it and let it create the connector */
- ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
+ ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
if (ret) {
+ DRM_ERROR("Failed to attach bridge to drm\n");
+
/* Otherwise create our own connector and attach to a panel */
ret = mtk_dsi_create_connector(drm, dsi);
if (ret)
diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
index 71227deef21b..5ca1b0fbf937 100644
--- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
+++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
@@ -149,6 +149,7 @@ struct hdmi_audio_param {
struct mtk_hdmi {
struct drm_bridge bridge;
+ struct drm_bridge *next_bridge;
struct drm_connector conn;
struct device *dev;
struct phy *phy;
@@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
return ret;
}
- if (bridge->next) {
- bridge->next->encoder = bridge->encoder;
- ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
+ if (hdmi->next_bridge) {
+ ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
+ bridge);
if (ret) {
dev_err(hdmi->dev,
"Failed to attach external bridge: %d\n", ret);
@@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
of_node_put(ep);
if (!of_device_is_compatible(remote, "hdmi-connector")) {
- hdmi->bridge.next = of_drm_find_bridge(remote);
- if (!hdmi->bridge.next) {
+ hdmi->next_bridge = of_drm_find_bridge(remote);
+ if (!hdmi->next_bridge) {
dev_err(dev, "Waiting for external bridge\n");
of_node_put(remote);
return -EPROBE_DEFER;
diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
index c8d1f19c9a6d..2bd8dad76105 100644
--- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
+++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
@@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct drm_bridge *bridge = NULL;
struct dsi_bridge *dsi_bridge;
+ struct drm_encoder *encoder;
int ret;
dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
@@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
dsi_bridge->id = id;
+ /*
+ * HACK: we may not know the external DSI bridge device's mode
+ * flags here. We'll get to know them only when the device
+ * attaches to the dsi host. For now, assume the bridge supports
+ * DSI video mode
+ */
+ encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
+
bridge = &dsi_bridge->base;
bridge->funcs = &dsi_mgr_bridge_funcs;
- ret = drm_bridge_attach(msm_dsi->dev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret)
goto fail;
@@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
/* link the internal dsi bridge to the external bridge */
- int_bridge->next = ext_bridge;
- /* set the external bridge's encoder as dsi's encoder */
- ext_bridge->encoder = encoder;
-
- drm_bridge_attach(dev, ext_bridge);
+ drm_bridge_attach(encoder, ext_bridge, int_bridge);
/*
* we need the drm_connector created by the external bridge
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
index 2bc73f82f3f5..931a5c97cccf 100644
--- a/drivers/gpu/drm/msm/edp/edp_bridge.c
+++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
@@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
bridge = &edp_bridge->base;
bridge->funcs = &edp_bridge_funcs;
- ret = drm_bridge_attach(edp->dev, bridge);
+ ret = drm_bridge_attach(edp->encoder, bridge, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index bacbd5d8df0e..4e6d1bf27474 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
bridge = &hdmi_bridge->base;
bridge->funcs = &msm_hdmi_bridge_funcs;
- ret = drm_bridge_attach(hdmi->dev, bridge);
+ ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
if (ret)
goto fail;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index a1a2c5e7822c..933a2547798e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
hdmienc->renc = renc;
/* Link the bridge to the encoder. */
- bridge->encoder = encoder;
- encoder->bridge = bridge;
-
- ret = drm_bridge_attach(rcdu->ddev, bridge);
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
drm_encoder_cleanup(encoder);
return ret;
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
index e8c1ed08a9f7..411dc6ec976e 100644
--- a/drivers/gpu/drm/sti/sti_dvo.c
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
return err;
}
- err = drm_bridge_attach(drm_dev, bridge);
+ err = drm_bridge_attach(encoder, bridge, NULL);
if (err) {
DRM_ERROR("Failed to attach bridge\n");
return err;
}
dvo->bridge = bridge;
- encoder->bridge = bridge;
connector->encoder = encoder;
dvo->encoder = encoder;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index e7c243f70870..5b1855e44f87 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
bridge->driver_private = hda;
bridge->funcs = &sti_hda_bridge_funcs;
- drm_bridge_attach(drm_dev, bridge);
+ drm_bridge_attach(encoder, bridge, NULL);
- encoder->bridge = bridge;
connector->encoder = encoder;
drm_connector = (struct drm_connector *)connector;
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index 376b0763c874..f0af1ae82ee9 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
bridge->driver_private = hdmi;
bridge->funcs = &sti_hdmi_bridge_funcs;
- drm_bridge_attach(drm_dev, bridge);
+ drm_bridge_attach(encoder, bridge, NULL);
- encoder->bridge = bridge;
connector->encoder = encoder;
drm_connector = (struct drm_connector *)connector;
diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
index c3ff10f559cc..ce071c17134b 100644
--- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
+++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
@@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
struct sun4i_drv *drv = drm->dev_private;
struct sun4i_tcon *tcon = drv->tcon;
struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
struct sun4i_rgb *rgb;
int ret;
@@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
encoder = &rgb->encoder;
tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
- encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
- if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
+ bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
+ if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
return 0;
}
@@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
}
}
- if (!IS_ERR(encoder->bridge)) {
- encoder->bridge->encoder = &rgb->encoder;
-
- ret = drm_bridge_attach(drm, encoder->bridge);
+ if (!IS_ERR(bridge)) {
+ ret = drm_bridge_attach(encoder, bridge, NULL);
if (ret) {
dev_err(drm->dev, "Couldn't attach our bridge\n");
goto err_cleanup_connector;
}
- } else {
- encoder->bridge = NULL;
}
return 0;
diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
index 530a1d6e8cde..94e5ee96b3b5 100644
--- a/include/drm/drm_bridge.h
+++ b/include/drm/drm_bridge.h
@@ -201,7 +201,8 @@ struct drm_bridge {
int drm_bridge_add(struct drm_bridge *bridge);
void drm_bridge_remove(struct drm_bridge *bridge);
struct drm_bridge *of_drm_find_bridge(struct device_node *np);
-int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
+int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
+ struct drm_bridge *previous);
void drm_bridge_detach(struct drm_bridge *bridge);
bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
--
Regards,
Laurent Pinchart
^ permalink raw reply related [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:04 ` Laurent Pinchart
@ 2016-11-29 9:35 ` Daniel Vetter
-1 siblings, 0 replies; 100+ messages in thread
From: Daniel Vetter @ 2016-11-29 9:35 UTC (permalink / raw)
To: Laurent Pinchart
Cc: dri-devel, Alison Wang, Jingoo Han, Seung-Woo Kim, Xinwei Kong,
linux-renesas-soc, Kyungmin Park, Xinliang Liu, Chen Feng,
Rongrong Zou, Maxime Ripard, Vincent Abriou
On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
Not sure we want to allow setting both encoder and bridge for chaining.
I'd kinda expect that for chained use-case the bridge doesn't care that
much who started the chain. And if not we can always create a helper to
look up the drm_encoder.
Also, should we convert these to WARN_ON, they're kinda glaring driver (or
well DT) bugs?
Otherwise looks all reasonable to me, but deferring to Archit for final
review.
-Daniel
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 9:35 ` Daniel Vetter
0 siblings, 0 replies; 100+ messages in thread
From: Daniel Vetter @ 2016-11-29 9:35 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Xinliang Liu, Alison Wang, Jingoo Han, Seung-Woo Kim,
Kyungmin Park, dri-devel, linux-renesas-soc, Xinwei Kong,
Chen Feng, Rongrong Zou, Maxime Ripard, Vincent Abriou
On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
Not sure we want to allow setting both encoder and bridge for chaining.
I'd kinda expect that for chained use-case the bridge doesn't care that
much who started the chain. And if not we can always create a helper to
look up the drm_encoder.
Also, should we convert these to WARN_ON, they're kinda glaring driver (or
well DT) bugs?
Otherwise looks all reasonable to me, but deferring to Archit for final
review.
-Daniel
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> --
> Regards,
>
> Laurent Pinchart
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:35 ` Daniel Vetter
(?)
@ 2016-11-29 9:43 ` Laurent Pinchart
2016-11-29 10:05 ` Daniel Vetter
-1 siblings, 1 reply; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 9:43 UTC (permalink / raw)
To: Daniel Vetter
Cc: Laurent Pinchart, dri-devel, Alison Wang, Jingoo Han,
Seung-Woo Kim, Xinwei Kong, linux-renesas-soc, Kyungmin Park,
Xinliang Liu, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
Hi Daniel,
On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> > Instead of linking encoders and bridges in every driver (and getting it
> > wrong half of the time, as many drivers forget to set the drm_bridge
> > encoder pointer), do so in core code. The drm_bridge_attach() function
> > needs the encoder and optional previous bridge to perform that task,
> > update all the callers.
> >
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> >
> > drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> > drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> > drivers/gpu/drm/drm_bridge.c | 46 +++++++++++++----
> > drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> > drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> > drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> > drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> > drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> > drivers/gpu/drm/imx/parallel-display.c | 4 +-
> > drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> > drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> > drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> > drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> > drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> > drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> > drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> > drivers/gpu/drm/sti/sti_hda.c | 3 +-
> > drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> > drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> > include/drm/drm_bridge.h | 3 +-
> > 23 files changed, 83 insertions(+), 103 deletions(-)
[snip]
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 0ee052b7c21a..850bd6509ef1 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
> > @@ -26,6 +26,7 @@
> >
> > #include <linux/mutex.h>
> > #include <drm/drm_bridge.h>
> > +#include <drm/drm_encoder.h>
> >
> > /**
> > * DOC: overview
> > @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> > EXPORT_SYMBOL(drm_bridge_remove);
> >
> > /**
> > - * drm_bridge_attach - associate given bridge to our DRM device
> > + * drm_bridge_attach - attach the bridge to an encoder's chain
> > *
> > - * @dev: DRM device
> > - * @bridge: bridge control structure
> > + * @encoder: DRM encoder
> > + * @bridge: bridge to attach
> > + * @previous: previous bridge in the chain (optional)
> > *
> > - * Called by a kms driver to link one of our encoder/bridge to the given
> > - * bridge.
> > + * Called by a kms driver to link the bridge to an encoder's chain. The
> > previous
> > + * argument specifies the previous bridge in the chain. If NULL, the
> > bridge is
> > + * linked directly at the encoder's output. Otherwise it is linked at the
> > + * previous bridge's output.
> > *
> > - * Note that setting up links between the bridge and our encoder/bridge
> > - * objects needs to be handled by the kms driver itself.
> > + * If non-NULL the previous bridge must be already attached by a call to
> > this
> > + * function.
> > *
> > * RETURNS:
> > * Zero on success, error code on failure
> > */
> > -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> > +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> > *bridge,
> > + struct drm_bridge *previous)
> > {
> > - if (!dev || !bridge)
> > + int ret;
> > +
> > + if (!encoder || !bridge)
> > + return -EINVAL;
> > +
> > + if (previous && (!previous->dev || previous->encoder != encoder))
> > return -EINVAL;
>
> Not sure we want to allow setting both encoder and bridge for chaining.
> I'd kinda expect that for chained use-case the bridge doesn't care that
> much who started the chain. And if not we can always create a helper to
> look up the drm_encoder.
As bridge drivers currently create connectors (I'd like to change that at some
point, but one thing at a time) they need to call
drm_mode_connector_attach_encoder() and thus need to have access to the
drm_encoder object at the beginning of the chain. The drm_bridge structure has
an encoder field, it seems to me that the easiest is to always populate it,
regardless of the position of the bridge in the chain.
> Also, should we convert these to WARN_ON, they're kinda glaring driver (or
> well DT) bugs?
Yes, that seems like a good idea. I can add a patch on top of this one to
convert the checks to WARN_ON, as I'd rather separate that change from the API
change.
> Otherwise looks all reasonable to me, but deferring to Archit for final
> review.
>
> > if (bridge->dev)
> > return -EBUSY;
> >
> > - bridge->dev = dev;
> > + bridge->dev = encoder->dev;
> > + bridge->encoder = encoder;
> > +
> > + if (bridge->funcs->attach) {
> > + ret = bridge->funcs->attach(bridge);
> > + if (ret < 0) {
> > + bridge->dev = NULL;
> > + bridge->encoder = NULL;
> > + return ret;
> > + }
> > + }
> >
> > - if (bridge->funcs->attach)
> > - return bridge->funcs->attach(bridge);
> > + if (previous)
> > + previous->next = bridge;
> > + else
> > + encoder->bridge = bridge;
> >
> > return 0;
> > }
> >
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:43 ` Laurent Pinchart
@ 2016-11-29 10:05 ` Daniel Vetter
0 siblings, 0 replies; 100+ messages in thread
From: Daniel Vetter @ 2016-11-29 10:05 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Daniel Vetter, Laurent Pinchart, dri-devel, Alison Wang,
Jingoo Han, Seung-Woo Kim, Xinwei Kong, linux-renesas-soc,
Kyungmin Park, Xinliang Liu, Chen Feng, Rongrong Zou,
Maxime Ripard, Vincent Abriou
On Tue, Nov 29, 2016 at 11:43:19AM +0200, Laurent Pinchart wrote:
> Hi Daniel,
>
> On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> > On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> > > Instead of linking encoders and bridges in every driver (and getting it
> > > wrong half of the time, as many drivers forget to set the drm_bridge
> > > encoder pointer), do so in core code. The drm_bridge_attach() function
> > > needs the encoder and optional previous bridge to perform that task,
> > > update all the callers.
> > >
> > > Signed-off-by: Laurent Pinchart
> > > <laurent.pinchart+renesas@ideasonboard.com>
> > > ---
> > >
> > > drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> > > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> > > drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> > > drivers/gpu/drm/drm_bridge.c | 46 +++++++++++++----
> > > drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> > > drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> > > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> > > drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> > > drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> > > drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> > > drivers/gpu/drm/imx/parallel-display.c | 4 +-
> > > drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> > > drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> > > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> > > drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> > > drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> > > drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> > > drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> > > drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> > > drivers/gpu/drm/sti/sti_hda.c | 3 +-
> > > drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> > > drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> > > include/drm/drm_bridge.h | 3 +-
> > > 23 files changed, 83 insertions(+), 103 deletions(-)
>
> [snip]
>
> > > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > > index 0ee052b7c21a..850bd6509ef1 100644
> > > --- a/drivers/gpu/drm/drm_bridge.c
> > > +++ b/drivers/gpu/drm/drm_bridge.c
> > > @@ -26,6 +26,7 @@
> > >
> > > #include <linux/mutex.h>
> > > #include <drm/drm_bridge.h>
> > > +#include <drm/drm_encoder.h>
> > >
> > > /**
> > > * DOC: overview
> > > @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> > > EXPORT_SYMBOL(drm_bridge_remove);
> > >
> > > /**
> > > - * drm_bridge_attach - associate given bridge to our DRM device
> > > + * drm_bridge_attach - attach the bridge to an encoder's chain
> > > *
> > > - * @dev: DRM device
> > > - * @bridge: bridge control structure
> > > + * @encoder: DRM encoder
> > > + * @bridge: bridge to attach
> > > + * @previous: previous bridge in the chain (optional)
> > > *
> > > - * Called by a kms driver to link one of our encoder/bridge to the given
> > > - * bridge.
> > > + * Called by a kms driver to link the bridge to an encoder's chain. The
> > > previous
> > > + * argument specifies the previous bridge in the chain. If NULL, the
> > > bridge is
> > > + * linked directly at the encoder's output. Otherwise it is linked at the
> > > + * previous bridge's output.
> > > *
> > > - * Note that setting up links between the bridge and our encoder/bridge
> > > - * objects needs to be handled by the kms driver itself.
> > > + * If non-NULL the previous bridge must be already attached by a call to
> > > this
> > > + * function.
> > > *
> > > * RETURNS:
> > > * Zero on success, error code on failure
> > > */
> > > -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> > > +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> > > *bridge,
> > > + struct drm_bridge *previous)
> > > {
> > > - if (!dev || !bridge)
> > > + int ret;
> > > +
> > > + if (!encoder || !bridge)
> > > + return -EINVAL;
> > > +
> > > + if (previous && (!previous->dev || previous->encoder != encoder))
> > > return -EINVAL;
> >
> > Not sure we want to allow setting both encoder and bridge for chaining.
> > I'd kinda expect that for chained use-case the bridge doesn't care that
> > much who started the chain. And if not we can always create a helper to
> > look up the drm_encoder.
>
> As bridge drivers currently create connectors (I'd like to change that at some
> point, but one thing at a time) they need to call
> drm_mode_connector_attach_encoder() and thus need to have access to the
> drm_encoder object at the beginning of the chain. The drm_bridge structure has
> an encoder field, it seems to me that the easiest is to always populate it,
> regardless of the position of the bridge in the chain.
I mean the function inteface, not what we fill out in the drm_bridge
struct. I.e. instead of expecting callers to give you the encoder for
chained bridges, look it up yourself:
bridge->encoder = previous : previous->encoder ? encoder;
Or something like that. Just feels confusing to connect a bridge to both
a bridge _and_ the first encoder.
Wrt creating the connector: Some helpers to make that easier could be
useful, and probably we need a separate ->register callback. That's needed
for proper demidlayered init/teardown sequence anyway, and then the
drm_bridge.c code make sure to only call ->register for the very last
bridge. Other bridges could still create ther connectors (less conditions
in the code), as long as they don't register them no one will ever see
them ;-)
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 10:05 ` Daniel Vetter
0 siblings, 0 replies; 100+ messages in thread
From: Daniel Vetter @ 2016-11-29 10:05 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Xinliang Liu, Laurent Pinchart, Alison Wang, Jingoo Han,
Seung-Woo Kim, Kyungmin Park, dri-devel, linux-renesas-soc,
Xinwei Kong, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
On Tue, Nov 29, 2016 at 11:43:19AM +0200, Laurent Pinchart wrote:
> Hi Daniel,
>
> On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> > On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> > > Instead of linking encoders and bridges in every driver (and getting it
> > > wrong half of the time, as many drivers forget to set the drm_bridge
> > > encoder pointer), do so in core code. The drm_bridge_attach() function
> > > needs the encoder and optional previous bridge to perform that task,
> > > update all the callers.
> > >
> > > Signed-off-by: Laurent Pinchart
> > > <laurent.pinchart+renesas@ideasonboard.com>
> > > ---
> > >
> > > drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> > > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> > > drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> > > drivers/gpu/drm/drm_bridge.c | 46 +++++++++++++----
> > > drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> > > drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> > > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> > > drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> > > drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> > > drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> > > drivers/gpu/drm/imx/parallel-display.c | 4 +-
> > > drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> > > drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> > > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> > > drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> > > drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> > > drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> > > drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> > > drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> > > drivers/gpu/drm/sti/sti_hda.c | 3 +-
> > > drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> > > drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> > > include/drm/drm_bridge.h | 3 +-
> > > 23 files changed, 83 insertions(+), 103 deletions(-)
>
> [snip]
>
> > > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > > index 0ee052b7c21a..850bd6509ef1 100644
> > > --- a/drivers/gpu/drm/drm_bridge.c
> > > +++ b/drivers/gpu/drm/drm_bridge.c
> > > @@ -26,6 +26,7 @@
> > >
> > > #include <linux/mutex.h>
> > > #include <drm/drm_bridge.h>
> > > +#include <drm/drm_encoder.h>
> > >
> > > /**
> > > * DOC: overview
> > > @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> > > EXPORT_SYMBOL(drm_bridge_remove);
> > >
> > > /**
> > > - * drm_bridge_attach - associate given bridge to our DRM device
> > > + * drm_bridge_attach - attach the bridge to an encoder's chain
> > > *
> > > - * @dev: DRM device
> > > - * @bridge: bridge control structure
> > > + * @encoder: DRM encoder
> > > + * @bridge: bridge to attach
> > > + * @previous: previous bridge in the chain (optional)
> > > *
> > > - * Called by a kms driver to link one of our encoder/bridge to the given
> > > - * bridge.
> > > + * Called by a kms driver to link the bridge to an encoder's chain. The
> > > previous
> > > + * argument specifies the previous bridge in the chain. If NULL, the
> > > bridge is
> > > + * linked directly at the encoder's output. Otherwise it is linked at the
> > > + * previous bridge's output.
> > > *
> > > - * Note that setting up links between the bridge and our encoder/bridge
> > > - * objects needs to be handled by the kms driver itself.
> > > + * If non-NULL the previous bridge must be already attached by a call to
> > > this
> > > + * function.
> > > *
> > > * RETURNS:
> > > * Zero on success, error code on failure
> > > */
> > > -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> > > +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> > > *bridge,
> > > + struct drm_bridge *previous)
> > > {
> > > - if (!dev || !bridge)
> > > + int ret;
> > > +
> > > + if (!encoder || !bridge)
> > > + return -EINVAL;
> > > +
> > > + if (previous && (!previous->dev || previous->encoder != encoder))
> > > return -EINVAL;
> >
> > Not sure we want to allow setting both encoder and bridge for chaining.
> > I'd kinda expect that for chained use-case the bridge doesn't care that
> > much who started the chain. And if not we can always create a helper to
> > look up the drm_encoder.
>
> As bridge drivers currently create connectors (I'd like to change that at some
> point, but one thing at a time) they need to call
> drm_mode_connector_attach_encoder() and thus need to have access to the
> drm_encoder object at the beginning of the chain. The drm_bridge structure has
> an encoder field, it seems to me that the easiest is to always populate it,
> regardless of the position of the bridge in the chain.
I mean the function inteface, not what we fill out in the drm_bridge
struct. I.e. instead of expecting callers to give you the encoder for
chained bridges, look it up yourself:
bridge->encoder = previous : previous->encoder ? encoder;
Or something like that. Just feels confusing to connect a bridge to both
a bridge _and_ the first encoder.
Wrt creating the connector: Some helpers to make that easier could be
useful, and probably we need a separate ->register callback. That's needed
for proper demidlayered init/teardown sequence anyway, and then the
drm_bridge.c code make sure to only call ->register for the very last
bridge. Other bridges could still create ther connectors (less conditions
in the code), as long as they don't register them no one will ever see
them ;-)
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 10:05 ` Daniel Vetter
@ 2016-11-29 18:02 ` Laurent Pinchart
-1 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 18:02 UTC (permalink / raw)
To: Daniel Vetter
Cc: Laurent Pinchart, dri-devel, Alison Wang, Jingoo Han,
Seung-Woo Kim, Xinwei Kong, linux-renesas-soc, Kyungmin Park,
Xinliang Liu, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
Hi Daniel,
On Tuesday 29 Nov 2016 11:05:27 Daniel Vetter wrote:
> On Tue, Nov 29, 2016 at 11:43:19AM +0200, Laurent Pinchart wrote:
> > On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> >> On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> >>> Instead of linking encoders and bridges in every driver (and getting
> >>> it wrong half of the time, as many drivers forget to set the
> >>> drm_bridge encoder pointer), do so in core code. The
> >>> drm_bridge_attach() function needs the encoder and optional previous
> >>> bridge to perform that task, update all the callers.
> >>>
> >>> Signed-off-by: Laurent Pinchart
> >>> <laurent.pinchart+renesas@ideasonboard.com>
> >>> ---
> >>>
> >>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> >>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> >>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> >>> drivers/gpu/drm/drm_bridge.c | 46 +++++++++----
> >>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> >>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> >>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> >>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> >>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> >>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> >>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> >>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> >>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> >>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> >>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> >>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> >>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> >>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> >>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> >>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> >>> include/drm/drm_bridge.h | 3 +-
> >>> 23 files changed, 83 insertions(+), 103 deletions(-)
> >
> > [snip]
> >
> >>> diff --git a/drivers/gpu/drm/drm_bridge.c
> >>> b/drivers/gpu/drm/drm_bridge.c
> >>> index 0ee052b7c21a..850bd6509ef1 100644
> >>> --- a/drivers/gpu/drm/drm_bridge.c
> >>> +++ b/drivers/gpu/drm/drm_bridge.c
[snip]
> >>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
> >>> *bridge)
> >>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> >>> *bridge,
> >>> + struct drm_bridge *previous)
> >>> {
> >>> - if (!dev || !bridge)
> >>> + int ret;
> >>> +
> >>> + if (!encoder || !bridge)
> >>> + return -EINVAL;
> >>> +
> >>> + if (previous && (!previous->dev || previous->encoder != encoder))
> >>> return -EINVAL;
> >>
> >> Not sure we want to allow setting both encoder and bridge for chaining.
> >> I'd kinda expect that for chained use-case the bridge doesn't care that
> >> much who started the chain. And if not we can always create a helper to
> >> look up the drm_encoder.
> >
> > As bridge drivers currently create connectors (I'd like to change that at
> > some point, but one thing at a time) they need to call
> > drm_mode_connector_attach_encoder() and thus need to have access to the
> > drm_encoder object at the beginning of the chain. The drm_bridge structure
> > has an encoder field, it seems to me that the easiest is to always
> > populate it, regardless of the position of the bridge in the chain.
>
> I mean the function inteface, not what we fill out in the drm_bridge
> struct. I.e. instead of expecting callers to give you the encoder for
> chained bridges, look it up yourself:
>
> bridge->encoder = previous : previous->encoder ? encoder;
>
> Or something like that. Just feels confusing to connect a bridge to both
> a bridge _and_ the first encoder.
Right. Archit proposed doing it the other way around:
previous = encoder->bridge;
while (previous && previous->next)
previous = previous->next;
That would simplify the API, at the cost of preventing us from catching
drivers that attach bridges in the wrong order (through the !previous->dev
check that you suggested should be turned into a WARN_ON). The previous-
>encoder != encoder check is also a safety net.
Any opinion on which option you like better ? I'd be very tempted to go for
Archit's proposal as it removes the previous parameter from the API, if it
wasn't for the loss of sanity checking.
> Wrt creating the connector: Some helpers to make that easier could be
> useful, and probably we need a separate ->register callback. That's needed
> for proper demidlayered init/teardown sequence anyway, and then the
> drm_bridge.c code make sure to only call ->register for the very last
> bridge. Other bridges could still create ther connectors (less conditions
> in the code), as long as they don't register them no one will ever see
> them ;-)
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 18:02 ` Laurent Pinchart
0 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 18:02 UTC (permalink / raw)
To: Daniel Vetter
Cc: Xinliang Liu, Laurent Pinchart, Alison Wang, Jingoo Han,
Seung-Woo Kim, Kyungmin Park, dri-devel, linux-renesas-soc,
Xinwei Kong, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
Hi Daniel,
On Tuesday 29 Nov 2016 11:05:27 Daniel Vetter wrote:
> On Tue, Nov 29, 2016 at 11:43:19AM +0200, Laurent Pinchart wrote:
> > On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> >> On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> >>> Instead of linking encoders and bridges in every driver (and getting
> >>> it wrong half of the time, as many drivers forget to set the
> >>> drm_bridge encoder pointer), do so in core code. The
> >>> drm_bridge_attach() function needs the encoder and optional previous
> >>> bridge to perform that task, update all the callers.
> >>>
> >>> Signed-off-by: Laurent Pinchart
> >>> <laurent.pinchart+renesas@ideasonboard.com>
> >>> ---
> >>>
> >>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> >>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> >>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> >>> drivers/gpu/drm/drm_bridge.c | 46 +++++++++----
> >>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> >>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> >>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> >>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> >>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> >>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> >>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> >>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> >>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> >>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> >>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> >>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> >>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> >>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> >>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> >>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> >>> include/drm/drm_bridge.h | 3 +-
> >>> 23 files changed, 83 insertions(+), 103 deletions(-)
> >
> > [snip]
> >
> >>> diff --git a/drivers/gpu/drm/drm_bridge.c
> >>> b/drivers/gpu/drm/drm_bridge.c
> >>> index 0ee052b7c21a..850bd6509ef1 100644
> >>> --- a/drivers/gpu/drm/drm_bridge.c
> >>> +++ b/drivers/gpu/drm/drm_bridge.c
[snip]
> >>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
> >>> *bridge)
> >>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> >>> *bridge,
> >>> + struct drm_bridge *previous)
> >>> {
> >>> - if (!dev || !bridge)
> >>> + int ret;
> >>> +
> >>> + if (!encoder || !bridge)
> >>> + return -EINVAL;
> >>> +
> >>> + if (previous && (!previous->dev || previous->encoder != encoder))
> >>> return -EINVAL;
> >>
> >> Not sure we want to allow setting both encoder and bridge for chaining.
> >> I'd kinda expect that for chained use-case the bridge doesn't care that
> >> much who started the chain. And if not we can always create a helper to
> >> look up the drm_encoder.
> >
> > As bridge drivers currently create connectors (I'd like to change that at
> > some point, but one thing at a time) they need to call
> > drm_mode_connector_attach_encoder() and thus need to have access to the
> > drm_encoder object at the beginning of the chain. The drm_bridge structure
> > has an encoder field, it seems to me that the easiest is to always
> > populate it, regardless of the position of the bridge in the chain.
>
> I mean the function inteface, not what we fill out in the drm_bridge
> struct. I.e. instead of expecting callers to give you the encoder for
> chained bridges, look it up yourself:
>
> bridge->encoder = previous : previous->encoder ? encoder;
>
> Or something like that. Just feels confusing to connect a bridge to both
> a bridge _and_ the first encoder.
Right. Archit proposed doing it the other way around:
previous = encoder->bridge;
while (previous && previous->next)
previous = previous->next;
That would simplify the API, at the cost of preventing us from catching
drivers that attach bridges in the wrong order (through the !previous->dev
check that you suggested should be turned into a WARN_ON). The previous-
>encoder != encoder check is also a safety net.
Any opinion on which option you like better ? I'd be very tempted to go for
Archit's proposal as it removes the previous parameter from the API, if it
wasn't for the loss of sanity checking.
> Wrt creating the connector: Some helpers to make that easier could be
> useful, and probably we need a separate ->register callback. That's needed
> for proper demidlayered init/teardown sequence anyway, and then the
> drm_bridge.c code make sure to only call ->register for the very last
> bridge. Other bridges could still create ther connectors (less conditions
> in the code), as long as they don't register them no one will ever see
> them ;-)
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 18:02 ` Laurent Pinchart
(?)
@ 2016-11-29 18:51 ` Laurent Pinchart
-1 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 18:51 UTC (permalink / raw)
To: dri-devel
Cc: Daniel Vetter, Xinliang Liu, Laurent Pinchart, Alison Wang,
Jingoo Han, Seung-Woo Kim, Kyungmin Park, linux-renesas-soc,
Xinwei Kong, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
Hi Daniel,
On Tuesday 29 Nov 2016 20:02:01 Laurent Pinchart wrote:
> On Tuesday 29 Nov 2016 11:05:27 Daniel Vetter wrote:
> > On Tue, Nov 29, 2016 at 11:43:19AM +0200, Laurent Pinchart wrote:
> >> On Tuesday 29 Nov 2016 10:35:24 Daniel Vetter wrote:
> >>> On Tue, Nov 29, 2016 at 11:04:33AM +0200, Laurent Pinchart wrote:
> >>>> Instead of linking encoders and bridges in every driver (and getting
> >>>> it wrong half of the time, as many drivers forget to set the
> >>>> drm_bridge encoder pointer), do so in core code. The
> >>>> drm_bridge_attach() function needs the encoder and optional previous
> >>>> bridge to perform that task, update all the callers.
> >>>>
> >>>> Signed-off-by: Laurent Pinchart
> >>>> <laurent.pinchart+renesas@ideasonboard.com>
> >>>> ---
[snip]
> >>>> diff --git a/drivers/gpu/drm/drm_bridge.c
> >>>> b/drivers/gpu/drm/drm_bridge.c
> >>>> index 0ee052b7c21a..850bd6509ef1 100644
> >>>> --- a/drivers/gpu/drm/drm_bridge.c
> >>>> +++ b/drivers/gpu/drm/drm_bridge.c
>
> [snip]
>
> >>>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
> >>>> *bridge)
> >>>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> >>>> *bridge,
> >>>> + struct drm_bridge *previous)
> >>>> {
> >>>> - if (!dev || !bridge)
> >>>> + int ret;
> >>>> +
> >>>> + if (!encoder || !bridge)
> >>>> + return -EINVAL;
> >>>> +
> >>>> + if (previous && (!previous->dev || previous->encoder !=
> >>>> encoder))
> >>>> return -EINVAL;
> >>>
> >>> Not sure we want to allow setting both encoder and bridge for chaining.
> >>> I'd kinda expect that for chained use-case the bridge doesn't care that
> >>> much who started the chain. And if not we can always create a helper to
> >>> look up the drm_encoder.
> >>
> >> As bridge drivers currently create connectors (I'd like to change that
> >> at some point, but one thing at a time) they need to call
> >> drm_mode_connector_attach_encoder() and thus need to have access to the
> >> drm_encoder object at the beginning of the chain. The drm_bridge
> >> structure has an encoder field, it seems to me that the easiest is to
> >> always populate it, regardless of the position of the bridge in the
> >> chain.
> >
> > I mean the function inteface, not what we fill out in the drm_bridge
> > struct. I.e. instead of expecting callers to give you the encoder for
> >
> > chained bridges, look it up yourself:
> > bridge->encoder = previous : previous->encoder ? encoder;
> >
> > Or something like that. Just feels confusing to connect a bridge to both
> > a bridge _and_ the first encoder.
>
> Right. Archit proposed doing it the other way around:
>
> previous = encoder->bridge;
> while (previous && previous->next)
> previous = previous->next;
>
> That would simplify the API, at the cost of preventing us from catching
> drivers that attach bridges in the wrong order (through the !previous->dev
> check that you suggested should be turned into a WARN_ON). The previous-
>
> >encoder != encoder check is also a safety net.
>
> Any opinion on which option you like better ? I'd be very tempted to go for
> Archit's proposal as it removes the previous parameter from the API, if it
> wasn't for the loss of sanity checking.
>
> > Wrt creating the connector: Some helpers to make that easier could be
> > useful, and probably we need a separate ->register callback. That's needed
> > for proper demidlayered init/teardown sequence anyway, and then the
> > drm_bridge.c code make sure to only call ->register for the very last
> > bridge. Other bridges could still create ther connectors (less conditions
> > in the code), as long as they don't register them no one will ever see
> > them ;-)
One thing at a time, we'll get there :-)
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:04 ` Laurent Pinchart
@ 2016-11-29 10:27 ` Archit Taneja
-1 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-29 10:27 UTC (permalink / raw)
To: Laurent Pinchart, dri-devel
Cc: linux-renesas-soc, Boris Brezillon, Jingoo Han, Inki Dae,
Joonyoung Shim, Seung-Woo Kim, Kyungmin Park, Stefan Agner,
Alison Wang, Xinliang Liu, Rongrong Zou, Xinwei Kong, Chen Feng,
Philipp Zabel, CK Hu, Rob Clark, Benjamin Gaignard,
Vincent Abriou, Maxime Ripard
On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
I think we could derive previous from the encoder itself. Something like:
previous = encoder->bridge;
while (previous && previous->next)
previous = previous->next;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
<snip>
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 10:27 ` Archit Taneja
0 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-29 10:27 UTC (permalink / raw)
To: Laurent Pinchart, dri-devel
Cc: Alison Wang, Jingoo Han, Seung-Woo Kim, Xinwei Kong,
linux-renesas-soc, Kyungmin Park, Xinliang Liu, Chen Feng,
Rongrong Zou, Maxime Ripard, Vincent Abriou
On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
I think we could derive previous from the encoder itself. Something like:
previous = encoder->bridge;
while (previous && previous->next)
previous = previous->next;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
<snip>
Archit
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 10:27 ` Archit Taneja
@ 2016-11-29 17:57 ` Laurent Pinchart
-1 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 17:57 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
Hi Archit,
On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> > Instead of linking encoders and bridges in every driver (and getting it
> > wrong half of the time, as many drivers forget to set the drm_bridge
> > encoder pointer), do so in core code. The drm_bridge_attach() function
> > needs the encoder and optional previous bridge to perform that task,
> > update all the callers.
> >
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> >
> > drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> > drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> > drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++-----
> > drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> > drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> > drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> > drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> > drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> > drivers/gpu/drm/imx/parallel-display.c | 4 +-
> > drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> > drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> > drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> > drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> > drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> > drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> > drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> > drivers/gpu/drm/sti/sti_hda.c | 3 +-
> > drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> > drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> > include/drm/drm_bridge.h | 3 +-
> > 23 files changed, 83 insertions(+), 103 deletions(-)
[snip]
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 0ee052b7c21a..850bd6509ef1 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
[snip]
> > @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> > EXPORT_SYMBOL(drm_bridge_remove);
> >
> > /**
> > - * drm_bridge_attach - associate given bridge to our DRM device
> > + * drm_bridge_attach - attach the bridge to an encoder's chain
> > *
> > - * @dev: DRM device
> > - * @bridge: bridge control structure
> > + * @encoder: DRM encoder
> > + * @bridge: bridge to attach
> > + * @previous: previous bridge in the chain (optional)
> > *
> > - * Called by a kms driver to link one of our encoder/bridge to the given
> > - * bridge.
> > + * Called by a kms driver to link the bridge to an encoder's chain. The
> > previous
> > + * argument specifies the previous bridge in the chain. If NULL, the
> > bridge is
> > + * linked directly at the encoder's output. Otherwise it is linked at the
> > + * previous bridge's output.
> > *
> > - * Note that setting up links between the bridge and our encoder/bridge
> > - * objects needs to be handled by the kms driver itself.
> > + * If non-NULL the previous bridge must be already attached by a call to
> > this
> > + * function.
> > *
> > * RETURNS:
> > * Zero on success, error code on failure
> > */
> > -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> > +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> > *bridge,
> > + struct drm_bridge *previous)
> > {
> > - if (!dev || !bridge)
> > + int ret;
> > +
> > + if (!encoder || !bridge)
> > + return -EINVAL;
>
> I think we could derive previous from the encoder itself. Something like:
>
> previous = encoder->bridge;
> while (previous && previous->next)
> previous = previous->next;
That's a very good point. It would however prevent us from catching drivers
that attach bridges in the wrong order, which the !previous->dev currently
allows us to do (and it should be turned into a WARN_ON as Daniel proposed).
I'm fine losing that ability, as your proposal makes the API simpler. I'll let
you decide, which option do you prefer ?
> > +
> > + if (previous && (!previous->dev || previous->encoder != encoder))
> > return -EINVAL;
> >
> > if (bridge->dev)
> > return -EBUSY;
> >
> > - bridge->dev = dev;
> > + bridge->dev = encoder->dev;
> > + bridge->encoder = encoder;
> > +
> > + if (bridge->funcs->attach) {
> > + ret = bridge->funcs->attach(bridge);
> > + if (ret < 0) {
> > + bridge->dev = NULL;
> > + bridge->encoder = NULL;
> > + return ret;
> > + }
> > + }
> >
> > - if (bridge->funcs->attach)
> > - return bridge->funcs->attach(bridge);
> > + if (previous)
> > + previous->next = bridge;
> > + else
> > + encoder->bridge = bridge;
> >
> > return 0;
> > }
>
> <snip>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 17:57 ` Laurent Pinchart
0 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-29 17:57 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard
Hi Archit,
On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> > Instead of linking encoders and bridges in every driver (and getting it
> > wrong half of the time, as many drivers forget to set the drm_bridge
> > encoder pointer), do so in core code. The drm_bridge_attach() function
> > needs the encoder and optional previous bridge to perform that task,
> > update all the callers.
> >
> > Signed-off-by: Laurent Pinchart
> > <laurent.pinchart+renesas@ideasonboard.com>
> > ---
> >
> > drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> > drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> > drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> > drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++-----
> > drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> > drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> > drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> > drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> > drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> > drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> > drivers/gpu/drm/imx/parallel-display.c | 4 +-
> > drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> > drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> > drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> > drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> > drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> > drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> > drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> > drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> > drivers/gpu/drm/sti/sti_hda.c | 3 +-
> > drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> > drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> > include/drm/drm_bridge.h | 3 +-
> > 23 files changed, 83 insertions(+), 103 deletions(-)
[snip]
> > diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> > index 0ee052b7c21a..850bd6509ef1 100644
> > --- a/drivers/gpu/drm/drm_bridge.c
> > +++ b/drivers/gpu/drm/drm_bridge.c
[snip]
> > @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> > EXPORT_SYMBOL(drm_bridge_remove);
> >
> > /**
> > - * drm_bridge_attach - associate given bridge to our DRM device
> > + * drm_bridge_attach - attach the bridge to an encoder's chain
> > *
> > - * @dev: DRM device
> > - * @bridge: bridge control structure
> > + * @encoder: DRM encoder
> > + * @bridge: bridge to attach
> > + * @previous: previous bridge in the chain (optional)
> > *
> > - * Called by a kms driver to link one of our encoder/bridge to the given
> > - * bridge.
> > + * Called by a kms driver to link the bridge to an encoder's chain. The
> > previous
> > + * argument specifies the previous bridge in the chain. If NULL, the
> > bridge is
> > + * linked directly at the encoder's output. Otherwise it is linked at the
> > + * previous bridge's output.
> > *
> > - * Note that setting up links between the bridge and our encoder/bridge
> > - * objects needs to be handled by the kms driver itself.
> > + * If non-NULL the previous bridge must be already attached by a call to
> > this
> > + * function.
> > *
> > * RETURNS:
> > * Zero on success, error code on failure
> > */
> > -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> > +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> > *bridge,
> > + struct drm_bridge *previous)
> > {
> > - if (!dev || !bridge)
> > + int ret;
> > +
> > + if (!encoder || !bridge)
> > + return -EINVAL;
>
> I think we could derive previous from the encoder itself. Something like:
>
> previous = encoder->bridge;
> while (previous && previous->next)
> previous = previous->next;
That's a very good point. It would however prevent us from catching drivers
that attach bridges in the wrong order, which the !previous->dev currently
allows us to do (and it should be turned into a WARN_ON as Daniel proposed).
I'm fine losing that ability, as your proposal makes the API simpler. I'll let
you decide, which option do you prefer ?
> > +
> > + if (previous && (!previous->dev || previous->encoder != encoder))
> > return -EINVAL;
> >
> > if (bridge->dev)
> > return -EBUSY;
> >
> > - bridge->dev = dev;
> > + bridge->dev = encoder->dev;
> > + bridge->encoder = encoder;
> > +
> > + if (bridge->funcs->attach) {
> > + ret = bridge->funcs->attach(bridge);
> > + if (ret < 0) {
> > + bridge->dev = NULL;
> > + bridge->encoder = NULL;
> > + return ret;
> > + }
> > + }
> >
> > - if (bridge->funcs->attach)
> > - return bridge->funcs->attach(bridge);
> > + if (previous)
> > + previous->next = bridge;
> > + else
> > + encoder->bridge = bridge;
> >
> > return 0;
> > }
>
> <snip>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 17:57 ` Laurent Pinchart
@ 2016-11-30 5:05 ` Archit Taneja
-1 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 5:05 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>> Instead of linking encoders and bridges in every driver (and getting it
>>> wrong half of the time, as many drivers forget to set the drm_bridge
>>> encoder pointer), do so in core code. The drm_bridge_attach() function
>>> needs the encoder and optional previous bridge to perform that task,
>>> update all the callers.
>>>
>>> Signed-off-by: Laurent Pinchart
>>> <laurent.pinchart+renesas@ideasonboard.com>
>>> ---
>>>
>>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
>>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
>>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
>>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++-----
>>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
>>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
>>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
>>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
>>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
>>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
>>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
>>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
>>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
>>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
>>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
>>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
>>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
>>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
>>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
>>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
>>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
>>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
>>> include/drm/drm_bridge.h | 3 +-
>>> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> [snip]
>
>>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>>> index 0ee052b7c21a..850bd6509ef1 100644
>>> --- a/drivers/gpu/drm/drm_bridge.c
>>> +++ b/drivers/gpu/drm/drm_bridge.c
>
> [snip]
>
>>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
>>> EXPORT_SYMBOL(drm_bridge_remove);
>>>
>>> /**
>>> - * drm_bridge_attach - associate given bridge to our DRM device
>>> + * drm_bridge_attach - attach the bridge to an encoder's chain
>>> *
>>> - * @dev: DRM device
>>> - * @bridge: bridge control structure
>>> + * @encoder: DRM encoder
>>> + * @bridge: bridge to attach
>>> + * @previous: previous bridge in the chain (optional)
>>> *
>>> - * Called by a kms driver to link one of our encoder/bridge to the given
>>> - * bridge.
>>> + * Called by a kms driver to link the bridge to an encoder's chain. The
>>> previous
>>> + * argument specifies the previous bridge in the chain. If NULL, the
>>> bridge is
>>> + * linked directly at the encoder's output. Otherwise it is linked at the
>>> + * previous bridge's output.
>>> *
>>> - * Note that setting up links between the bridge and our encoder/bridge
>>> - * objects needs to be handled by the kms driver itself.
>>> + * If non-NULL the previous bridge must be already attached by a call to
>>> this
>>> + * function.
>>> *
>>> * RETURNS:
>>> * Zero on success, error code on failure
>>> */
>>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
>>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
>>> *bridge,
>>> + struct drm_bridge *previous)
>>> {
>>> - if (!dev || !bridge)
>>> + int ret;
>>> +
>>> + if (!encoder || !bridge)
>>> + return -EINVAL;
>>
>> I think we could derive previous from the encoder itself. Something like:
>>
>> previous = encoder->bridge;
>> while (previous && previous->next)
>> previous = previous->next;
>
> That's a very good point. It would however prevent us from catching drivers
> that attach bridges in the wrong order, which the !previous->dev currently
> allows us to do (and it should be turned into a WARN_ON as Daniel proposed).
>
With the simpler API, I don't think we will ever hit the case of
!previous->dev. The previous bridge (if it exists) in the chain would
already have a dev attached to it. In other words, we would remove the
risk of the chance of the 'previous' bridge being unattached.
I'm a bit unclear about what you mean about the order part. If a kms driver
wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
drm_bridge_attach(encoder, bridge1, NULL);
drm_bridge_attach(encoder, bridge2, bridge1);
We can't do much if the kms driver does the opposite:
drm_bridge_attach(encoder, bridge2, NULL);
drm_bridge_attach(encoder, bridge2, bridge1);
> I'm fine losing that ability, as your proposal makes the API simpler. I'll let
> you decide, which option do you prefer ?
I prefer the simpler API. I guess the main aim of the patch was to prevent the
driver setting up the encoder<->bridge links, which will be done anyway.
Thanks,
Archit
>
>>> +
>>> + if (previous && (!previous->dev || previous->encoder != encoder))
>>> return -EINVAL;
>>>
>>> if (bridge->dev)
>>> return -EBUSY;
>>>
>>> - bridge->dev = dev;
>>> + bridge->dev = encoder->dev;
>>> + bridge->encoder = encoder;
>>> +
>>> + if (bridge->funcs->attach) {
>>> + ret = bridge->funcs->attach(bridge);
>>> + if (ret < 0) {
>>> + bridge->dev = NULL;
>>> + bridge->encoder = NULL;
>>> + return ret;
>>> + }
>>> + }
>>>
>>> - if (bridge->funcs->attach)
>>> - return bridge->funcs->attach(bridge);
>>> + if (previous)
>>> + previous->next = bridge;
>>> + else
>>> + encoder->bridge = bridge;
>>>
>>> return 0;
>>> }
>>
>> <snip>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 5:05 ` Archit Taneja
0 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 5:05 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard
On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>> Instead of linking encoders and bridges in every driver (and getting it
>>> wrong half of the time, as many drivers forget to set the drm_bridge
>>> encoder pointer), do so in core code. The drm_bridge_attach() function
>>> needs the encoder and optional previous bridge to perform that task,
>>> update all the callers.
>>>
>>> Signed-off-by: Laurent Pinchart
>>> <laurent.pinchart+renesas@ideasonboard.com>
>>> ---
>>>
>>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
>>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
>>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
>>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++-----
>>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
>>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
>>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
>>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
>>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
>>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
>>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
>>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
>>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
>>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
>>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
>>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
>>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
>>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
>>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
>>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
>>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
>>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
>>> include/drm/drm_bridge.h | 3 +-
>>> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> [snip]
>
>>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>>> index 0ee052b7c21a..850bd6509ef1 100644
>>> --- a/drivers/gpu/drm/drm_bridge.c
>>> +++ b/drivers/gpu/drm/drm_bridge.c
>
> [snip]
>
>>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
>>> EXPORT_SYMBOL(drm_bridge_remove);
>>>
>>> /**
>>> - * drm_bridge_attach - associate given bridge to our DRM device
>>> + * drm_bridge_attach - attach the bridge to an encoder's chain
>>> *
>>> - * @dev: DRM device
>>> - * @bridge: bridge control structure
>>> + * @encoder: DRM encoder
>>> + * @bridge: bridge to attach
>>> + * @previous: previous bridge in the chain (optional)
>>> *
>>> - * Called by a kms driver to link one of our encoder/bridge to the given
>>> - * bridge.
>>> + * Called by a kms driver to link the bridge to an encoder's chain. The
>>> previous
>>> + * argument specifies the previous bridge in the chain. If NULL, the
>>> bridge is
>>> + * linked directly at the encoder's output. Otherwise it is linked at the
>>> + * previous bridge's output.
>>> *
>>> - * Note that setting up links between the bridge and our encoder/bridge
>>> - * objects needs to be handled by the kms driver itself.
>>> + * If non-NULL the previous bridge must be already attached by a call to
>>> this
>>> + * function.
>>> *
>>> * RETURNS:
>>> * Zero on success, error code on failure
>>> */
>>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
>>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
>>> *bridge,
>>> + struct drm_bridge *previous)
>>> {
>>> - if (!dev || !bridge)
>>> + int ret;
>>> +
>>> + if (!encoder || !bridge)
>>> + return -EINVAL;
>>
>> I think we could derive previous from the encoder itself. Something like:
>>
>> previous = encoder->bridge;
>> while (previous && previous->next)
>> previous = previous->next;
>
> That's a very good point. It would however prevent us from catching drivers
> that attach bridges in the wrong order, which the !previous->dev currently
> allows us to do (and it should be turned into a WARN_ON as Daniel proposed).
>
With the simpler API, I don't think we will ever hit the case of
!previous->dev. The previous bridge (if it exists) in the chain would
already have a dev attached to it. In other words, we would remove the
risk of the chance of the 'previous' bridge being unattached.
I'm a bit unclear about what you mean about the order part. If a kms driver
wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
drm_bridge_attach(encoder, bridge1, NULL);
drm_bridge_attach(encoder, bridge2, bridge1);
We can't do much if the kms driver does the opposite:
drm_bridge_attach(encoder, bridge2, NULL);
drm_bridge_attach(encoder, bridge2, bridge1);
> I'm fine losing that ability, as your proposal makes the API simpler. I'll let
> you decide, which option do you prefer ?
I prefer the simpler API. I guess the main aim of the patch was to prevent the
driver setting up the encoder<->bridge links, which will be done anyway.
Thanks,
Archit
>
>>> +
>>> + if (previous && (!previous->dev || previous->encoder != encoder))
>>> return -EINVAL;
>>>
>>> if (bridge->dev)
>>> return -EBUSY;
>>>
>>> - bridge->dev = dev;
>>> + bridge->dev = encoder->dev;
>>> + bridge->encoder = encoder;
>>> +
>>> + if (bridge->funcs->attach) {
>>> + ret = bridge->funcs->attach(bridge);
>>> + if (ret < 0) {
>>> + bridge->dev = NULL;
>>> + bridge->encoder = NULL;
>>> + return ret;
>>> + }
>>> + }
>>>
>>> - if (bridge->funcs->attach)
>>> - return bridge->funcs->attach(bridge);
>>> + if (previous)
>>> + previous->next = bridge;
>>> + else
>>> + encoder->bridge = bridge;
>>>
>>> return 0;
>>> }
>>
>> <snip>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-30 5:05 ` Archit Taneja
@ 2016-11-30 10:23 ` Laurent Pinchart
-1 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-30 10:23 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
Hi Archit,
On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> > On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> >> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> >>> Instead of linking encoders and bridges in every driver (and getting it
> >>> wrong half of the time, as many drivers forget to set the drm_bridge
> >>> encoder pointer), do so in core code. The drm_bridge_attach() function
> >>> needs the encoder and optional previous bridge to perform that task,
> >>> update all the callers.
> >>>
> >>> Signed-off-by: Laurent Pinchart
> >>> <laurent.pinchart+renesas@ideasonboard.com>
> >>> ---
> >>>
> >>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> >>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> >>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> >>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++-----
> >>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> >>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> >>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> >>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> >>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> >>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> >>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> >>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> >>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> >>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> >>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> >>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> >>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> >>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> >>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> >>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> >>> include/drm/drm_bridge.h | 3 +-
> >>> 23 files changed, 83 insertions(+), 103 deletions(-)
> >
> > [snip]
> >
> >>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> >>> index 0ee052b7c21a..850bd6509ef1 100644
> >>> --- a/drivers/gpu/drm/drm_bridge.c
> >>> +++ b/drivers/gpu/drm/drm_bridge.c
> >
> > [snip]
> >
> >>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> >>> EXPORT_SYMBOL(drm_bridge_remove);
> >>>
> >>> /**
> >>> - * drm_bridge_attach - associate given bridge to our DRM device
> >>> + * drm_bridge_attach - attach the bridge to an encoder's chain
> >>> *
> >>> - * @dev: DRM device
> >>> - * @bridge: bridge control structure
> >>> + * @encoder: DRM encoder
> >>> + * @bridge: bridge to attach
> >>> + * @previous: previous bridge in the chain (optional)
> >>> *
> >>> - * Called by a kms driver to link one of our encoder/bridge to the
> >>> given
> >>> - * bridge.
> >>> + * Called by a kms driver to link the bridge to an encoder's chain. The
> >>> previous
> >>> + * argument specifies the previous bridge in the chain. If NULL, the
> >>> bridge is
> >>> + * linked directly at the encoder's output. Otherwise it is linked at
> >>> the
> >>> + * previous bridge's output.
> >>> *
> >>> - * Note that setting up links between the bridge and our encoder/bridge
> >>> - * objects needs to be handled by the kms driver itself.
> >>> + * If non-NULL the previous bridge must be already attached by a call
> >>> to this
> >>> + * function.
> >>> *
> >>> * RETURNS:
> >>> * Zero on success, error code on failure
> >>> */
> >>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
> >>> *bridge)
> >>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> >>> *bridge,
> >>> + struct drm_bridge *previous)
> >>> {
> >>> - if (!dev || !bridge)
> >>> + int ret;
> >>> +
> >>> + if (!encoder || !bridge)
> >>> + return -EINVAL;
> >>
> >> I think we could derive previous from the encoder itself. Something like:
> >> previous = encoder->bridge;
> >> while (previous && previous->next)
> >>
> >> previous = previous->next;
> >
> > That's a very good point. It would however prevent us from catching
> > drivers that attach bridges in the wrong order, which the !previous->dev
> > currently allows us to do (and it should be turned into a WARN_ON as
> > Daniel proposed).
>
> With the simpler API, I don't think we will ever hit the case of
> !previous->dev. The previous bridge (if it exists) in the chain would
> already have a dev attached to it. In other words, we would remove the
> risk of the chance of the 'previous' bridge being unattached.
>
> I'm a bit unclear about what you mean about the order part. If a kms driver
> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>
> drm_bridge_attach(encoder, bridge1, NULL);
> drm_bridge_attach(encoder, bridge2, bridge1);
Correct.
> We can't do much if the kms driver does the opposite:
>
> drm_bridge_attach(encoder, bridge2, NULL);
> drm_bridge_attach(encoder, bridge2, bridge1);
That would certainly be a very stupid thing for a driver to do :-) The problem
that we could catch with my current proposal is
drm_bridge_attach(encoder, bridge2, bridge1);
...
drm_bridge_attach(encoder, bridge1, NULL);
which I expect to happen from time to time as the two bridge can be attached
through separate code paths sometimes a bit difficult to trace. It's not a big
deal though, you could convince me that the advantages of a simpler API exceed
its drawbacks.
> > I'm fine losing that ability, as your proposal makes the API simpler. I'll
> > let you decide, which option do you prefer ?
>
> I prefer the simpler API. I guess the main aim of the patch was to prevent
> the driver setting up the encoder<->bridge links, which will be done
> anyway.
If you still prefer the simpler API after reading the above, I'll update my
patch.
> >>> +
> >>> + if (previous && (!previous->dev || previous->encoder != encoder))
> >>> return -EINVAL;
> >>>
> >>> if (bridge->dev)
> >>> return -EBUSY;
> >>>
> >>> - bridge->dev = dev;
> >>> + bridge->dev = encoder->dev;
> >>> + bridge->encoder = encoder;
> >>> +
> >>> + if (bridge->funcs->attach) {
> >>> + ret = bridge->funcs->attach(bridge);
> >>> + if (ret < 0) {
> >>> + bridge->dev = NULL;
> >>> + bridge->encoder = NULL;
> >>> + return ret;
> >>> + }
> >>> + }
> >>>
> >>> - if (bridge->funcs->attach)
> >>> - return bridge->funcs->attach(bridge);
> >>> + if (previous)
> >>> + previous->next = bridge;
> >>> + else
> >>> + encoder->bridge = bridge;
> >>>
> >>> return 0;
> >>> }
> >>
> >> <snip>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 10:23 ` Laurent Pinchart
0 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-30 10:23 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard
Hi Archit,
On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> > On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> >> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> >>> Instead of linking encoders and bridges in every driver (and getting it
> >>> wrong half of the time, as many drivers forget to set the drm_bridge
> >>> encoder pointer), do so in core code. The drm_bridge_attach() function
> >>> needs the encoder and optional previous bridge to perform that task,
> >>> update all the callers.
> >>>
> >>> Signed-off-by: Laurent Pinchart
> >>> <laurent.pinchart+renesas@ideasonboard.com>
> >>> ---
> >>>
> >>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> >>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> >>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> >>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++-----
> >>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> >>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> >>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> >>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> >>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> >>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> >>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> >>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> >>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> >>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> >>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> >>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> >>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> >>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> >>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> >>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> >>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> >>> include/drm/drm_bridge.h | 3 +-
> >>> 23 files changed, 83 insertions(+), 103 deletions(-)
> >
> > [snip]
> >
> >>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> >>> index 0ee052b7c21a..850bd6509ef1 100644
> >>> --- a/drivers/gpu/drm/drm_bridge.c
> >>> +++ b/drivers/gpu/drm/drm_bridge.c
> >
> > [snip]
> >
> >>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> >>> EXPORT_SYMBOL(drm_bridge_remove);
> >>>
> >>> /**
> >>> - * drm_bridge_attach - associate given bridge to our DRM device
> >>> + * drm_bridge_attach - attach the bridge to an encoder's chain
> >>> *
> >>> - * @dev: DRM device
> >>> - * @bridge: bridge control structure
> >>> + * @encoder: DRM encoder
> >>> + * @bridge: bridge to attach
> >>> + * @previous: previous bridge in the chain (optional)
> >>> *
> >>> - * Called by a kms driver to link one of our encoder/bridge to the
> >>> given
> >>> - * bridge.
> >>> + * Called by a kms driver to link the bridge to an encoder's chain. The
> >>> previous
> >>> + * argument specifies the previous bridge in the chain. If NULL, the
> >>> bridge is
> >>> + * linked directly at the encoder's output. Otherwise it is linked at
> >>> the
> >>> + * previous bridge's output.
> >>> *
> >>> - * Note that setting up links between the bridge and our encoder/bridge
> >>> - * objects needs to be handled by the kms driver itself.
> >>> + * If non-NULL the previous bridge must be already attached by a call
> >>> to this
> >>> + * function.
> >>> *
> >>> * RETURNS:
> >>> * Zero on success, error code on failure
> >>> */
> >>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
> >>> *bridge)
> >>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
> >>> *bridge,
> >>> + struct drm_bridge *previous)
> >>> {
> >>> - if (!dev || !bridge)
> >>> + int ret;
> >>> +
> >>> + if (!encoder || !bridge)
> >>> + return -EINVAL;
> >>
> >> I think we could derive previous from the encoder itself. Something like:
> >> previous = encoder->bridge;
> >> while (previous && previous->next)
> >>
> >> previous = previous->next;
> >
> > That's a very good point. It would however prevent us from catching
> > drivers that attach bridges in the wrong order, which the !previous->dev
> > currently allows us to do (and it should be turned into a WARN_ON as
> > Daniel proposed).
>
> With the simpler API, I don't think we will ever hit the case of
> !previous->dev. The previous bridge (if it exists) in the chain would
> already have a dev attached to it. In other words, we would remove the
> risk of the chance of the 'previous' bridge being unattached.
>
> I'm a bit unclear about what you mean about the order part. If a kms driver
> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>
> drm_bridge_attach(encoder, bridge1, NULL);
> drm_bridge_attach(encoder, bridge2, bridge1);
Correct.
> We can't do much if the kms driver does the opposite:
>
> drm_bridge_attach(encoder, bridge2, NULL);
> drm_bridge_attach(encoder, bridge2, bridge1);
That would certainly be a very stupid thing for a driver to do :-) The problem
that we could catch with my current proposal is
drm_bridge_attach(encoder, bridge2, bridge1);
...
drm_bridge_attach(encoder, bridge1, NULL);
which I expect to happen from time to time as the two bridge can be attached
through separate code paths sometimes a bit difficult to trace. It's not a big
deal though, you could convince me that the advantages of a simpler API exceed
its drawbacks.
> > I'm fine losing that ability, as your proposal makes the API simpler. I'll
> > let you decide, which option do you prefer ?
>
> I prefer the simpler API. I guess the main aim of the patch was to prevent
> the driver setting up the encoder<->bridge links, which will be done
> anyway.
If you still prefer the simpler API after reading the above, I'll update my
patch.
> >>> +
> >>> + if (previous && (!previous->dev || previous->encoder != encoder))
> >>> return -EINVAL;
> >>>
> >>> if (bridge->dev)
> >>> return -EBUSY;
> >>>
> >>> - bridge->dev = dev;
> >>> + bridge->dev = encoder->dev;
> >>> + bridge->encoder = encoder;
> >>> +
> >>> + if (bridge->funcs->attach) {
> >>> + ret = bridge->funcs->attach(bridge);
> >>> + if (ret < 0) {
> >>> + bridge->dev = NULL;
> >>> + bridge->encoder = NULL;
> >>> + return ret;
> >>> + }
> >>> + }
> >>>
> >>> - if (bridge->funcs->attach)
> >>> - return bridge->funcs->attach(bridge);
> >>> + if (previous)
> >>> + previous->next = bridge;
> >>> + else
> >>> + encoder->bridge = bridge;
> >>>
> >>> return 0;
> >>> }
> >>
> >> <snip>
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-30 10:23 ` Laurent Pinchart
@ 2016-11-30 11:00 ` Archit Taneja
-1 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 11:00 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
>> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
>>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>>>> Instead of linking encoders and bridges in every driver (and getting it
>>>>> wrong half of the time, as many drivers forget to set the drm_bridge
>>>>> encoder pointer), do so in core code. The drm_bridge_attach() function
>>>>> needs the encoder and optional previous bridge to perform that task,
>>>>> update all the callers.
>>>>>
>>>>> Signed-off-by: Laurent Pinchart
>>>>> <laurent.pinchart+renesas@ideasonboard.com>
>>>>> ---
>>>>>
>>>>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
>>>>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
>>>>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
>>>>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++-----
>>>>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
>>>>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
>>>>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
>>>>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
>>>>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
>>>>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
>>>>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
>>>>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
>>>>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
>>>>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
>>>>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
>>>>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
>>>>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
>>>>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
>>>>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
>>>>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
>>>>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
>>>>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
>>>>> include/drm/drm_bridge.h | 3 +-
>>>>> 23 files changed, 83 insertions(+), 103 deletions(-)
>>>
>>> [snip]
>>>
>>>>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>>>>> index 0ee052b7c21a..850bd6509ef1 100644
>>>>> --- a/drivers/gpu/drm/drm_bridge.c
>>>>> +++ b/drivers/gpu/drm/drm_bridge.c
>>>
>>> [snip]
>>>
>>>>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
>>>>> EXPORT_SYMBOL(drm_bridge_remove);
>>>>>
>>>>> /**
>>>>> - * drm_bridge_attach - associate given bridge to our DRM device
>>>>> + * drm_bridge_attach - attach the bridge to an encoder's chain
>>>>> *
>>>>> - * @dev: DRM device
>>>>> - * @bridge: bridge control structure
>>>>> + * @encoder: DRM encoder
>>>>> + * @bridge: bridge to attach
>>>>> + * @previous: previous bridge in the chain (optional)
>>>>> *
>>>>> - * Called by a kms driver to link one of our encoder/bridge to the
>>>>> given
>>>>> - * bridge.
>>>>> + * Called by a kms driver to link the bridge to an encoder's chain. The
>>>>> previous
>>>>> + * argument specifies the previous bridge in the chain. If NULL, the
>>>>> bridge is
>>>>> + * linked directly at the encoder's output. Otherwise it is linked at
>>>>> the
>>>>> + * previous bridge's output.
>>>>> *
>>>>> - * Note that setting up links between the bridge and our encoder/bridge
>>>>> - * objects needs to be handled by the kms driver itself.
>>>>> + * If non-NULL the previous bridge must be already attached by a call
>>>>> to this
>>>>> + * function.
>>>>> *
>>>>> * RETURNS:
>>>>> * Zero on success, error code on failure
>>>>> */
>>>>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
>>>>> *bridge)
>>>>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
>>>>> *bridge,
>>>>> + struct drm_bridge *previous)
>>>>> {
>>>>> - if (!dev || !bridge)
>>>>> + int ret;
>>>>> +
>>>>> + if (!encoder || !bridge)
>>>>> + return -EINVAL;
>>>>
>>>> I think we could derive previous from the encoder itself. Something like:
>>>> previous = encoder->bridge;
>>>> while (previous && previous->next)
>>>>
>>>> previous = previous->next;
>>>
>>> That's a very good point. It would however prevent us from catching
>>> drivers that attach bridges in the wrong order, which the !previous->dev
>>> currently allows us to do (and it should be turned into a WARN_ON as
>>> Daniel proposed).
>>
>> With the simpler API, I don't think we will ever hit the case of
>> !previous->dev. The previous bridge (if it exists) in the chain would
>> already have a dev attached to it. In other words, we would remove the
>> risk of the chance of the 'previous' bridge being unattached.
>>
>> I'm a bit unclear about what you mean about the order part. If a kms driver
>> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>>
>> drm_bridge_attach(encoder, bridge1, NULL);
>> drm_bridge_attach(encoder, bridge2, bridge1);
>
> Correct.
>
>> We can't do much if the kms driver does the opposite:
>>
>> drm_bridge_attach(encoder, bridge2, NULL);
>> drm_bridge_attach(encoder, bridge2, bridge1);
>
> That would certainly be a very stupid thing for a driver to do :-) The problem
> that we could catch with my current proposal is
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> ...
> drm_bridge_attach(encoder, bridge1, NULL);
>
> which I expect to happen from time to time as the two bridge can be attached
> through separate code paths sometimes a bit difficult to trace. It's not a big
> deal though, you could convince me that the advantages of a simpler API exceed
> its drawbacks.
Having no 'previous' argument would prevent the possibility of this altogether,
won't it?
With no 'previous' arg in the API, the driver can only do:
drm_bridge_attach(encoder, bridge1);
drm_bridge_attach(encoder, bridge2);
or
drm_bridge_attach(encoder, bridge2);
drm_bridge_attach(encoder, bridge1);
For the latter, we can't do much as discussed above.
Archit
>
>>> I'm fine losing that ability, as your proposal makes the API simpler. I'll
>>> let you decide, which option do you prefer ?
>>
>> I prefer the simpler API. I guess the main aim of the patch was to prevent
>> the driver setting up the encoder<->bridge links, which will be done
>> anyway.
>
> If you still prefer the simpler API after reading the above, I'll update my
> patch.
>
>>>>> +
>>>>> + if (previous && (!previous->dev || previous->encoder != encoder))
>>>>> return -EINVAL;
>>>>>
>>>>> if (bridge->dev)
>>>>> return -EBUSY;
>>>>>
>>>>> - bridge->dev = dev;
>>>>> + bridge->dev = encoder->dev;
>>>>> + bridge->encoder = encoder;
>>>>> +
>>>>> + if (bridge->funcs->attach) {
>>>>> + ret = bridge->funcs->attach(bridge);
>>>>> + if (ret < 0) {
>>>>> + bridge->dev = NULL;
>>>>> + bridge->encoder = NULL;
>>>>> + return ret;
>>>>> + }
>>>>> + }
>>>>>
>>>>> - if (bridge->funcs->attach)
>>>>> - return bridge->funcs->attach(bridge);
>>>>> + if (previous)
>>>>> + previous->next = bridge;
>>>>> + else
>>>>> + encoder->bridge = bridge;
>>>>>
>>>>> return 0;
>>>>> }
>>>>
>>>> <snip>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 11:00 ` Archit Taneja
0 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 11:00 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, Alison Wang, Jingoo Han, Seung-Woo Kim,
Xinwei Kong, dri-devel, linux-renesas-soc, Kyungmin Park,
Xinliang Liu, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
>> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
>>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>>>> Instead of linking encoders and bridges in every driver (and getting it
>>>>> wrong half of the time, as many drivers forget to set the drm_bridge
>>>>> encoder pointer), do so in core code. The drm_bridge_attach() function
>>>>> needs the encoder and optional previous bridge to perform that task,
>>>>> update all the callers.
>>>>>
>>>>> Signed-off-by: Laurent Pinchart
>>>>> <laurent.pinchart+renesas@ideasonboard.com>
>>>>> ---
>>>>>
>>>>> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
>>>>> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
>>>>> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
>>>>> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++-----
>>>>> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
>>>>> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
>>>>> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
>>>>> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
>>>>> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
>>>>> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
>>>>> drivers/gpu/drm/imx/parallel-display.c | 4 +-
>>>>> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
>>>>> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
>>>>> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
>>>>> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
>>>>> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
>>>>> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
>>>>> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
>>>>> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
>>>>> drivers/gpu/drm/sti/sti_hda.c | 3 +-
>>>>> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
>>>>> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
>>>>> include/drm/drm_bridge.h | 3 +-
>>>>> 23 files changed, 83 insertions(+), 103 deletions(-)
>>>
>>> [snip]
>>>
>>>>> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
>>>>> index 0ee052b7c21a..850bd6509ef1 100644
>>>>> --- a/drivers/gpu/drm/drm_bridge.c
>>>>> +++ b/drivers/gpu/drm/drm_bridge.c
>>>
>>> [snip]
>>>
>>>>> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
>>>>> EXPORT_SYMBOL(drm_bridge_remove);
>>>>>
>>>>> /**
>>>>> - * drm_bridge_attach - associate given bridge to our DRM device
>>>>> + * drm_bridge_attach - attach the bridge to an encoder's chain
>>>>> *
>>>>> - * @dev: DRM device
>>>>> - * @bridge: bridge control structure
>>>>> + * @encoder: DRM encoder
>>>>> + * @bridge: bridge to attach
>>>>> + * @previous: previous bridge in the chain (optional)
>>>>> *
>>>>> - * Called by a kms driver to link one of our encoder/bridge to the
>>>>> given
>>>>> - * bridge.
>>>>> + * Called by a kms driver to link the bridge to an encoder's chain. The
>>>>> previous
>>>>> + * argument specifies the previous bridge in the chain. If NULL, the
>>>>> bridge is
>>>>> + * linked directly at the encoder's output. Otherwise it is linked at
>>>>> the
>>>>> + * previous bridge's output.
>>>>> *
>>>>> - * Note that setting up links between the bridge and our encoder/bridge
>>>>> - * objects needs to be handled by the kms driver itself.
>>>>> + * If non-NULL the previous bridge must be already attached by a call
>>>>> to this
>>>>> + * function.
>>>>> *
>>>>> * RETURNS:
>>>>> * Zero on success, error code on failure
>>>>> */
>>>>> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge
>>>>> *bridge)
>>>>> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge
>>>>> *bridge,
>>>>> + struct drm_bridge *previous)
>>>>> {
>>>>> - if (!dev || !bridge)
>>>>> + int ret;
>>>>> +
>>>>> + if (!encoder || !bridge)
>>>>> + return -EINVAL;
>>>>
>>>> I think we could derive previous from the encoder itself. Something like:
>>>> previous = encoder->bridge;
>>>> while (previous && previous->next)
>>>>
>>>> previous = previous->next;
>>>
>>> That's a very good point. It would however prevent us from catching
>>> drivers that attach bridges in the wrong order, which the !previous->dev
>>> currently allows us to do (and it should be turned into a WARN_ON as
>>> Daniel proposed).
>>
>> With the simpler API, I don't think we will ever hit the case of
>> !previous->dev. The previous bridge (if it exists) in the chain would
>> already have a dev attached to it. In other words, we would remove the
>> risk of the chance of the 'previous' bridge being unattached.
>>
>> I'm a bit unclear about what you mean about the order part. If a kms driver
>> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>>
>> drm_bridge_attach(encoder, bridge1, NULL);
>> drm_bridge_attach(encoder, bridge2, bridge1);
>
> Correct.
>
>> We can't do much if the kms driver does the opposite:
>>
>> drm_bridge_attach(encoder, bridge2, NULL);
>> drm_bridge_attach(encoder, bridge2, bridge1);
>
> That would certainly be a very stupid thing for a driver to do :-) The problem
> that we could catch with my current proposal is
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> ...
> drm_bridge_attach(encoder, bridge1, NULL);
>
> which I expect to happen from time to time as the two bridge can be attached
> through separate code paths sometimes a bit difficult to trace. It's not a big
> deal though, you could convince me that the advantages of a simpler API exceed
> its drawbacks.
Having no 'previous' argument would prevent the possibility of this altogether,
won't it?
With no 'previous' arg in the API, the driver can only do:
drm_bridge_attach(encoder, bridge1);
drm_bridge_attach(encoder, bridge2);
or
drm_bridge_attach(encoder, bridge2);
drm_bridge_attach(encoder, bridge1);
For the latter, we can't do much as discussed above.
Archit
>
>>> I'm fine losing that ability, as your proposal makes the API simpler. I'll
>>> let you decide, which option do you prefer ?
>>
>> I prefer the simpler API. I guess the main aim of the patch was to prevent
>> the driver setting up the encoder<->bridge links, which will be done
>> anyway.
>
> If you still prefer the simpler API after reading the above, I'll update my
> patch.
>
>>>>> +
>>>>> + if (previous && (!previous->dev || previous->encoder != encoder))
>>>>> return -EINVAL;
>>>>>
>>>>> if (bridge->dev)
>>>>> return -EBUSY;
>>>>>
>>>>> - bridge->dev = dev;
>>>>> + bridge->dev = encoder->dev;
>>>>> + bridge->encoder = encoder;
>>>>> +
>>>>> + if (bridge->funcs->attach) {
>>>>> + ret = bridge->funcs->attach(bridge);
>>>>> + if (ret < 0) {
>>>>> + bridge->dev = NULL;
>>>>> + bridge->encoder = NULL;
>>>>> + return ret;
>>>>> + }
>>>>> + }
>>>>>
>>>>> - if (bridge->funcs->attach)
>>>>> - return bridge->funcs->attach(bridge);
>>>>> + if (previous)
>>>>> + previous->next = bridge;
>>>>> + else
>>>>> + encoder->bridge = bridge;
>>>>>
>>>>> return 0;
>>>>> }
>>>>
>>>> <snip>
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-30 11:00 ` Archit Taneja
@ 2016-11-30 11:05 ` Laurent Pinchart
-1 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-30 11:05 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
Hi Archit,
On Wednesday 30 Nov 2016 16:30:53 Archit Taneja wrote:
> On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
> > On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
> >> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> >>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> >>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> >>>>> Instead of linking encoders and bridges in every driver (and getting
> >>>>> it wrong half of the time, as many drivers forget to set the
> >>>>> drm_bridge encoder pointer), do so in core code. The
> >>>>> drm_bridge_attach() function needs the encoder and optional previous
> >>>>> bridge to perform that task, update all the callers.
> >>>>>
> >>>>> Signed-off-by: Laurent Pinchart
> >>>>> <laurent.pinchart+renesas@ideasonboard.com>
> >>>>> ---
[snip]
> >>>> I think we could derive previous from the encoder itself. Something
> >>>> like:
> >>>>
> >>>> previous = encoder->bridge;
> >>>> while (previous && previous->next)
> >>>> previous = previous->next;
> >>>
> >>> That's a very good point. It would however prevent us from catching
> >>> drivers that attach bridges in the wrong order, which the !previous->dev
> >>> currently allows us to do (and it should be turned into a WARN_ON as
> >>> Daniel proposed).
> >>
> >> With the simpler API, I don't think we will ever hit the case of
> >> !previous->dev. The previous bridge (if it exists) in the chain would
> >> already have a dev attached to it. In other words, we would remove the
> >> risk of the chance of the 'previous' bridge being unattached.
> >>
> >> I'm a bit unclear about what you mean about the order part. If a kms
> >> driver
> >> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
> >>
> >> drm_bridge_attach(encoder, bridge1, NULL);
> >> drm_bridge_attach(encoder, bridge2, bridge1);
> >
> > Correct.
> >
> >> We can't do much if the kms driver does the opposite:
> >>
> >> drm_bridge_attach(encoder, bridge2, NULL);
> >> drm_bridge_attach(encoder, bridge2, bridge1);
> >
> > That would certainly be a very stupid thing for a driver to do :-) The
> > problem that we could catch with my current proposal is
> >
> > drm_bridge_attach(encoder, bridge2, bridge1);
> > ...
> > drm_bridge_attach(encoder, bridge1, NULL);
> >
> > which I expect to happen from time to time as the two bridge can be
> > attached through separate code paths sometimes a bit difficult to trace.
> > It's not a big deal though, you could convince me that the advantages of
> > a simpler API exceed its drawbacks.
>
> Having no 'previous' argument would prevent the possibility of this
> altogether, won't it?
>
> With no 'previous' arg in the API, the driver can only do:
>
> drm_bridge_attach(encoder, bridge1);
> drm_bridge_attach(encoder, bridge2);
>
> or
>
> drm_bridge_attach(encoder, bridge2);
> drm_bridge_attach(encoder, bridge1);
Correct.
> For the latter, we can't do much as discussed above.
Except that with the currently proposed API the code would be
drm_bridge_attach(encoder, bridge2, bridge1);
drm_bridge_attach(encoder, bridge1, NULL);
(correct case)
or
drm_bridge_attach(encoder, bridge2, bridge1);
drm_bridge_attach(encoder, bridge1, NULL);
(incorrect case)
The second one could be caught by the drm_bridge_attach() function as bridge1-
>dev will be NULL when attaching bridge2 in the incorrect case.
--
Regards,
Laurent Pinchart
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 11:05 ` Laurent Pinchart
0 siblings, 0 replies; 100+ messages in thread
From: Laurent Pinchart @ 2016-11-30 11:05 UTC (permalink / raw)
To: Archit Taneja
Cc: Laurent Pinchart, Alison Wang, Jingoo Han, Seung-Woo Kim,
Xinwei Kong, dri-devel, linux-renesas-soc, Kyungmin Park,
Xinliang Liu, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
Hi Archit,
On Wednesday 30 Nov 2016 16:30:53 Archit Taneja wrote:
> On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
> > On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
> >> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
> >>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
> >>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
> >>>>> Instead of linking encoders and bridges in every driver (and getting
> >>>>> it wrong half of the time, as many drivers forget to set the
> >>>>> drm_bridge encoder pointer), do so in core code. The
> >>>>> drm_bridge_attach() function needs the encoder and optional previous
> >>>>> bridge to perform that task, update all the callers.
> >>>>>
> >>>>> Signed-off-by: Laurent Pinchart
> >>>>> <laurent.pinchart+renesas@ideasonboard.com>
> >>>>> ---
[snip]
> >>>> I think we could derive previous from the encoder itself. Something
> >>>> like:
> >>>>
> >>>> previous = encoder->bridge;
> >>>> while (previous && previous->next)
> >>>> previous = previous->next;
> >>>
> >>> That's a very good point. It would however prevent us from catching
> >>> drivers that attach bridges in the wrong order, which the !previous->dev
> >>> currently allows us to do (and it should be turned into a WARN_ON as
> >>> Daniel proposed).
> >>
> >> With the simpler API, I don't think we will ever hit the case of
> >> !previous->dev. The previous bridge (if it exists) in the chain would
> >> already have a dev attached to it. In other words, we would remove the
> >> risk of the chance of the 'previous' bridge being unattached.
> >>
> >> I'm a bit unclear about what you mean about the order part. If a kms
> >> driver
> >> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
> >>
> >> drm_bridge_attach(encoder, bridge1, NULL);
> >> drm_bridge_attach(encoder, bridge2, bridge1);
> >
> > Correct.
> >
> >> We can't do much if the kms driver does the opposite:
> >>
> >> drm_bridge_attach(encoder, bridge2, NULL);
> >> drm_bridge_attach(encoder, bridge2, bridge1);
> >
> > That would certainly be a very stupid thing for a driver to do :-) The
> > problem that we could catch with my current proposal is
> >
> > drm_bridge_attach(encoder, bridge2, bridge1);
> > ...
> > drm_bridge_attach(encoder, bridge1, NULL);
> >
> > which I expect to happen from time to time as the two bridge can be
> > attached through separate code paths sometimes a bit difficult to trace.
> > It's not a big deal though, you could convince me that the advantages of
> > a simpler API exceed its drawbacks.
>
> Having no 'previous' argument would prevent the possibility of this
> altogether, won't it?
>
> With no 'previous' arg in the API, the driver can only do:
>
> drm_bridge_attach(encoder, bridge1);
> drm_bridge_attach(encoder, bridge2);
>
> or
>
> drm_bridge_attach(encoder, bridge2);
> drm_bridge_attach(encoder, bridge1);
Correct.
> For the latter, we can't do much as discussed above.
Except that with the currently proposed API the code would be
drm_bridge_attach(encoder, bridge2, bridge1);
drm_bridge_attach(encoder, bridge1, NULL);
(correct case)
or
drm_bridge_attach(encoder, bridge2, bridge1);
drm_bridge_attach(encoder, bridge1, NULL);
(incorrect case)
The second one could be caught by the drm_bridge_attach() function as bridge1-
>dev will be NULL when attaching bridge2 in the incorrect case.
--
Regards,
Laurent Pinchart
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-30 11:05 ` Laurent Pinchart
@ 2016-11-30 13:27 ` Archit Taneja
-1 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 13:27 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, dri-devel, linux-renesas-soc, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Stefan Agner, Alison Wang, Xinliang Liu,
Rongrong Zou, Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu,
Rob Clark, Benjamin Gaignard, Vincent Abriou, Maxime Ripard
On 11/30/2016 4:35 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Wednesday 30 Nov 2016 16:30:53 Archit Taneja wrote:
>> On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
>>> On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
>>>> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
>>>>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>>>>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>>>>>> Instead of linking encoders and bridges in every driver (and getting
>>>>>>> it wrong half of the time, as many drivers forget to set the
>>>>>>> drm_bridge encoder pointer), do so in core code. The
>>>>>>> drm_bridge_attach() function needs the encoder and optional previous
>>>>>>> bridge to perform that task, update all the callers.
>>>>>>>
>>>>>>> Signed-off-by: Laurent Pinchart
>>>>>>> <laurent.pinchart+renesas@ideasonboard.com>
>>>>>>> ---
>
> [snip]
>
>>>>>> I think we could derive previous from the encoder itself. Something
>>>>>> like:
>>>>>>
>>>>>> previous = encoder->bridge;
>>>>>> while (previous && previous->next)
>>>>>> previous = previous->next;
>>>>>
>>>>> That's a very good point. It would however prevent us from catching
>>>>> drivers that attach bridges in the wrong order, which the !previous->dev
>>>>> currently allows us to do (and it should be turned into a WARN_ON as
>>>>> Daniel proposed).
>>>>
>>>> With the simpler API, I don't think we will ever hit the case of
>>>> !previous->dev. The previous bridge (if it exists) in the chain would
>>>> already have a dev attached to it. In other words, we would remove the
>>>> risk of the chance of the 'previous' bridge being unattached.
>>>>
>>>> I'm a bit unclear about what you mean about the order part. If a kms
>>>> driver
>>>> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>>>>
>>>> drm_bridge_attach(encoder, bridge1, NULL);
>>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>>
>>> Correct.
>>>
>>>> We can't do much if the kms driver does the opposite:
>>>>
>>>> drm_bridge_attach(encoder, bridge2, NULL);
>>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>>
>>> That would certainly be a very stupid thing for a driver to do :-) The
>>> problem that we could catch with my current proposal is
>>>
>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>> ...
>>> drm_bridge_attach(encoder, bridge1, NULL);
>>>
>>> which I expect to happen from time to time as the two bridge can be
>>> attached through separate code paths sometimes a bit difficult to trace.
>>> It's not a big deal though, you could convince me that the advantages of
>>> a simpler API exceed its drawbacks.
>>
>> Having no 'previous' argument would prevent the possibility of this
>> altogether, won't it?
>>
>> With no 'previous' arg in the API, the driver can only do:
>>
>> drm_bridge_attach(encoder, bridge1);
>> drm_bridge_attach(encoder, bridge2);
>>
>> or
>>
>> drm_bridge_attach(encoder, bridge2);
>> drm_bridge_attach(encoder, bridge1);
>
> Correct.
>
>> For the latter, we can't do much as discussed above.
>
> Except that with the currently proposed API the code would be
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> drm_bridge_attach(encoder, bridge1, NULL);
>
> (correct case)
>
> or
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> drm_bridge_attach(encoder, bridge1, NULL);
>
> (incorrect case)
>
> The second one could be caught by the drm_bridge_attach() function as bridge1-
>> dev will be NULL when attaching bridge2 in the incorrect case.
Okay, I got it now.
As you said, it does make sense for cases like analogix_dp, where one
attach is in the bridge driver, and the other is in the kms driver.
It makes things more legible too. Passing 'previous' as NULL makes it
clear in the code that we're attaching first bridge in the chain.
Let's stick to your proposal.
One additional thing we could do is to compare the 'previous' arg
passed by the API with the last bridge in the chain, and return
an error if they aren't the same, just as an additional safety
measure.
Archit
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 13:27 ` Archit Taneja
0 siblings, 0 replies; 100+ messages in thread
From: Archit Taneja @ 2016-11-30 13:27 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Laurent Pinchart, Alison Wang, Jingoo Han, Seung-Woo Kim,
Xinwei Kong, dri-devel, linux-renesas-soc, Kyungmin Park,
Xinliang Liu, Chen Feng, Rongrong Zou, Maxime Ripard,
Vincent Abriou
On 11/30/2016 4:35 PM, Laurent Pinchart wrote:
> Hi Archit,
>
> On Wednesday 30 Nov 2016 16:30:53 Archit Taneja wrote:
>> On 11/30/2016 03:53 PM, Laurent Pinchart wrote:
>>> On Wednesday 30 Nov 2016 10:35:02 Archit Taneja wrote:
>>>> On 11/29/2016 11:27 PM, Laurent Pinchart wrote:
>>>>> On Tuesday 29 Nov 2016 15:57:06 Archit Taneja wrote:
>>>>>> On 11/29/2016 02:34 PM, Laurent Pinchart wrote:
>>>>>>> Instead of linking encoders and bridges in every driver (and getting
>>>>>>> it wrong half of the time, as many drivers forget to set the
>>>>>>> drm_bridge encoder pointer), do so in core code. The
>>>>>>> drm_bridge_attach() function needs the encoder and optional previous
>>>>>>> bridge to perform that task, update all the callers.
>>>>>>>
>>>>>>> Signed-off-by: Laurent Pinchart
>>>>>>> <laurent.pinchart+renesas@ideasonboard.com>
>>>>>>> ---
>
> [snip]
>
>>>>>> I think we could derive previous from the encoder itself. Something
>>>>>> like:
>>>>>>
>>>>>> previous = encoder->bridge;
>>>>>> while (previous && previous->next)
>>>>>> previous = previous->next;
>>>>>
>>>>> That's a very good point. It would however prevent us from catching
>>>>> drivers that attach bridges in the wrong order, which the !previous->dev
>>>>> currently allows us to do (and it should be turned into a WARN_ON as
>>>>> Daniel proposed).
>>>>
>>>> With the simpler API, I don't think we will ever hit the case of
>>>> !previous->dev. The previous bridge (if it exists) in the chain would
>>>> already have a dev attached to it. In other words, we would remove the
>>>> risk of the chance of the 'previous' bridge being unattached.
>>>>
>>>> I'm a bit unclear about what you mean about the order part. If a kms
>>>> driver
>>>> wants to create a chain: encoder->bridge1->bridge2, it should ideally do:
>>>>
>>>> drm_bridge_attach(encoder, bridge1, NULL);
>>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>>
>>> Correct.
>>>
>>>> We can't do much if the kms driver does the opposite:
>>>>
>>>> drm_bridge_attach(encoder, bridge2, NULL);
>>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>>
>>> That would certainly be a very stupid thing for a driver to do :-) The
>>> problem that we could catch with my current proposal is
>>>
>>> drm_bridge_attach(encoder, bridge2, bridge1);
>>> ...
>>> drm_bridge_attach(encoder, bridge1, NULL);
>>>
>>> which I expect to happen from time to time as the two bridge can be
>>> attached through separate code paths sometimes a bit difficult to trace.
>>> It's not a big deal though, you could convince me that the advantages of
>>> a simpler API exceed its drawbacks.
>>
>> Having no 'previous' argument would prevent the possibility of this
>> altogether, won't it?
>>
>> With no 'previous' arg in the API, the driver can only do:
>>
>> drm_bridge_attach(encoder, bridge1);
>> drm_bridge_attach(encoder, bridge2);
>>
>> or
>>
>> drm_bridge_attach(encoder, bridge2);
>> drm_bridge_attach(encoder, bridge1);
>
> Correct.
>
>> For the latter, we can't do much as discussed above.
>
> Except that with the currently proposed API the code would be
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> drm_bridge_attach(encoder, bridge1, NULL);
>
> (correct case)
>
> or
>
> drm_bridge_attach(encoder, bridge2, bridge1);
> drm_bridge_attach(encoder, bridge1, NULL);
>
> (incorrect case)
>
> The second one could be caught by the drm_bridge_attach() function as bridge1-
>> dev will be NULL when attaching bridge2 in the incorrect case.
Okay, I got it now.
As you said, it does make sense for cases like analogix_dp, where one
attach is in the bridge driver, and the other is in the kms driver.
It makes things more legible too. Passing 'previous' as NULL makes it
clear in the code that we're attaching first bridge in the chain.
Let's stick to your proposal.
One additional thing we could do is to compare the 'previous' arg
passed by the API with the last bridge in the chain, and return
an error if they aren't the same, just as an additional safety
measure.
Archit
>
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:04 ` Laurent Pinchart
@ 2016-11-29 17:01 ` Stefan Agner
-1 siblings, 0 replies; 100+ messages in thread
From: Stefan Agner @ 2016-11-29 17:01 UTC (permalink / raw)
To: Laurent Pinchart
Cc: dri-devel, linux-renesas-soc, Archit Taneja, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Alison Wang, Xinliang Liu, Rongrong Zou,
Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu, Rob Clark,
Benjamin Gaignard, Vincent Abriou, Maxime Ripard
On 2016-11-29 01:04, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
For DCU
Acked-by: Stefan Agner <stefan@agner.ch>
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct
> drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct
> drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device
> *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain.
> The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c
> b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs
> drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c
> b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct
> analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct
> analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev,
> struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct
> fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device
> *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c
> b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c
> b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct
> device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c
> b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct
> mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct
> drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct
> drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector
> *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c
> b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev,
> struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct
> device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev,
> struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 17:01 ` Stefan Agner
0 siblings, 0 replies; 100+ messages in thread
From: Stefan Agner @ 2016-11-29 17:01 UTC (permalink / raw)
To: Laurent Pinchart
Cc: dri-devel, linux-renesas-soc, Archit Taneja, Boris Brezillon,
Jingoo Han, Inki Dae, Joonyoung Shim, Seung-Woo Kim,
Kyungmin Park, Alison Wang, Xinliang Liu, Rongrong Zou,
Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu, Rob Clark,
Benjamin Gaignard, Vincent Abriou, Maxime
On 2016-11-29 01:04, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
For DCU
Acked-by: Stefan Agner <stefan@agner.ch>
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct
> drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct
> drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device
> *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain.
> The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c
> b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs
> drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c
> b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct
> analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct
> analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev,
> struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct
> fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device
> *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c
> b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c
> b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct
> device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c
> b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct
> mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct
> drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct
> drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector
> *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c
> b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev,
> struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct
> device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev,
> struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:04 ` Laurent Pinchart
@ 2016-11-29 19:58 ` Boris Brezillon
-1 siblings, 0 replies; 100+ messages in thread
From: Boris Brezillon @ 2016-11-29 19:58 UTC (permalink / raw)
To: Laurent Pinchart
Cc: dri-devel, linux-renesas-soc, Archit Taneja, Jingoo Han,
Inki Dae, Joonyoung Shim, Seung-Woo Kim, Kyungmin Park,
Stefan Agner, Alison Wang, Xinliang Liu, Rongrong Zou,
Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu, Rob Clark,
Benjamin Gaignard, Vincent Abriou, Maxime Ripard
On Tue, 29 Nov 2016 11:04:33 +0200
Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
For atmel-hlcdc
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-29 19:58 ` Boris Brezillon
0 siblings, 0 replies; 100+ messages in thread
From: Boris Brezillon @ 2016-11-29 19:58 UTC (permalink / raw)
To: Laurent Pinchart
Cc: Alison Wang, Jingoo Han, Seung-Woo Kim, Xinwei Kong, dri-devel,
linux-renesas-soc, Kyungmin Park, Xinliang Liu, Chen Feng,
Rongrong Zou, Maxime Ripard, Vincent Abriou
On Tue, 29 Nov 2016 11:04:33 +0200
Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com> wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
For atmel-hlcdc
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
2016-11-29 9:04 ` Laurent Pinchart
@ 2016-11-30 15:30 ` Vincent ABRIOU
-1 siblings, 0 replies; 100+ messages in thread
From: Vincent ABRIOU @ 2016-11-30 15:30 UTC (permalink / raw)
To: Laurent Pinchart, dri-devel
Cc: linux-renesas-soc, Archit Taneja, Boris Brezillon, Jingoo Han,
Inki Dae, Joonyoung Shim, Seung-Woo Kim, Kyungmin Park,
Stefan Agner, Alison Wang, Xinliang Liu, Rongrong Zou,
Xinwei Kong, Chen Feng, Philipp Zabel, CK Hu, Rob Clark,
Benjamin Gaignard, Maxime Ripard
On 11/29/2016 10:04 AM, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
Hi Laurent,
For sti dvo, hda and hdmi:
Acked-by: Vincent Abriou <vincent.abriou@st.com>
Vincent
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> --
> Regards,
>
> Laurent Pinchart
>
^ permalink raw reply [flat|nested] 100+ messages in thread
* Re: [PATCH v3 03/13] drm: bridge: Link encoder and bridge in core code
@ 2016-11-30 15:30 ` Vincent ABRIOU
0 siblings, 0 replies; 100+ messages in thread
From: Vincent ABRIOU @ 2016-11-30 15:30 UTC (permalink / raw)
To: Laurent Pinchart, dri-devel
Cc: Alison Wang, Jingoo Han, Seung-Woo Kim, Xinwei Kong,
linux-renesas-soc, Kyungmin Park, Xinliang Liu, Chen Feng,
Rongrong Zou, Maxime Ripard
On 11/29/2016 10:04 AM, Laurent Pinchart wrote:
> Instead of linking encoders and bridges in every driver (and getting it
> wrong half of the time, as many drivers forget to set the drm_bridge
> encoder pointer), do so in core code. The drm_bridge_attach() function
> needs the encoder and optional previous bridge to perform that task,
> update all the callers.
>
> Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
> ---
> drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c | 4 +-
> drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 +-
> drivers/gpu/drm/bridge/dw-hdmi.c | 3 +-
> drivers/gpu/drm/drm_bridge.c | 46 ++++++++++++++++------
> drivers/gpu/drm/drm_simple_kms_helper.c | 4 +-
> drivers/gpu/drm/exynos/exynos_dp.c | 5 +--
> drivers/gpu/drm/exynos/exynos_drm_dsi.c | 6 +--
> drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c | 5 +--
> drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c | 5 +--
> drivers/gpu/drm/imx/imx-ldb.c | 6 +--
> drivers/gpu/drm/imx/parallel-display.c | 4 +-
> drivers/gpu/drm/mediatek/mtk_dpi.c | 8 ++--
> drivers/gpu/drm/mediatek/mtk_dsi.c | 24 ++---------
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 11 +++---
> drivers/gpu/drm/msm/dsi/dsi_manager.c | 17 +++++---
> drivers/gpu/drm/msm/edp/edp_bridge.c | 2 +-
> drivers/gpu/drm/msm/hdmi/hdmi_bridge.c | 2 +-
> drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c | 5 +--
> drivers/gpu/drm/sti/sti_dvo.c | 3 +-
> drivers/gpu/drm/sti/sti_hda.c | 3 +-
> drivers/gpu/drm/sti/sti_hdmi.c | 3 +-
Hi Laurent,
For sti dvo, hda and hdmi:
Acked-by: Vincent Abriou <vincent.abriou@st.com>
Vincent
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 13 +++---
> include/drm/drm_bridge.h | 3 +-
> 23 files changed, 83 insertions(+), 103 deletions(-)
>
> diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> index 6119b5085501..e7799b6ee829 100644
> --- a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> +++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
> @@ -230,9 +230,7 @@ static int atmel_hlcdc_attach_endpoint(struct drm_device *dev,
> of_node_put(np);
>
> if (bridge) {
> - output->encoder.bridge = bridge;
> - bridge->encoder = &output->encoder;
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(&output->encoder, bridge, NULL);
> if (!ret)
> return 0;
> }
> diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> index 6e0447f329a2..1835f1fdad19 100644
> --- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> +++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
> @@ -1227,12 +1227,10 @@ static int analogix_dp_create_bridge(struct drm_device *drm_dev,
>
> dp->bridge = bridge;
>
> - dp->encoder->bridge = bridge;
> bridge->driver_private = dp;
> - bridge->encoder = dp->encoder;
> bridge->funcs = &analogix_dp_bridge_funcs;
>
> - ret = drm_bridge_attach(drm_dev, bridge);
> + ret = drm_bridge_attach(dp->encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach drm bridge\n");
> return -EINVAL;
> diff --git a/drivers/gpu/drm/bridge/dw-hdmi.c b/drivers/gpu/drm/bridge/dw-hdmi.c
> index b71088dab268..432e0e3fff72 100644
> --- a/drivers/gpu/drm/bridge/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/dw-hdmi.c
> @@ -1841,13 +1841,12 @@ static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
> hdmi->bridge = bridge;
> bridge->driver_private = hdmi;
> bridge->funcs = &dw_hdmi_bridge_funcs;
> - ret = drm_bridge_attach(drm, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return -EINVAL;
> }
>
> - encoder->bridge = bridge;
> hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
>
> drm_connector_helper_add(&hdmi->connector,
> diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
> index 0ee052b7c21a..850bd6509ef1 100644
> --- a/drivers/gpu/drm/drm_bridge.c
> +++ b/drivers/gpu/drm/drm_bridge.c
> @@ -26,6 +26,7 @@
> #include <linux/mutex.h>
>
> #include <drm/drm_bridge.h>
> +#include <drm/drm_encoder.h>
>
> /**
> * DOC: overview
> @@ -92,32 +93,53 @@ void drm_bridge_remove(struct drm_bridge *bridge)
> EXPORT_SYMBOL(drm_bridge_remove);
>
> /**
> - * drm_bridge_attach - associate given bridge to our DRM device
> + * drm_bridge_attach - attach the bridge to an encoder's chain
> *
> - * @dev: DRM device
> - * @bridge: bridge control structure
> + * @encoder: DRM encoder
> + * @bridge: bridge to attach
> + * @previous: previous bridge in the chain (optional)
> *
> - * Called by a kms driver to link one of our encoder/bridge to the given
> - * bridge.
> + * Called by a kms driver to link the bridge to an encoder's chain. The previous
> + * argument specifies the previous bridge in the chain. If NULL, the bridge is
> + * linked directly at the encoder's output. Otherwise it is linked at the
> + * previous bridge's output.
> *
> - * Note that setting up links between the bridge and our encoder/bridge
> - * objects needs to be handled by the kms driver itself.
> + * If non-NULL the previous bridge must be already attached by a call to this
> + * function.
> *
> * RETURNS:
> * Zero on success, error code on failure
> */
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous)
> {
> - if (!dev || !bridge)
> + int ret;
> +
> + if (!encoder || !bridge)
> + return -EINVAL;
> +
> + if (previous && (!previous->dev || previous->encoder != encoder))
> return -EINVAL;
>
> if (bridge->dev)
> return -EBUSY;
>
> - bridge->dev = dev;
> + bridge->dev = encoder->dev;
> + bridge->encoder = encoder;
> +
> + if (bridge->funcs->attach) {
> + ret = bridge->funcs->attach(bridge);
> + if (ret < 0) {
> + bridge->dev = NULL;
> + bridge->encoder = NULL;
> + return ret;
> + }
> + }
>
> - if (bridge->funcs->attach)
> - return bridge->funcs->attach(bridge);
> + if (previous)
> + previous->next = bridge;
> + else
> + encoder->bridge = bridge;
>
> return 0;
> }
> diff --git a/drivers/gpu/drm/drm_simple_kms_helper.c b/drivers/gpu/drm/drm_simple_kms_helper.c
> index 7bae08c2bf0a..ba7be6169339 100644
> --- a/drivers/gpu/drm/drm_simple_kms_helper.c
> +++ b/drivers/gpu/drm/drm_simple_kms_helper.c
> @@ -182,9 +182,7 @@ static const struct drm_plane_funcs drm_simple_kms_plane_funcs = {
> int drm_simple_display_pipe_attach_bridge(struct drm_simple_display_pipe *pipe,
> struct drm_bridge *bridge)
> {
> - bridge->encoder = &pipe->encoder;
> - pipe->encoder.bridge = bridge;
> - return drm_bridge_attach(pipe->encoder.dev, bridge);
> + return drm_bridge_attach(&pipe->encoder, bridge, NULL);
> }
> EXPORT_SYMBOL(drm_simple_display_pipe_attach_bridge);
>
> diff --git a/drivers/gpu/drm/exynos/exynos_dp.c b/drivers/gpu/drm/exynos/exynos_dp.c
> index 528229faffe4..1ef0be338b85 100644
> --- a/drivers/gpu/drm/exynos/exynos_dp.c
> +++ b/drivers/gpu/drm/exynos/exynos_dp.c
> @@ -99,7 +99,6 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
> struct drm_connector *connector)
> {
> struct exynos_dp_device *dp = to_dp(plat_data);
> - struct drm_encoder *encoder = &dp->encoder;
> int ret;
>
> drm_connector_register(connector);
> @@ -107,9 +106,7 @@ static int exynos_dp_bridge_attach(struct analogix_dp_plat_data *plat_data,
>
> /* Pre-empt DP connector creation if there's a bridge */
> if (dp->ptn_bridge) {
> - bridge->next = dp->ptn_bridge;
> - dp->ptn_bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, dp->ptn_bridge);
> + ret = drm_bridge_attach(&dp->encoder, dp->ptn_bridge, bridge);
> if (ret) {
> DRM_ERROR("Failed to attach bridge to drm\n");
> bridge->next = NULL;
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> index e07cb1fe4860..812e2ec0761d 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
> @@ -1718,10 +1718,8 @@ static int exynos_dsi_bind(struct device *dev, struct device *master,
> }
>
> bridge = of_drm_find_bridge(dsi->bridge_node);
> - if (bridge) {
> - encoder->bridge = bridge;
> - drm_bridge_attach(drm_dev, bridge);
> - }
> + if (bridge)
> + drm_bridge_attach(encoder, bridge, NULL);
>
> return mipi_dsi_host_register(&dsi->dsi_host);
> }
> diff --git a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> index e1dd75b18118..3ad76423c60d 100644
> --- a/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> +++ b/drivers/gpu/drm/fsl-dcu/fsl_dcu_drm_rgb.c
> @@ -167,10 +167,7 @@ static int fsl_dcu_attach_endpoint(struct fsl_dcu_drm_device *fsl_dev,
> if (!bridge)
> return -ENODEV;
>
> - fsl_dev->encoder.bridge = bridge;
> - bridge->encoder = &fsl_dev->encoder;
> -
> - return drm_bridge_attach(fsl_dev->drm, bridge);
> + return drm_bridge_attach(&fsl_dev->encoder, bridge, NULL);
> }
>
> int fsl_dcu_create_outputs(struct fsl_dcu_drm_device *fsl_dev)
> diff --git a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> index 998452ad0fcb..1737e98bc10a 100644
> --- a/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> +++ b/drivers/gpu/drm/hisilicon/kirin/dw_drm_dsi.c
> @@ -709,10 +709,7 @@ static int dsi_bridge_init(struct drm_device *dev, struct dw_dsi *dsi)
> int ret;
>
> /* associate the bridge to dsi encoder */
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> -
> - ret = drm_bridge_attach(dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> DRM_ERROR("failed to attach external bridge\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
> index b300998dce7d..2fcb579f5489 100644
> --- a/drivers/gpu/drm/imx/imx-ldb.c
> +++ b/drivers/gpu/drm/imx/imx-ldb.c
> @@ -461,10 +461,8 @@ static int imx_ldb_register(struct drm_device *drm,
> DRM_MODE_ENCODER_LVDS, NULL);
>
> if (imx_ldb_ch->bridge) {
> - imx_ldb_ch->bridge->encoder = encoder;
> -
> - imx_ldb_ch->encoder.bridge = imx_ldb_ch->bridge;
> - ret = drm_bridge_attach(drm, imx_ldb_ch->bridge);
> + ret = drm_bridge_attach(&imx_ldb_ch->encoder,
> + imx_ldb_ch->bridge, NULL);
> if (ret) {
> DRM_ERROR("Failed to initialize bridge with drm\n");
> return ret;
> diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
> index d796ada2a47a..2d80c769f56b 100644
> --- a/drivers/gpu/drm/imx/parallel-display.c
> +++ b/drivers/gpu/drm/imx/parallel-display.c
> @@ -198,9 +198,7 @@ static int imx_pd_register(struct drm_device *drm,
> drm_panel_attach(imxpd->panel, &imxpd->connector);
>
> if (imxpd->bridge) {
> - imxpd->bridge->encoder = encoder;
> - encoder->bridge = imxpd->bridge;
> - ret = drm_bridge_attach(drm, imxpd->bridge);
> + ret = drm_bridge_attach(encoder, imxpd->bridge, NULL);
> if (ret < 0) {
> dev_err(imxpd->dev, "failed to attach bridge: %d\n",
> ret);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dpi.c b/drivers/gpu/drm/mediatek/mtk_dpi.c
> index 0186e500d2a5..3cced1c522fd 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dpi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dpi.c
> @@ -63,6 +63,7 @@ enum mtk_dpi_out_color_format {
> struct mtk_dpi {
> struct mtk_ddp_comp ddp_comp;
> struct drm_encoder encoder;
> + struct drm_bridge *bridge;
> void __iomem *regs;
> struct device *dev;
> struct clk *engine_clk;
> @@ -615,8 +616,7 @@ static int mtk_dpi_bind(struct device *dev, struct device *master, void *data)
> /* Currently DPI0 is fixed to be driven by OVL1 */
> dpi->encoder.possible_crtcs = BIT(1);
>
> - dpi->encoder.bridge->encoder = &dpi->encoder;
> - ret = drm_bridge_attach(dpi->encoder.dev, dpi->encoder.bridge);
> + ret = drm_bridge_attach(&dpi->encoder, dpi->bridge, NULL);
> if (ret) {
> dev_err(dev, "Failed to attach bridge: %d\n", ret);
> goto err_cleanup;
> @@ -713,9 +713,9 @@ static int mtk_dpi_probe(struct platform_device *pdev)
>
> dev_info(dev, "Found bridge node: %s\n", bridge_node->full_name);
>
> - dpi->encoder.bridge = of_drm_find_bridge(bridge_node);
> + dpi->bridge = of_drm_find_bridge(bridge_node);
> of_node_put(bridge_node);
> - if (!dpi->encoder.bridge)
> + if (!dpi->bridge)
> return -EPROBE_DEFER;
>
> comp_id = mtk_ddp_comp_get_id(dev->of_node, MTK_DPI);
> diff --git a/drivers/gpu/drm/mediatek/mtk_dsi.c b/drivers/gpu/drm/mediatek/mtk_dsi.c
> index 28b2044ed9f2..2ac0f1abba86 100644
> --- a/drivers/gpu/drm/mediatek/mtk_dsi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_dsi.c
> @@ -597,26 +597,6 @@ static const struct drm_connector_helper_funcs
> .get_modes = mtk_dsi_connector_get_modes,
> };
>
> -static int mtk_drm_attach_bridge(struct drm_bridge *bridge,
> - struct drm_encoder *encoder)
> -{
> - int ret;
> -
> - if (!bridge)
> - return -ENOENT;
> -
> - encoder->bridge = bridge;
> - bridge->encoder = encoder;
> - ret = drm_bridge_attach(encoder->dev, bridge);
> - if (ret) {
> - DRM_ERROR("Failed to attach bridge to drm\n");
> - encoder->bridge = NULL;
> - bridge->encoder = NULL;
> - }
> -
> - return ret;
> -}
> -
> static int mtk_dsi_create_connector(struct drm_device *drm, struct mtk_dsi *dsi)
> {
> int ret;
> @@ -667,8 +647,10 @@ static int mtk_dsi_create_conn_enc(struct drm_device *drm, struct mtk_dsi *dsi)
> dsi->encoder.possible_crtcs = 1;
>
> /* If there's a bridge, attach to it and let it create the connector */
> - ret = mtk_drm_attach_bridge(dsi->bridge, &dsi->encoder);
> + ret = drm_bridge_attach(&dsi->encoder, dsi->bridge, NULL);
> if (ret) {
> + DRM_ERROR("Failed to attach bridge to drm\n");
> +
> /* Otherwise create our own connector and attach to a panel */
> ret = mtk_dsi_create_connector(drm, dsi);
> if (ret)
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 71227deef21b..5ca1b0fbf937 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -149,6 +149,7 @@ struct hdmi_audio_param {
>
> struct mtk_hdmi {
> struct drm_bridge bridge;
> + struct drm_bridge *next_bridge;
> struct drm_connector conn;
> struct device *dev;
> struct phy *phy;
> @@ -1320,9 +1321,9 @@ static int mtk_hdmi_bridge_attach(struct drm_bridge *bridge)
> return ret;
> }
>
> - if (bridge->next) {
> - bridge->next->encoder = bridge->encoder;
> - ret = drm_bridge_attach(bridge->encoder->dev, bridge->next);
> + if (hdmi->next_bridge) {
> + ret = drm_bridge_attach(bridge->encoder, hdmi->next_bridge,
> + bridge);
> if (ret) {
> dev_err(hdmi->dev,
> "Failed to attach external bridge: %d\n", ret);
> @@ -1505,8 +1506,8 @@ static int mtk_hdmi_dt_parse_pdata(struct mtk_hdmi *hdmi,
> of_node_put(ep);
>
> if (!of_device_is_compatible(remote, "hdmi-connector")) {
> - hdmi->bridge.next = of_drm_find_bridge(remote);
> - if (!hdmi->bridge.next) {
> + hdmi->next_bridge = of_drm_find_bridge(remote);
> + if (!hdmi->next_bridge) {
> dev_err(dev, "Waiting for external bridge\n");
> of_node_put(remote);
> return -EPROBE_DEFER;
> diff --git a/drivers/gpu/drm/msm/dsi/dsi_manager.c b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> index c8d1f19c9a6d..2bd8dad76105 100644
> --- a/drivers/gpu/drm/msm/dsi/dsi_manager.c
> +++ b/drivers/gpu/drm/msm/dsi/dsi_manager.c
> @@ -579,6 +579,7 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
> struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
> struct drm_bridge *bridge = NULL;
> struct dsi_bridge *dsi_bridge;
> + struct drm_encoder *encoder;
> int ret;
>
> dsi_bridge = devm_kzalloc(msm_dsi->dev->dev,
> @@ -590,10 +591,18 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id)
>
> dsi_bridge->id = id;
>
> + /*
> + * HACK: we may not know the external DSI bridge device's mode
> + * flags here. We'll get to know them only when the device
> + * attaches to the dsi host. For now, assume the bridge supports
> + * DSI video mode
> + */
> + encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
> +
> bridge = &dsi_bridge->base;
> bridge->funcs = &dsi_mgr_bridge_funcs;
>
> - ret = drm_bridge_attach(msm_dsi->dev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> @@ -628,11 +637,7 @@ struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id)
> encoder = msm_dsi->encoders[MSM_DSI_VIDEO_ENCODER_ID];
>
> /* link the internal dsi bridge to the external bridge */
> - int_bridge->next = ext_bridge;
> - /* set the external bridge's encoder as dsi's encoder */
> - ext_bridge->encoder = encoder;
> -
> - drm_bridge_attach(dev, ext_bridge);
> + drm_bridge_attach(encoder, ext_bridge, int_bridge);
>
> /*
> * we need the drm_connector created by the external bridge
> diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
> index 2bc73f82f3f5..931a5c97cccf 100644
> --- a/drivers/gpu/drm/msm/edp/edp_bridge.c
> +++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
> @@ -106,7 +106,7 @@ struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
> bridge = &edp_bridge->base;
> bridge->funcs = &edp_bridge_funcs;
>
> - ret = drm_bridge_attach(edp->dev, bridge);
> + ret = drm_bridge_attach(edp->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> index bacbd5d8df0e..4e6d1bf27474 100644
> --- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> +++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
> @@ -227,7 +227,7 @@ struct drm_bridge *msm_hdmi_bridge_init(struct hdmi *hdmi)
> bridge = &hdmi_bridge->base;
> bridge->funcs = &msm_hdmi_bridge_funcs;
>
> - ret = drm_bridge_attach(hdmi->dev, bridge);
> + ret = drm_bridge_attach(hdmi->encoder, bridge, NULL);
> if (ret)
> goto fail;
>
> diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> index a1a2c5e7822c..933a2547798e 100644
> --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
> @@ -124,10 +124,7 @@ int rcar_du_hdmienc_init(struct rcar_du_device *rcdu,
> hdmienc->renc = renc;
>
> /* Link the bridge to the encoder. */
> - bridge->encoder = encoder;
> - encoder->bridge = bridge;
> -
> - ret = drm_bridge_attach(rcdu->ddev, bridge);
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> drm_encoder_cleanup(encoder);
> return ret;
> diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
> index e8c1ed08a9f7..411dc6ec976e 100644
> --- a/drivers/gpu/drm/sti/sti_dvo.c
> +++ b/drivers/gpu/drm/sti/sti_dvo.c
> @@ -478,14 +478,13 @@ static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
> return err;
> }
>
> - err = drm_bridge_attach(drm_dev, bridge);
> + err = drm_bridge_attach(encoder, bridge, NULL);
> if (err) {
> DRM_ERROR("Failed to attach bridge\n");
> return err;
> }
>
> dvo->bridge = bridge;
> - encoder->bridge = bridge;
> connector->encoder = encoder;
> dvo->encoder = encoder;
>
> diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
> index e7c243f70870..5b1855e44f87 100644
> --- a/drivers/gpu/drm/sti/sti_hda.c
> +++ b/drivers/gpu/drm/sti/sti_hda.c
> @@ -714,9 +714,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hda;
> bridge->funcs = &sti_hda_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
> index 376b0763c874..f0af1ae82ee9 100644
> --- a/drivers/gpu/drm/sti/sti_hdmi.c
> +++ b/drivers/gpu/drm/sti/sti_hdmi.c
> @@ -1308,9 +1308,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
>
> bridge->driver_private = hdmi;
> bridge->funcs = &sti_hdmi_bridge_funcs;
> - drm_bridge_attach(drm_dev, bridge);
> + drm_bridge_attach(encoder, bridge, NULL);
>
> - encoder->bridge = bridge;
> connector->encoder = encoder;
>
> drm_connector = (struct drm_connector *)connector;
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f559cc..ce071c17134b 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -219,6 +219,7 @@ int sun4i_rgb_init(struct drm_device *drm)
> struct sun4i_drv *drv = drm->dev_private;
> struct sun4i_tcon *tcon = drv->tcon;
> struct drm_encoder *encoder;
> + struct drm_bridge *bridge;
> struct sun4i_rgb *rgb;
> int ret;
>
> @@ -229,8 +230,8 @@ int sun4i_rgb_init(struct drm_device *drm)
> encoder = &rgb->encoder;
>
> tcon->panel = sun4i_tcon_find_panel(tcon->dev->of_node);
> - encoder->bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> - if (IS_ERR(tcon->panel) && IS_ERR(encoder->bridge)) {
> + bridge = sun4i_tcon_find_bridge(tcon->dev->of_node);
> + if (IS_ERR(tcon->panel) && IS_ERR(bridge)) {
> dev_info(drm->dev, "No panel or bridge found... RGB output disabled\n");
> return 0;
> }
> @@ -271,16 +272,12 @@ int sun4i_rgb_init(struct drm_device *drm)
> }
> }
>
> - if (!IS_ERR(encoder->bridge)) {
> - encoder->bridge->encoder = &rgb->encoder;
> -
> - ret = drm_bridge_attach(drm, encoder->bridge);
> + if (!IS_ERR(bridge)) {
> + ret = drm_bridge_attach(encoder, bridge, NULL);
> if (ret) {
> dev_err(drm->dev, "Couldn't attach our bridge\n");
> goto err_cleanup_connector;
> }
> - } else {
> - encoder->bridge = NULL;
> }
>
> return 0;
> diff --git a/include/drm/drm_bridge.h b/include/drm/drm_bridge.h
> index 530a1d6e8cde..94e5ee96b3b5 100644
> --- a/include/drm/drm_bridge.h
> +++ b/include/drm/drm_bridge.h
> @@ -201,7 +201,8 @@ struct drm_bridge {
> int drm_bridge_add(struct drm_bridge *bridge);
> void drm_bridge_remove(struct drm_bridge *bridge);
> struct drm_bridge *of_drm_find_bridge(struct device_node *np);
> -int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge);
> +int drm_bridge_attach(struct drm_encoder *encoder, struct drm_bridge *bridge,
> + struct drm_bridge *previous);
> void drm_bridge_detach(struct drm_bridge *bridge);
>
> bool drm_bridge_mode_fixup(struct drm_bridge *bridge,
> --
> Regards,
>
> Laurent Pinchart
>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 100+ messages in thread