drm/sun4i: Use lists to track registered display backends and TCONs
authorChen-Yu Tsai <wens@csie.org>
Fri, 21 Apr 2017 08:38:50 +0000 (16:38 +0800)
committerMaxime Ripard <maxime.ripard@free-electrons.com>
Sun, 14 May 2017 06:27:41 +0000 (08:27 +0200)
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>
drivers/gpu/drm/sun4i/sun4i_backend.c
drivers/gpu/drm/sun4i/sun4i_backend.h
drivers/gpu/drm/sun4i/sun4i_drv.c
drivers/gpu/drm/sun4i/sun4i_drv.h
drivers/gpu/drm/sun4i/sun4i_tcon.c
drivers/gpu/drm/sun4i/sun4i_tcon.h

index d660741ba475af98c22d36275f950661c6b98a9e..95a77c6a91615c2443adb8e30df15287ece64361 100644 (file)
@@ -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 device *dev, struct device *master,
        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 device *dev, struct device *master,
                }
        }
 
+       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 device *dev, struct device *master,
 {
        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);
index 83e63cc702b412e2c0035d4dcd9b7ba27c9395ad..9c8287309c65ffa47ecb10c8bd30bae039d21fd2 100644 (file)
@@ -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);
index 8ddd72cd58736e3f6e0935087cccdab802e6dd96..c52f7a9eb04562e59165684e08510b162f6c04d0 100644 (file)
@@ -91,6 +91,8 @@ static int sun4i_drv_bind(struct device *dev)
                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) {
index 5df50126ff52531be776e79db00f629347efae25..250c29017ef54d9c225d307e2c7e2b2dd16730b3 100644 (file)
 #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;
 };
index 9a83a85529ac46ab0b351e7111cded6ef7313259..5adb643ed41d9aca3cfa9c7926d7a1f77a243f4b 100644 (file)
@@ -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 *dev, struct device *master,
 {
        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 *dev, struct device *master,
                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 *dev, struct device *master,
        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 device *dev, struct device *master,
 {
        struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
+       list_del(&tcon->list);
        sun4i_dclk_free(tcon);
        sun4i_tcon_free_clocks(tcon);
 }
index f636343a935dce6889d9f0651354191b9af03c6d..1bda4d183eeccd91b197e6fafe118cfe8d1c2a3f 100644 (file)
@@ -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);