diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_tcon.c')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 126 |
1 files changed, 30 insertions, 96 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index ea2906f87cb9..9a83a85529ac 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -15,13 +15,12 @@ #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", ®); - 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", ®); - 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); } |