All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] drm/arm/hdlcd: Attach the output bridge directly
       [not found] <CGME20261020130022eucas1p2564adcaa74eea27cb4b88164b385b184@eucas1p2.samsung.com>
@ 2026-10-20 13:00 ` Marek Szyprowski
  2026-10-21 12:36   ` Liviu Dudau
  2026-10-23 12:57   ` Liviu Dudau
  0 siblings, 2 replies; 3+ messages in thread
From: Marek Szyprowski @ 2026-10-20 13:00 UTC (permalink / raw)
  To: dri-devel
  Cc: Marek Szyprowski, Liviu Dudau, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Luca Ceresoli,
	Kory Maincent

Since commit d700fd0ff100 ("drm/bridge: tda998x: Remove component
support") the TDA998x driver no longer registers itself as a component,
so the HDLCD component master never gets bound and the display stays
dead on Juno board.

Drop the component framework and get the output bridge with
devm_drm_of_get_bridge() at probe time, deferring until it becomes
available. Create the encoder in the HDLCD driver, attach the bridge
with DRM_BRIDGE_ATTACH_NO_CONNECTOR and use drm_bridge_connector for
the connector, like tilcdc does since the TDA998x component support
removal.

This also makes HDLCD work with any DRM bridge, not only TDA998x.

As a side effect, interlaced modes are no longer exposed on the HDMI
connector. The connector created by TDA998x itself always allowed them,
while drm_bridge_connector only allows them when all bridges in the
chain set interlace_allowed, which TDA998x does not. HDLCD has no
interlaced scanout support, so these modes were not usable anyway.

Fixes: d700fd0ff100 ("drm/bridge: tda998x: Remove component support")
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
---
This patch has been developed with LLM assistance, but the results has
been tested on the real Juno R1 board (juno-r1-scmi.dtb) with HDMI
monitor.

Bst regards
Marek Szyprowski, PhD
Samsung R&D Institute Poland
---
 drivers/gpu/drm/arm/Kconfig     |  4 +-
 drivers/gpu/drm/arm/hdlcd_drv.c | 85 +++++++++++++++------------------
 drivers/gpu/drm/arm/hdlcd_drv.h |  1 +
 3 files changed, 42 insertions(+), 48 deletions(-)

diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
index ed3ed617c688..6dcc063aa503 100644
--- a/drivers/gpu/drm/arm/Kconfig
+++ b/drivers/gpu/drm/arm/Kconfig
@@ -9,7 +9,9 @@ config DRM_HDLCD
 	select DRM_CLIENT_SELECTION
 	select DRM_KMS_HELPER
 	select DRM_GEM_DMA_HELPER
-	select DRM_BRIDGE # for TDA998x
+	select DRM_BRIDGE
+	select DRM_BRIDGE_CONNECTOR
+	select DRM_DISPLAY_HELPER
 	help
 	  Choose this option if you have an ARM High Definition Colour LCD
 	  controller.
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
index 81d45f2dd6a7..340b1bb38bf9 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.c
+++ b/drivers/gpu/drm/arm/hdlcd_drv.c
@@ -13,17 +13,17 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/clk.h>
-#include <linux/component.h>
 #include <linux/console.h>
 #include <linux/dma-mapping.h>
 #include <linux/list.h>
-#include <linux/of_graph.h>
 #include <linux/of_reserved_mem.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
 #include <drm/clients/drm_client_setup.h>
 #include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
 #include <drm/drm_crtc.h>
 #include <drm/drm_debugfs.h>
 #include <drm/drm_drv.h>
@@ -238,12 +238,43 @@ static const struct drm_driver hdlcd_driver = {
 	.minor = 0,
 };
 
-static int hdlcd_drm_bind(struct device *dev)
+static int hdlcd_attach_bridge(struct drm_device *drm, struct drm_bridge *bridge)
 {
+	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
+	struct drm_connector *connector;
+	int ret;
+
+	ret = drmm_encoder_init(drm, &hdlcd->encoder, NULL,
+				DRM_MODE_ENCODER_NONE, NULL);
+	if (ret)
+		return ret;
+
+	hdlcd->encoder.possible_crtcs = drm_crtc_mask(&hdlcd->crtc);
+
+	ret = drm_bridge_attach(&hdlcd->encoder, bridge, NULL,
+				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
+	if (ret)
+		return ret;
+
+	connector = drm_bridge_connector_init(drm, &hdlcd->encoder);
+
+	return PTR_ERR_OR_ZERO(connector);
+}
+
+static int hdlcd_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
 	struct drm_device *drm;
 	struct hdlcd_drm_private *hdlcd;
+	struct drm_bridge *bridge;
 	int ret;
 
+	/* there is only one output port inside each device, find its bridge */
+	bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
+	if (IS_ERR(bridge))
+		return dev_err_probe(dev, PTR_ERR(bridge),
+				     "failed to find output bridge\n");
+
 	hdlcd = devm_drm_dev_alloc(dev, &hdlcd_driver, typeof(*hdlcd), base);
 	if (IS_ERR(hdlcd))
 		return PTR_ERR(hdlcd);
@@ -260,12 +291,9 @@ static int hdlcd_drm_bind(struct device *dev)
 	if (ret)
 		goto err_free;
 
-	/* Set the CRTC's port so that the encoder component can find it */
-	hdlcd->crtc.port = of_graph_get_port_by_id(dev->of_node, 0);
-
-	ret = component_bind_all(dev, drm);
+	ret = hdlcd_attach_bridge(drm, bridge);
 	if (ret) {
-		DRM_ERROR("Failed to bind all components\n");
+		DRM_ERROR("failed to attach bridge\n");
 		goto err_unload;
 	}
 
@@ -311,10 +339,7 @@ static int hdlcd_drm_bind(struct device *dev)
 	pm_runtime_disable(drm->dev);
 err_pm_active:
 	drm_atomic_helper_shutdown(drm);
-	component_unbind_all(dev, drm);
 err_unload:
-	of_node_put(hdlcd->crtc.port);
-	hdlcd->crtc.port = NULL;
 	hdlcd_irq_uninstall(hdlcd);
 	of_reserved_mem_device_release(drm->dev);
 err_free:
@@ -322,16 +347,14 @@ static int hdlcd_drm_bind(struct device *dev)
 	return ret;
 }
 
-static void hdlcd_drm_unbind(struct device *dev)
+static void hdlcd_remove(struct platform_device *pdev)
 {
+	struct device *dev = &pdev->dev;
 	struct drm_device *drm = dev_get_drvdata(dev);
 	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
 
 	drm_dev_unregister(drm);
 	drm_kms_helper_poll_fini(drm);
-	component_unbind_all(dev, drm);
-	of_node_put(hdlcd->crtc.port);
-	hdlcd->crtc.port = NULL;
 	pm_runtime_get_sync(dev);
 	drm_atomic_helper_shutdown(drm);
 	hdlcd_irq_uninstall(hdlcd);
@@ -342,38 +365,6 @@ static void hdlcd_drm_unbind(struct device *dev)
 	dev_set_drvdata(dev, NULL);
 }
 
-static const struct component_master_ops hdlcd_master_ops = {
-	.bind		= hdlcd_drm_bind,
-	.unbind		= hdlcd_drm_unbind,
-};
-
-static int compare_dev(struct device *dev, void *data)
-{
-	return dev->of_node == data;
-}
-
-static int hdlcd_probe(struct platform_device *pdev)
-{
-	struct device_node *port;
-	struct component_match *match = NULL;
-
-	/* there is only one output port inside each device, find it */
-	port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0);
-	if (!port)
-		return -ENODEV;
-
-	drm_of_component_match_add(&pdev->dev, &match, compare_dev, port);
-	of_node_put(port);
-
-	return component_master_add_with_match(&pdev->dev, &hdlcd_master_ops,
-					       match);
-}
-
-static void hdlcd_remove(struct platform_device *pdev)
-{
-	component_master_del(&pdev->dev, &hdlcd_master_ops);
-}
-
 static void hdlcd_shutdown(struct platform_device *pdev)
 {
 	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
index f1c1da2ac2db..6fb48727e54e 100644
--- a/drivers/gpu/drm/arm/hdlcd_drv.h
+++ b/drivers/gpu/drm/arm/hdlcd_drv.h
@@ -11,6 +11,7 @@ struct hdlcd_drm_private {
 	void __iomem			*mmio;
 	struct clk			*clk;
 	struct drm_crtc			crtc;
+	struct drm_encoder		encoder;
 	struct drm_plane		*plane;
 	unsigned int			irq;
 #ifdef CONFIG_DEBUG_FS
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/arm/hdlcd: Attach the output bridge directly
  2026-10-20 13:00 ` [PATCH] drm/arm/hdlcd: Attach the output bridge directly Marek Szyprowski
