diff mbox

[3/7,v2] drm/pl111: Replace custom connector with panel bridge

Message ID 20170901093637.4041-4-linus.walleij@linaro.org (mailing list archive)
State New, archived
Headers show

Commit Message

Linus Walleij Sept. 1, 2017, 9:36 a.m. UTC
This replaces the custom connector in the PL111 with the
panel bridge helper.

This works nicely for all standard panels, but since there
are several PL11x-based systems that will need to use the dumb
VGA connector bridge we use drm_of_find_panel_or_bridge()
and make some headroom for dealing with bridges that are
not panels as well, and drop a TODO in the code.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
ChangeLog v1->v2:
- Remove the panel [un]prepare() and [en|dis]able() calls
  from the display driver, since this is now handled
  by the bridge.
---
 drivers/gpu/drm/pl111/Kconfig           |   3 +-
 drivers/gpu/drm/pl111/Makefile          |   3 +-
 drivers/gpu/drm/pl111/pl111_connector.c | 127 --------------------------------
 drivers/gpu/drm/pl111/pl111_display.c   |  16 ++--
 drivers/gpu/drm/pl111/pl111_drm.h       |  18 ++---
 drivers/gpu/drm/pl111/pl111_drv.c       |  62 +++++++++++-----
 6 files changed, 60 insertions(+), 169 deletions(-)
 delete mode 100644 drivers/gpu/drm/pl111/pl111_connector.c
diff mbox

Patch

diff --git a/drivers/gpu/drm/pl111/Kconfig b/drivers/gpu/drm/pl111/Kconfig
index bbfba87cd1a8..e5e2abd66491 100644
--- a/drivers/gpu/drm/pl111/Kconfig
+++ b/drivers/gpu/drm/pl111/Kconfig
@@ -6,7 +6,8 @@  config DRM_PL111
 	select DRM_KMS_HELPER
 	select DRM_KMS_CMA_HELPER
 	select DRM_GEM_CMA_HELPER
-	select DRM_PANEL
+	select DRM_BRIDGE
+	select DRM_PANEL_BRIDGE
 	select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
 	help
 	  Choose this option for DRM support for the PL111 CLCD controller.
diff --git a/drivers/gpu/drm/pl111/Makefile b/drivers/gpu/drm/pl111/Makefile
index 59483d610ef5..c5f8f9684848 100644
--- a/drivers/gpu/drm/pl111/Makefile
+++ b/drivers/gpu/drm/pl111/Makefile
@@ -1,5 +1,4 @@ 
-pl111_drm-y +=	pl111_connector.o \
-		pl111_display.o \
+pl111_drm-y +=	pl111_display.o \
 		pl111_drv.o
 
 pl111_drm-$(CONFIG_DEBUG_FS) += pl111_debugfs.o
