Blob Blame History Raw
From: Chen-Yu Tsai <wens@csie.org>
Date: Fri, 21 Apr 2017 16:38:50 +0800
Subject: drm/sun4i: Use lists to track registered display backends and TCONs
Git-commit: 80a58240efef576ef909f7d99180ae2a70ca68a5
Patch-mainline: v4.13-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

To support multiple display pipelines, we need to keep track of the
multiple display backends and TCONs registered with the driver.

Switch to lists to track registered components. Components are only
appended to their respective lists if the bind process was successful.
The TCON bind function now defers if a backend was not registered.

Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/sun4i/sun4i_backend.c |    6 +++++-
 drivers/gpu/drm/sun4i/sun4i_backend.h |    4 ++++
 drivers/gpu/drm/sun4i/sun4i_drv.c     |    2 ++
 drivers/gpu/drm/sun4i/sun4i_drv.h     |    5 +++--
 drivers/gpu/drm/sun4i/sun4i_tcon.c    |   14 ++++++++++++--
 drivers/gpu/drm/sun4i/sun4i_tcon.h    |    4 ++++
 6 files changed, 30 insertions(+), 5 deletions(-)

--- a/drivers/gpu/drm/sun4i/sun4i_backend.c
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.c
@@ -19,6 +19,7 @@
 #include <drm/drm_plane_helper.h>
 
 #include <linux/component.h>
+#include <linux/list.h>
 #include <linux/reset.h>
 
 #include "sun4i_backend.h"
@@ -310,7 +311,6 @@ static int sun4i_backend_bind(struct dev
 	if (!backend)
 		return -ENOMEM;
 	dev_set_drvdata(dev, backend);
-	drv->backend = backend;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	regs = devm_ioremap_resource(dev, res);
@@ -369,6 +369,8 @@ static int sun4i_backend_bind(struct dev
 		}
 	}
 
+	list_add_tail(&backend->list, &drv->backend_list);
+
 	/* Reset the registers */
 	for (i = 0x800; i < 0x1000; i += 4)
 		regmap_write(backend->regs, i, 0);
@@ -400,6 +402,8 @@ static void sun4i_backend_unbind(struct
 {
 	struct sun4i_backend *backend = dev_get_drvdata(dev);
 
+	list_del(&backend->list);
+
 	if (of_device_is_compatible(dev->of_node,
 				    "allwinner,sun8i-a33-display-backend"))
 		sun4i_backend_free_sat(dev);
--- a/drivers/gpu/drm/sun4i/sun4i_backend.h
+++ b/drivers/gpu/drm/sun4i/sun4i_backend.h
@@ -14,6 +14,7 @@
 #define _SUN4I_BACKEND_H_
 
 #include <linux/clk.h>
+#include <linux/list.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
@@ -149,6 +150,9 @@ struct sun4i_backend {
 
 	struct clk		*sat_clk;
 	struct reset_control	*sat_reset;
+
+	/* Backend list management */
+	struct list_head	list;
 };
 
 void sun4i_backend_apply_color_correction(struct sun4i_backend *backend);
--- a/drivers/gpu/drm/sun4i/sun4i_drv.c
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.c
@@ -99,6 +99,8 @@ static int sun4i_drv_bind(struct device
 		goto free_drm;
 	}
 	drm->dev_private = drv;
+	INIT_LIST_HEAD(&drv->backend_list);
+	INIT_LIST_HEAD(&drv->tcon_list);
 
 	ret = of_reserved_mem_device_init(dev);
 	if (ret && ret != -ENODEV) {
--- a/drivers/gpu/drm/sun4i/sun4i_drv.h
+++ b/drivers/gpu/drm/sun4i/sun4i_drv.h
@@ -14,11 +14,12 @@
 #define _SUN4I_DRV_H_
 
 #include <linux/clk.h>
+#include <linux/list.h>
 #include <linux/regmap.h>
 
 struct sun4i_drv {
-	struct sun4i_backend	*backend;
-	struct sun4i_tcon	*tcon;
+	struct list_head	backend_list;
+	struct list_head	tcon_list;
 
 	struct drm_fbdev_cma	*fbdev;
 };
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -25,6 +25,7 @@
 #include <linux/regmap.h>
 #include <linux/reset.h>
 
+#include "sun4i_backend.h"
 #include "sun4i_crtc.h"
 #include "sun4i_dotclock.h"
 #include "sun4i_drv.h"
@@ -407,14 +408,18 @@ static int sun4i_tcon_bind(struct device
 {
 	struct drm_device *drm = data;
 	struct sun4i_drv *drv = drm->dev_private;
+	struct sun4i_backend *backend;
 	struct sun4i_tcon *tcon;
 	int ret;
 
+	/* Wait for a backend to be registered */
+	if (list_empty(&drv->backend_list))
+		return -EPROBE_DEFER;
+
 	tcon = devm_kzalloc(dev, sizeof(*tcon), GFP_KERNEL);
 	if (!tcon)
 		return -ENOMEM;
 	dev_set_drvdata(dev, tcon);
-	drv->tcon = tcon;
 	tcon->drm = drm;
 	tcon->dev = dev;
 	tcon->quirks = of_device_get_match_data(dev);
@@ -459,7 +464,9 @@ static int sun4i_tcon_bind(struct device
 		goto err_free_dotclock;
 	}
 
-	tcon->crtc = sun4i_crtc_init(drm, drv->backend, tcon);
+	backend = list_first_entry(&drv->backend_list,
+				   struct sun4i_backend, list);
+	tcon->crtc = sun4i_crtc_init(drm, backend, tcon);
 	if (IS_ERR(tcon->crtc)) {
 		dev_err(dev, "Couldn't create our CRTC\n");
 		ret = PTR_ERR(tcon->crtc);
@@ -470,6 +477,8 @@ static int sun4i_tcon_bind(struct device
 	if (ret < 0)
 		goto err_free_clocks;
 
+	list_add_tail(&tcon->list, &drv->tcon_list);
+
 	return 0;
 
 err_free_dotclock:
@@ -486,6 +495,7 @@ static void sun4i_tcon_unbind(struct dev
 {
 	struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
+	list_del(&tcon->list);
 	sun4i_dclk_free(tcon);
 	sun4i_tcon_free_clocks(tcon);
 }
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -17,6 +17,7 @@
 #include <drm/drm_crtc.h>
 
 #include <linux/kernel.h>
+#include <linux/list.h>
 #include <linux/reset.h>
 
 #define SUN4I_TCON_GCTL_REG			0x0
@@ -172,6 +173,9 @@ struct sun4i_tcon {
 
 	/* Associated crtc */
 	struct sun4i_crtc		*crtc;
+
+	/* TCON list management */
+	struct list_head		list;
 };
 
 struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node);