]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - drivers/gpu/drm/sun4i/sun4i_tcon.c
Merge tag 'sunxi-drm-for-4.12' of https://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-artful-kernel.git] / drivers / gpu / drm / sun4i / sun4i_tcon.c
index ea2906f87cb91f3ca5a8ced1261da19bc9bbca02..9a83a85529ac46ab0b351e7111cded6ef7313259 100644 (file)
 #include <drm/drm_crtc.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_modes.h>
-#include <drm/drm_panel.h>
+#include <drm/drm_of.h>
 
 #include <linux/component.h>
 #include <linux/ioport.h>
 #include <linux/of_address.h>
 #include <linux/of_device.h>
-#include <linux/of_graph.h>
 #include <linux/of_irq.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
@@ -143,7 +142,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 
        /*
         * This is called a backporch in the register documentation,
-        * but it really is the front porch + hsync
+        * but it really is the back porch + hsync
         */
        bp = mode->crtc_htotal - mode->crtc_hsync_start;
        DRM_DEBUG_DRIVER("Setting horizontal total %d, backporch %d\n",
@@ -156,7 +155,7 @@ void sun4i_tcon0_mode_set(struct sun4i_tcon *tcon,
 
        /*
         * This is called a backporch in the register documentation,
-        * but it really is the front porch + hsync
+        * but it really is the back porch + hsync
         */
        bp = mode->crtc_vtotal - mode->crtc_vsync_start;
        DRM_DEBUG_DRIVER("Setting vertical total %d, backporch %d\n",
@@ -290,8 +289,7 @@ static irqreturn_t sun4i_tcon_handler(int irq, void *private)
 {
        struct sun4i_tcon *tcon = private;
        struct drm_device *drm = tcon->drm;
-       struct sun4i_drv *drv = drm->dev_private;
-       struct sun4i_crtc *scrtc = drv->crtc;
+       struct sun4i_crtc *scrtc = tcon->crtc;
        unsigned int status;
 
        regmap_read(tcon->regs, SUN4I_TCON_GINT0_REG, &status);
@@ -336,12 +334,11 @@ static int sun4i_tcon_init_clocks(struct device *dev,
                }
        }
 
-       return sun4i_dclk_create(dev, tcon);
+       return 0;
 }
 
 static void sun4i_tcon_free_clocks(struct sun4i_tcon *tcon)
 {
-       sun4i_dclk_free(tcon);
        clk_disable_unprepare(tcon->clk);
 }
 
@@ -405,74 +402,6 @@ static int sun4i_tcon_init_regmap(struct device *dev,
        return 0;
 }
 
-struct drm_panel *sun4i_tcon_find_panel(struct device_node *node)
-{
-       struct device_node *port, *remote, *child;
-       struct device_node *end_node = NULL;
-
-       /* Inputs are listed first, then outputs */
-       port = of_graph_get_port_by_id(node, 1);
-
-       /*
-        * Our first output is the RGB interface where the panel will
-        * be connected.
-        */
-       for_each_child_of_node(port, child) {
-               u32 reg;
-
-               of_property_read_u32(child, "reg", &reg);
-               if (reg == 0)
-                       end_node = child;
-       }
-
-       if (!end_node) {
-               DRM_DEBUG_DRIVER("Missing panel endpoint\n");
-               return ERR_PTR(-ENODEV);
-       }
-
-       remote = of_graph_get_remote_port_parent(end_node);
-       if (!remote) {
-               DRM_DEBUG_DRIVER("Unable to parse remote node\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       return of_drm_find_panel(remote) ?: ERR_PTR(-EPROBE_DEFER);
-}
-
-struct drm_bridge *sun4i_tcon_find_bridge(struct device_node *node)
-{
-       struct device_node *port, *remote, *child;
-       struct device_node *end_node = NULL;
-
-       /* Inputs are listed first, then outputs */
-       port = of_graph_get_port_by_id(node, 1);
-
-       /*
-        * Our first output is the RGB interface where the panel will
-        * be connected.
-        */
-       for_each_child_of_node(port, child) {
-               u32 reg;
-
-               of_property_read_u32(child, "reg", &reg);
-               if (reg == 0)
-                       end_node = child;
-       }
-
-       if (!end_node) {
-               DRM_DEBUG_DRIVER("Missing bridge endpoint\n");
-               return ERR_PTR(-ENODEV);
-       }
-
-       remote = of_graph_get_remote_port_parent(end_node);
-       if (!remote) {
-               DRM_DEBUG_DRIVER("Enable to parse remote node\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       return of_drm_find_bridge(remote) ?: ERR_PTR(-EPROBE_DEFER);
-}
-
 static int sun4i_tcon_bind(struct device *dev, struct device *master,
                           void *data)
 {
@@ -506,30 +435,45 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
                return ret;
        }
 
+       ret = sun4i_tcon_init_clocks(dev, tcon);
+       if (ret) {
+               dev_err(dev, "Couldn't init our TCON clocks\n");
+               goto err_assert_reset;
+       }
+
        ret = sun4i_tcon_init_regmap(dev, tcon);
        if (ret) {
                dev_err(dev, "Couldn't init our TCON regmap\n");
-               goto err_assert_reset;
+               goto err_free_clocks;
        }
 
-       ret = sun4i_tcon_init_clocks(dev, tcon);
+       ret = sun4i_dclk_create(dev, tcon);
        if (ret) {
-               dev_err(dev, "Couldn't init our TCON clocks\n");
-               goto err_assert_reset;
+               dev_err(dev, "Couldn't create our TCON dot clock\n");
+               goto err_free_clocks;
        }
 
        ret = sun4i_tcon_init_irq(dev, tcon);
        if (ret) {
                dev_err(dev, "Couldn't init our TCON interrupts\n");
+               goto err_free_dotclock;
+       }
+
+       tcon->crtc = sun4i_crtc_init(drm, drv->backend, tcon);
+       if (IS_ERR(tcon->crtc)) {
+               dev_err(dev, "Couldn't create our CRTC\n");
+               ret = PTR_ERR(tcon->crtc);
                goto err_free_clocks;
        }
 
-       ret = sun4i_rgb_init(drm);
+       ret = sun4i_rgb_init(drm, tcon);
        if (ret < 0)
                goto err_free_clocks;
 
        return 0;
 
+err_free_dotclock:
+       sun4i_dclk_free(tcon);
 err_free_clocks:
        sun4i_tcon_free_clocks(tcon);
 err_assert_reset:
@@ -542,6 +486,7 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
 {
        struct sun4i_tcon *tcon = dev_get_drvdata(dev);
 
+       sun4i_dclk_free(tcon);
        sun4i_tcon_free_clocks(tcon);
 }
 
@@ -555,22 +500,11 @@ static int sun4i_tcon_probe(struct platform_device *pdev)
        struct device_node *node = pdev->dev.of_node;
        struct drm_bridge *bridge;
        struct drm_panel *panel;
+       int ret;
 
-       /*
-        * Neither the bridge or the panel is ready.
-        * Defer the probe.
-        */
-       panel = sun4i_tcon_find_panel(node);
-       bridge = sun4i_tcon_find_bridge(node);
-
-       /*
-        * If we don't have a panel endpoint, just go on
-        */
-       if ((PTR_ERR(panel) == -EPROBE_DEFER) &&
-           (PTR_ERR(bridge) == -EPROBE_DEFER)) {
-               DRM_DEBUG_DRIVER("Still waiting for our panel/bridge. Deferring...\n");
-               return -EPROBE_DEFER;
-       }
+       ret = drm_of_find_panel_or_bridge(node, 1, 0, &panel, &bridge);
+       if (ret == -EPROBE_DEFER)
+               return ret;
 
        return component_add(&pdev->dev, &sun4i_tcon_ops);
 }