diff --git a/drivers/gpu/drm/pl111/pl111_connector.c b/drivers/gpu/drm/pl111/pl111_connector.c
deleted file mode 100644
index 3f213d7e7692..000000000000
--- a/drivers/gpu/drm/pl111/pl111_connector.c
+++ /dev/null
@@ -1,127 +0,0 @@ 
-/*
- * (C) COPYRIGHT 2012-2013 ARM Limited. All rights reserved.
- *
- * Parts of this file were based on sources as follows:
- *
- * Copyright (c) 2006-2008 Intel Corporation
- * Copyright (c) 2007 Dave Airlie <airlied@linux.ie>
- * Copyright (C) 2011 Texas Instruments
- *
- * This program is free software and is provided to you under the terms of the
- * GNU General Public License version 2 as published by the Free Software
- * Foundation, and any use by you of this program is subject to the terms of
- * such GNU licence.
- *
- */
-
-/**
- * pl111_drm_connector.c
- * Implementation of the connector functions for PL111 DRM
- */
-#include <linux/amba/clcd-regs.h>
-#include <linux/version.h>
-#include <linux/shmem_fs.h>
-#include <linux/dma-buf.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_atomic_helper.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_of.h>
-#include <drm/drm_panel.h>
-
-#include "pl111_drm.h"
-
-static void pl111_connector_destroy(struct drm_connector *connector)
-{
-	struct pl111_drm_connector *pl111_connector =
-		to_pl111_connector(connector);
-
-	if (pl111_connector->panel)
-		drm_panel_detach(pl111_connector->panel);
-
-	drm_connector_unregister(connector);
-	drm_connector_cleanup(connector);
-}
-
-static enum drm_connector_status pl111_connector_detect(struct drm_connector
-							*connector, bool force)
-{
-	struct pl111_drm_connector *pl111_connector =
-		to_pl111_connector(connector);
-
-	return (pl111_connector->panel ?
-		connector_status_connected :
-		connector_status_disconnected);
-}
-
-static int pl111_connector_helper_get_modes(struct drm_connector *connector)
-{
-	struct pl111_drm_connector *pl111_connector =
-		to_pl111_connector(connector);
-
-	if (!pl111_connector->panel)
-		return 0;
-
-	return drm_panel_get_modes(pl111_connector->panel);
-}
-
-const struct drm_connector_funcs connector_funcs = {
-	.fill_modes = drm_helper_probe_single_connector_modes,
-	.destroy = pl111_connector_destroy,
-	.detect = pl111_connector_detect,
-	.dpms = drm_atomic_helper_connector_dpms,
-	.reset = drm_atomic_helper_connector_reset,
-	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
-	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
-};
-
-const struct drm_connector_helper_funcs connector_helper_funcs = {
-	.get_modes = pl111_connector_helper_get_modes,
-};
-
-/* Walks the OF graph to find the panel node and then asks DRM to look
- * up the panel.
- */
-static struct drm_panel *pl111_get_panel(struct device *dev)
-{
-	struct device_node *endpoint, *panel_node;
-	struct device_node *np = dev->of_node;
-	struct drm_panel *panel;
-
-	endpoint = of_graph_get_next_endpoint(np, NULL);
-	if (!endpoint) {
-		dev_err(dev, "no endpoint to fetch panel\n");
-		return NULL;
-	}
-
-	/* don't proceed if we have an endpoint but no panel_node tied to it */
-	panel_node = of_graph_get_remote_port_parent(endpoint);
-	of_node_put(endpoint);
-	if (!panel_node) {
-		dev_err(dev, "no valid panel node\n");
-		return NULL;
-	}
-
-	panel = of_drm_find_panel(panel_node);
-	of_node_put(panel_node);
-
-	return panel;
-}
-
-int pl111_connector_init(struct drm_device *dev)
-{
-	struct pl111_drm_dev_private *priv = dev->dev_private;
-	struct pl111_drm_connector *pl111_connector = &priv->connector;
-	struct drm_connector *connector = &pl111_connector->connector;
-
-	drm_connector_init(dev, connector, &connector_funcs,
-			   DRM_MODE_CONNECTOR_DPI);
-	drm_connector_helper_add(connector, &connector_helper_funcs);
-
-	pl111_connector->panel = pl111_get_panel(dev->dev);
-	if (pl111_connector->panel)
-		drm_panel_attach(pl111_connector->panel, connector);
-
-	return 0;
-}
-
diff --git a/drivers/gpu/drm/pl111/pl111_display.c b/drivers/gpu/drm/pl111/pl111_display.c
index c6ca4f1bbd49..59cdb8f49bb1 100644
--- a/drivers/gpu/drm/pl111/pl111_display.c
+++ b/drivers/gpu/drm/pl111/pl111_display.c
@@ -21,7 +21,6 @@ 
 #include <linux/of_graph.h>
 
 #include <drm/drmP.h>
-#include <drm/drm_panel.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
 
