diff options
Diffstat (limited to 'drivers/gpu/drm/sun4i/sun4i_tcon.c')
-rw-r--r-- | drivers/gpu/drm/sun4i/sun4i_tcon.c | 61 |
1 files changed, 60 insertions, 1 deletions
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c index 5fbd3ce9d651..9f19b0e08560 100644 --- a/drivers/gpu/drm/sun4i/sun4i_tcon.c +++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c @@ -15,10 +15,12 @@ #include <drm/drm_crtc.h> #include <drm/drm_crtc_helper.h> #include <drm/drm_modes.h> +#include <drm/drm_panel.h> #include <linux/component.h> #include <linux/ioport.h> #include <linux/of_address.h> +#include <linux/of_graph.h> #include <linux/of_irq.h> #include <linux/regmap.h> #include <linux/reset.h> @@ -26,6 +28,7 @@ #include "sun4i_crtc.h" #include "sun4i_dotclock.h" #include "sun4i_drv.h" +#include "sun4i_rgb.h" #include "sun4i_tcon.h" void sun4i_tcon_disable(struct sun4i_tcon *tcon) @@ -395,6 +398,40 @@ static int sun4i_tcon_init_regmap(struct device *dev, return 0; } +static 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("Enable to parse remote node\n"); + return ERR_PTR(-EINVAL); + } + + return of_drm_find_panel(remote); +} + static int sun4i_tcon_bind(struct device *dev, struct device *master, void *data) { @@ -447,7 +484,13 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master, goto err_free_clocks; } - return 0; + tcon->panel = sun4i_tcon_find_panel(dev->of_node); + if (IS_ERR(tcon->panel)) { + dev_info(dev, "No panel found... RGB output disabled\n"); + return 0; + } + + return sun4i_rgb_init(drm); err_free_clocks: sun4i_tcon_free_clocks(tcon); @@ -471,6 +514,22 @@ static struct component_ops sun4i_tcon_ops = { static int sun4i_tcon_probe(struct platform_device *pdev) { + struct device_node *node = pdev->dev.of_node; + struct drm_panel *panel; + + /* + * The panel is not ready. + * Defer the probe. + */ + panel = sun4i_tcon_find_panel(node); + if (IS_ERR(panel)) { + /* + * If we don't have a panel endpoint, just go on + */ + if (PTR_ERR(panel) != -ENODEV) + return -EPROBE_DEFER; + } + return component_add(&pdev->dev, &sun4i_tcon_ops); } |