@ 2026-10-21 12:36   ` Liviu Dudau
  2026-10-23 12:57   ` Liviu Dudau
  1 sibling, 0 replies; 3+ messages in thread
From: Liviu Dudau @ 2026-10-21 12:36 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: dri-devel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Luca Ceresoli, Kory Maincent

On Tue, Oct 20, 2026 at 03:00:07PM +0200, Marek Szyprowski wrote:
> Since commit d700fd0ff100 ("drm/bridge: tda998x: Remove component
> support") the TDA998x driver no longer registers itself as a component,
> so the HDLCD component master never gets bound and the display stays
> dead on Juno board.

I've missed that tda998x is no longer doing component. I think I had
an earlier fix for malidp as there was interest to use it with bridges
other than TDA998x, but I've thought the driver for the bridge is now
frozen.

> 
> Drop the component framework and get the output bridge with
> devm_drm_of_get_bridge() at probe time, deferring until it becomes
> available. Create the encoder in the HDLCD driver, attach the bridge
> with DRM_BRIDGE_ATTACH_NO_CONNECTOR and use drm_bridge_connector for
> the connector, like tilcdc does since the TDA998x component support
> removal.
> 
> This also makes HDLCD work with any DRM bridge, not only TDA998x.
> 
> As a side effect, interlaced modes are no longer exposed on the HDMI
> connector. The connector created by TDA998x itself always allowed them,
> while drm_bridge_connector only allows them when all bridges in the
> chain set interlace_allowed, which TDA998x does not. HDLCD has no
> interlaced scanout support, so these modes were not usable anyway.
> 
> Fixes: d700fd0ff100 ("drm/bridge: tda998x: Remove component support")
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Thanks for the fix!


Reviewed-by: Liviu Dudau <liviu.dudau@arm.com>

Best regards,
Liviu

> ---
> This patch has been developed with LLM assistance, but the results has
> been tested on the real Juno R1 board (juno-r1-scmi.dtb) with HDMI
> monitor.
> 
> Bst regards
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
> ---
>  drivers/gpu/drm/arm/Kconfig     |  4 +-
>  drivers/gpu/drm/arm/hdlcd_drv.c | 85 +++++++++++++++------------------
>  drivers/gpu/drm/arm/hdlcd_drv.h |  1 +
>  3 files changed, 42 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index ed3ed617c688..6dcc063aa503 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -9,7 +9,9 @@ config DRM_HDLCD
>  	select DRM_CLIENT_SELECTION
>  	select DRM_KMS_HELPER
>  	select DRM_GEM_DMA_HELPER
> -	select DRM_BRIDGE # for TDA998x
> +	select DRM_BRIDGE
> +	select DRM_BRIDGE_CONNECTOR
> +	select DRM_DISPLAY_HELPER
>  	help
>  	  Choose this option if you have an ARM High Definition Colour LCD
>  	  controller.
> diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
> index 81d45f2dd6a7..340b1bb38bf9 100644
> --- a/drivers/gpu/drm/arm/hdlcd_drv.c
> +++ b/drivers/gpu/drm/arm/hdlcd_drv.c
> @@ -13,17 +13,17 @@
>  #include <linux/module.h>
>  #include <linux/spinlock.h>
>  #include <linux/clk.h>
> -#include <linux/component.h>
>  #include <linux/console.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/list.h>
> -#include <linux/of_graph.h>
>  #include <linux/of_reserved_mem.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  
>  #include <drm/clients/drm_client_setup.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_bridge_connector.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_drv.h>
> @@ -238,12 +238,43 @@ static const struct drm_driver hdlcd_driver = {
>  	.minor = 0,
>  };
>  
> -static int hdlcd_drm_bind(struct device *dev)
> +static int hdlcd_attach_bridge(struct drm_device *drm, struct drm_bridge *bridge)
>  {
> +	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
> +	struct drm_connector *connector;
> +	int ret;
> +
> +	ret = drmm_encoder_init(drm, &hdlcd->encoder, NULL,
> +				DRM_MODE_ENCODER_NONE, NULL);
> +	if (ret)
> +		return ret;
> +
> +	hdlcd->encoder.possible_crtcs = drm_crtc_mask(&hdlcd->crtc);
> +
> +	ret = drm_bridge_attach(&hdlcd->encoder, bridge, NULL,
> +				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +	if (ret)
> +		return ret;
> +
> +	connector = drm_bridge_connector_init(drm, &hdlcd->encoder);
> +
> +	return PTR_ERR_OR_ZERO(connector);
> +}
> +
> +static int hdlcd_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
>  	struct drm_device *drm;
>  	struct hdlcd_drm_private *hdlcd;
> +	struct drm_bridge *bridge;
>  	int ret;
>  
> +	/* there is only one output port inside each device, find its bridge */
> +	bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
> +	if (IS_ERR(bridge))
> +		return dev_err_probe(dev, PTR_ERR(bridge),
> +				     "failed to find output bridge\n");
> +
>  	hdlcd = devm_drm_dev_alloc(dev, &hdlcd_driver, typeof(*hdlcd), base);
>  	if (IS_ERR(hdlcd))
>  		return PTR_ERR(hdlcd);
> @@ -260,12 +291,9 @@ static int hdlcd_drm_bind(struct device *dev)
>  	if (ret)
>  		goto err_free;
>  
> -	/* Set the CRTC's port so that the encoder component can find it */
> -	hdlcd->crtc.port = of_graph_get_port_by_id(dev->of_node, 0);
> -
> -	ret = component_bind_all(dev, drm);
> +	ret = hdlcd_attach_bridge(drm, bridge);
>  	if (ret) {
> -		DRM_ERROR("Failed to bind all components\n");
> +		DRM_ERROR("failed to attach bridge\n");
>  		goto err_unload;
>  	}
>  
> @@ -311,10 +339,7 @@ static int hdlcd_drm_bind(struct device *dev)
>  	pm_runtime_disable(drm->dev);
>  err_pm_active:
>  	drm_atomic_helper_shutdown(drm);
> -	component_unbind_all(dev, drm);
>  err_unload:
> -	of_node_put(hdlcd->crtc.port);
> -	hdlcd->crtc.port = NULL;
>  	hdlcd_irq_uninstall(hdlcd);
>  	of_reserved_mem_device_release(drm->dev);
>  err_free:
> @@ -322,16 +347,14 @@ static int hdlcd_drm_bind(struct device *dev)
>  	return ret;
>  }
>  
> -static void hdlcd_drm_unbind(struct device *dev)
> +static void hdlcd_remove(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
>  	struct drm_device *drm = dev_get_drvdata(dev);
>  	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
>  
>  	drm_dev_unregister(drm);
>  	drm_kms_helper_poll_fini(drm);
> -	component_unbind_all(dev, drm);
> -	of_node_put(hdlcd->crtc.port);
> -	hdlcd->crtc.port = NULL;
>  	pm_runtime_get_sync(dev);
>  	drm_atomic_helper_shutdown(drm);
>  	hdlcd_irq_uninstall(hdlcd);
> @@ -342,38 +365,6 @@ static void hdlcd_drm_unbind(struct device *dev)
>  	dev_set_drvdata(dev, NULL);
>  }
>  
> -static const struct component_master_ops hdlcd_master_ops = {
> -	.bind		= hdlcd_drm_bind,
> -	.unbind		= hdlcd_drm_unbind,
> -};
> -
> -static int compare_dev(struct device *dev, void *data)
> -{
> -	return dev->of_node == data;
> -}
> -
> -static int hdlcd_probe(struct platform_device *pdev)
> -{
> -	struct device_node *port;
> -	struct component_match *match = NULL;
> -
> -	/* there is only one output port inside each device, find it */
> -	port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0);
> -	if (!port)
> -		return -ENODEV;
> -
> -	drm_of_component_match_add(&pdev->dev, &match, compare_dev, port);
> -	of_node_put(port);
> -
> -	return component_master_add_with_match(&pdev->dev, &hdlcd_master_ops,
> -					       match);
> -}
> -
> -static void hdlcd_remove(struct platform_device *pdev)
> -{
> -	component_master_del(&pdev->dev, &hdlcd_master_ops);
> -}
> -
>  static void hdlcd_shutdown(struct platform_device *pdev)
>  {
>  	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
> diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
> index f1c1da2ac2db..6fb48727e54e 100644
> --- a/drivers/gpu/drm/arm/hdlcd_drv.h
> +++ b/drivers/gpu/drm/arm/hdlcd_drv.h
> @@ -11,6 +11,7 @@ struct hdlcd_drm_private {
>  	void __iomem			*mmio;
>  	struct clk			*clk;
>  	struct drm_crtc			crtc;
> +	struct drm_encoder		encoder;
>  	struct drm_plane		*plane;
>  	unsigned int			irq;
>  #ifdef CONFIG_DEBUG_FS
> -- 
> 2.43.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] drm/arm/hdlcd: Attach the output bridge directly
  2026-10-20 13:00 ` [PATCH] drm/arm/hdlcd: Attach the output bridge directly Marek Szyprowski
  2026-10-21 12:36   ` Liviu Dudau
@ 2026-10-23 12:57   ` Liviu Dudau
  1 sibling, 0 replies; 3+ messages in thread
From: Liviu Dudau @ 2026-10-23 12:57 UTC (permalink / raw)
  To: Marek Szyprowski
  Cc: dri-devel, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Luca Ceresoli, Kory Maincent

On Tue, Oct 20, 2026 at 03:00:07PM +0200, Marek Szyprowski wrote:
> Since commit d700fd0ff100 ("drm/bridge: tda998x: Remove component
> support") the TDA998x driver no longer registers itself as a component,
> so the HDLCD component master never gets bound and the display stays
> dead on Juno board.
> 
> Drop the component framework and get the output bridge with
> devm_drm_of_get_bridge() at probe time, deferring until it becomes
> available. Create the encoder in the HDLCD driver, attach the bridge
> with DRM_BRIDGE_ATTACH_NO_CONNECTOR and use drm_bridge_connector for
> the connector, like tilcdc does since the TDA998x component support
> removal.
> 
> This also makes HDLCD work with any DRM bridge, not only TDA998x.
> 
> As a side effect, interlaced modes are no longer exposed on the HDMI
> connector. The connector created by TDA998x itself always allowed them,
> while drm_bridge_connector only allows them when all bridges in the
> chain set interlace_allowed, which TDA998x does not. HDLCD has no
> interlaced scanout support, so these modes were not usable anyway.
> 
> Fixes: d700fd0ff100 ("drm/bridge: tda998x: Remove component support")
> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>

Pushed to drm-misc-next.

Best regards,
Liviu


> ---
> This patch has been developed with LLM assistance, but the results has
> been tested on the real Juno R1 board (juno-r1-scmi.dtb) with HDMI
> monitor.
> 
> Bst regards
> Marek Szyprowski, PhD
> Samsung R&D Institute Poland
> ---
>  drivers/gpu/drm/arm/Kconfig     |  4 +-
>  drivers/gpu/drm/arm/hdlcd_drv.c | 85 +++++++++++++++------------------
>  drivers/gpu/drm/arm/hdlcd_drv.h |  1 +
>  3 files changed, 42 insertions(+), 48 deletions(-)
> 
> diff --git a/drivers/gpu/drm/arm/Kconfig b/drivers/gpu/drm/arm/Kconfig
> index ed3ed617c688..6dcc063aa503 100644
> --- a/drivers/gpu/drm/arm/Kconfig
> +++ b/drivers/gpu/drm/arm/Kconfig
> @@ -9,7 +9,9 @@ config DRM_HDLCD
>  	select DRM_CLIENT_SELECTION
>  	select DRM_KMS_HELPER
>  	select DRM_GEM_DMA_HELPER
> -	select DRM_BRIDGE # for TDA998x
> +	select DRM_BRIDGE
> +	select DRM_BRIDGE_CONNECTOR
> +	select DRM_DISPLAY_HELPER
>  	help
>  	  Choose this option if you have an ARM High Definition Colour LCD
>  	  controller.
> diff --git a/drivers/gpu/drm/arm/hdlcd_drv.c b/drivers/gpu/drm/arm/hdlcd_drv.c
> index 81d45f2dd6a7..340b1bb38bf9 100644
> --- a/drivers/gpu/drm/arm/hdlcd_drv.c
> +++ b/drivers/gpu/drm/arm/hdlcd_drv.c
> @@ -13,17 +13,17 @@
>  #include <linux/module.h>
>  #include <linux/spinlock.h>
>  #include <linux/clk.h>
> -#include <linux/component.h>
>  #include <linux/console.h>
>  #include <linux/dma-mapping.h>
>  #include <linux/list.h>
> -#include <linux/of_graph.h>
>  #include <linux/of_reserved_mem.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
>  
>  #include <drm/clients/drm_client_setup.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_bridge.h>
> +#include <drm/drm_bridge_connector.h>
>  #include <drm/drm_crtc.h>
>  #include <drm/drm_debugfs.h>
>  #include <drm/drm_drv.h>
> @@ -238,12 +238,43 @@ static const struct drm_driver hdlcd_driver = {
>  	.minor = 0,
>  };
>  
> -static int hdlcd_drm_bind(struct device *dev)
> +static int hdlcd_attach_bridge(struct drm_device *drm, struct drm_bridge *bridge)
>  {
> +	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
> +	struct drm_connector *connector;
> +	int ret;
> +
> +	ret = drmm_encoder_init(drm, &hdlcd->encoder, NULL,
> +				DRM_MODE_ENCODER_NONE, NULL);
> +	if (ret)
> +		return ret;
> +
> +	hdlcd->encoder.possible_crtcs = drm_crtc_mask(&hdlcd->crtc);
> +
> +	ret = drm_bridge_attach(&hdlcd->encoder, bridge, NULL,
> +				DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> +	if (ret)
> +		return ret;
> +
> +	connector = drm_bridge_connector_init(drm, &hdlcd->encoder);
> +
> +	return PTR_ERR_OR_ZERO(connector);
> +}
> +
> +static int hdlcd_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
>  	struct drm_device *drm;
>  	struct hdlcd_drm_private *hdlcd;
> +	struct drm_bridge *bridge;
>  	int ret;
>  
> +	/* there is only one output port inside each device, find its bridge */
> +	bridge = devm_drm_of_get_bridge(dev, dev->of_node, 0, 0);
> +	if (IS_ERR(bridge))
> +		return dev_err_probe(dev, PTR_ERR(bridge),
> +				     "failed to find output bridge\n");
> +
>  	hdlcd = devm_drm_dev_alloc(dev, &hdlcd_driver, typeof(*hdlcd), base);
>  	if (IS_ERR(hdlcd))
>  		return PTR_ERR(hdlcd);
> @@ -260,12 +291,9 @@ static int hdlcd_drm_bind(struct device *dev)
>  	if (ret)
>  		goto err_free;
>  
> -	/* Set the CRTC's port so that the encoder component can find it */
> -	hdlcd->crtc.port = of_graph_get_port_by_id(dev->of_node, 0);
> -
> -	ret = component_bind_all(dev, drm);
> +	ret = hdlcd_attach_bridge(drm, bridge);
>  	if (ret) {
> -		DRM_ERROR("Failed to bind all components\n");
> +		DRM_ERROR("failed to attach bridge\n");
>  		goto err_unload;
>  	}
>  
> @@ -311,10 +339,7 @@ static int hdlcd_drm_bind(struct device *dev)
>  	pm_runtime_disable(drm->dev);
>  err_pm_active:
>  	drm_atomic_helper_shutdown(drm);
> -	component_unbind_all(dev, drm);
>  err_unload:
> -	of_node_put(hdlcd->crtc.port);
> -	hdlcd->crtc.port = NULL;
>  	hdlcd_irq_uninstall(hdlcd);
>  	of_reserved_mem_device_release(drm->dev);
>  err_free:
> @@ -322,16 +347,14 @@ static int hdlcd_drm_bind(struct device *dev)
>  	return ret;
>  }
>  
> -static void hdlcd_drm_unbind(struct device *dev)
> +static void hdlcd_remove(struct platform_device *pdev)
>  {
> +	struct device *dev = &pdev->dev;
>  	struct drm_device *drm = dev_get_drvdata(dev);
>  	struct hdlcd_drm_private *hdlcd = drm_to_hdlcd_priv(drm);
>  
>  	drm_dev_unregister(drm);
>  	drm_kms_helper_poll_fini(drm);
> -	component_unbind_all(dev, drm);
> -	of_node_put(hdlcd->crtc.port);
> -	hdlcd->crtc.port = NULL;
>  	pm_runtime_get_sync(dev);
>  	drm_atomic_helper_shutdown(drm);
>  	hdlcd_irq_uninstall(hdlcd);
> @@ -342,38 +365,6 @@ static void hdlcd_drm_unbind(struct device *dev)
>  	dev_set_drvdata(dev, NULL);
>  }
>  
> -static const struct component_master_ops hdlcd_master_ops = {
> -	.bind		= hdlcd_drm_bind,
> -	.unbind		= hdlcd_drm_unbind,
> -};
> -
> -static int compare_dev(struct device *dev, void *data)
> -{
> -	return dev->of_node == data;
> -}
> -
> -static int hdlcd_probe(struct platform_device *pdev)
> -{
> -	struct device_node *port;
> -	struct component_match *match = NULL;
> -
> -	/* there is only one output port inside each device, find it */
> -	port = of_graph_get_remote_node(pdev->dev.of_node, 0, 0);
> -	if (!port)
> -		return -ENODEV;
> -
> -	drm_of_component_match_add(&pdev->dev, &match, compare_dev, port);
> -	of_node_put(port);
> -
> -	return component_master_add_with_match(&pdev->dev, &hdlcd_master_ops,
> -					       match);
> -}
> -
> -static void hdlcd_remove(struct platform_device *pdev)
> -{
> -	component_master_del(&pdev->dev, &hdlcd_master_ops);
> -}
> -
>  static void hdlcd_shutdown(struct platform_device *pdev)
>  {
>  	drm_atomic_helper_shutdown(platform_get_drvdata(pdev));
> diff --git a/drivers/gpu/drm/arm/hdlcd_drv.h b/drivers/gpu/drm/arm/hdlcd_drv.h
> index f1c1da2ac2db..6fb48727e54e 100644
> --- a/drivers/gpu/drm/arm/hdlcd_drv.h
> +++ b/drivers/gpu/drm/arm/hdlcd_drv.h
> @@ -11,6 +11,7 @@ struct hdlcd_drm_private {
>  	void __iomem			*mmio;
>  	struct clk			*clk;
>  	struct drm_crtc			crtc;
> +	struct drm_encoder		encoder;
>  	struct drm_plane		*plane;
>  	unsigned int			irq;
>  #ifdef CONFIG_DEBUG_FS
> -- 
> 2.43.0
> 

-- 
====================
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2026-10-23 12:57 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <CGME20261020130022eucas1p2564adcaa74eea27cb4b88164b385b184@eucas1p2.samsung.com>
2026-10-20 13:00 ` [PATCH] drm/arm/hdlcd: Attach the output bridge directly Marek Szyprowski
2026-10-21 12:36   ` Liviu Dudau
2026-10-23 12:57   ` Liviu Dudau

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.