@@ -93,7 +92,7 @@  static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 	struct pl111_drm_dev_private *priv = drm->dev_private;
 	const struct drm_display_mode *mode = &cstate->mode;
 	struct drm_framebuffer *fb = plane->state->fb;
-	struct drm_connector *connector = &priv->connector.connector;
+	struct drm_connector *connector = priv->connector;
 	u32 cntl;
 	u32 ppl, hsw, hfp, hbp;
 	u32 lpp, vsw, vfp, vbp;
@@ -155,8 +154,6 @@  static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 
 	writel(0, priv->regs + CLCD_TIM3);
 
-	drm_panel_prepare(priv->connector.panel);
-
 	/* Enable and Power Up */
 	cntl = CNTL_LCDEN | CNTL_LCDTFT | CNTL_LCDPWR | CNTL_LCDVCOMP(1);
 
@@ -203,8 +200,6 @@  static void pl111_display_enable(struct drm_simple_display_pipe *pipe,
 
 	writel(cntl, priv->regs + CLCD_PL111_CNTL);
 
-	drm_panel_enable(priv->connector.panel);
-
 	drm_crtc_vblank_on(crtc);
 }
 
@@ -216,13 +211,9 @@  void pl111_display_disable(struct drm_simple_display_pipe *pipe)
 
 	drm_crtc_vblank_off(crtc);
 
-	drm_panel_disable(priv->connector.panel);
-
 	/* Disable and Power Down */
 	writel(0, priv->regs + CLCD_PL111_CNTL);
 
-	drm_panel_unprepare(priv->connector.panel);
-
 	clk_disable_unprepare(priv->clk);
 }
 
@@ -457,9 +448,12 @@  int pl111_display_init(struct drm_device *drm)
 	ret = drm_simple_display_pipe_init(drm, &priv->pipe,
 					   &pl111_display_funcs,
 					   formats, ARRAY_SIZE(formats),
-					   &priv->connector.connector);
+					   priv->connector);
 	if (ret)
 		return ret;
 
+	/* We need the encoder to attach the bridge */
+	priv->encoder = &priv->pipe.encoder;
+
 	return 0;
 }
diff --git a/drivers/gpu/drm/pl111/pl111_drm.h b/drivers/gpu/drm/pl111/pl111_drm.h
index a97f303f6833..8804af0f8997 100644
--- a/drivers/gpu/drm/pl111/pl111_drm.h
+++ b/drivers/gpu/drm/pl111/pl111_drm.h
@@ -21,21 +21,23 @@ 
 
 #include <drm/drm_gem.h>
 #include <drm/drm_simple_kms_helper.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_bridge.h>
 #include <linux/clk-provider.h>
 
 #define CLCD_IRQ_NEXTBASE_UPDATE BIT(2)
 
 struct drm_minor;
 
-struct pl111_drm_connector {
-	struct drm_connector connector;
-	struct drm_panel *panel;
-};
-
 struct pl111_drm_dev_private {
 	struct drm_device *drm;
 
-	struct pl111_drm_connector connector;
+	struct drm_connector *connector;
+	struct drm_encoder *encoder;
+	struct drm_panel *panel;
+	struct drm_bridge *bridge;
 	struct drm_simple_display_pipe pipe;
 	struct drm_fbdev_cma *fbdev;
 
@@ -50,14 +52,10 @@  struct pl111_drm_dev_private {
 	spinlock_t tim2_lock;
 };
 
-#define to_pl111_connector(x) \
-	container_of(x, struct pl111_drm_connector, connector)
-
 int pl111_display_init(struct drm_device *dev);
 int pl111_enable_vblank(struct drm_device *drm, unsigned int crtc);
 void pl111_disable_vblank(struct drm_device *drm, unsigned int crtc);
 irqreturn_t pl111_irq(int irq, void *data);
-int pl111_connector_init(struct drm_device *dev);
 int pl111_debugfs_init(struct drm_minor *minor);
 
 #endif /* _PL111_DRM_H_ */
diff --git a/drivers/gpu/drm/pl111/pl111_drv.c b/drivers/gpu/drm/pl111/pl111_drv.c
index ac8771be70b0..e66cbf202e17 100644
--- a/drivers/gpu/drm/pl111/pl111_drv.c
+++ b/drivers/gpu/drm/pl111/pl111_drv.c
@@ -67,6 +67,9 @@ 
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_gem_cma_helper.h>
 #include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_of.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_panel.h>
 
 #include "pl111_drm.h"
 
@@ -82,6 +85,8 @@  static int pl111_modeset_init(struct drm_device *dev)
 {
 	struct drm_mode_config *mode_config;
 	struct pl111_drm_dev_private *priv = dev->dev_private;
+	struct drm_panel *panel;
+	struct drm_bridge *bridge;
 	int ret = 0;
 
 	drm_mode_config_init(dev);
@@ -92,34 +97,46 @@  static int pl111_modeset_init(struct drm_device *dev)
 	mode_config->min_height = 1;
 	mode_config->max_height = 768;
 
-	ret = pl111_connector_init(dev);
-	if (ret) {
-		dev_err(dev->dev, "Failed to create pl111_drm_connector\n");
-		goto out_config;
-	}
-
-	/* Don't actually attach if we didn't find a drm_panel
-	 * attached to us.  This will allow a kernel to include both
-	 * the fbdev pl111 driver and this one, and choose between
-	 * them based on which subsystem has support for the panel.
-	 */
-	if (!priv->connector.panel) {
-		dev_info(dev->dev,
-			 "Disabling due to lack of DRM panel device.\n");
-		ret = -ENODEV;
-		goto out_config;
+	ret = drm_of_find_panel_or_bridge(dev->dev->of_node,
+					  0, 0, &panel, &bridge);
+	if (ret && ret != -ENODEV)
+		return ret;
+	if (panel) {
+		bridge = drm_panel_bridge_add(panel,
+					      DRM_MODE_CONNECTOR_Unknown);
+		if (IS_ERR(bridge)) {
+			ret = PTR_ERR(bridge);
+			goto out_config;
+		}
 	}
 
 	ret = pl111_display_init(dev);
 	if (ret != 0) {
 		dev_err(dev->dev, "Failed to init display\n");
-		goto out_config;
+		goto out_bridge;
+	}
+
+	if (bridge) {
+		ret = drm_bridge_attach(priv->encoder, bridge, NULL);
+		if (ret)
+			goto out_bridge;
+	}
+
+	/*
+	 * TODO: when we are using a different bridge than a panel
+	 * (such as a dumb VGA connector) we need to devise a different
+	 * method to get the connector out of the bridge.
+	 */
+	if (panel) {
+		priv->panel = panel;
+		priv->connector = panel->connector;
 	}
+	priv->bridge = bridge;
 
 	ret = drm_vblank_init(dev, 1);
 	if (ret != 0) {
 		dev_err(dev->dev, "Failed to init vblank\n");
-		goto out_config;
+		goto out_bridge;
 	}
 
 	drm_mode_config_reset(dev);
@@ -131,6 +148,11 @@  static int pl111_modeset_init(struct drm_device *dev)
 
 	goto finish;
 
+out_bridge:
+	if (panel)
+		drm_panel_bridge_remove(bridge);
+	else
+		drm_bridge_remove(bridge);
 out_config:
 	drm_mode_config_cleanup(dev);
 finish:
@@ -237,6 +259,10 @@  static int pl111_amba_remove(struct amba_device *amba_dev)
 	drm_dev_unregister(drm);
 	if (priv->fbdev)
 		drm_fbdev_cma_fini(priv->fbdev);
+	if (priv->panel)
+		drm_panel_bridge_remove(priv->bridge);
+	else
+		drm_bridge_remove(priv->bridge);
 	drm_mode_config_cleanup(drm);
 	drm_dev_unref(drm);