Skip to content

Commit

Permalink
drm/armada: convert to componentized support
Browse files Browse the repository at this point in the history
Convert the Armada DRM driver to use the component helpers, which will
permit us to clean up the driver and move towards an implementation
which is compatible with a DT description of the hardware.

Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
Russell King committed Jul 11, 2014
1 parent 2f2d270 commit 0101fd0
Showing 1 changed file with 148 additions and 7 deletions.
155 changes: 148 additions & 7 deletions drivers/gpu/drm/armada/armada_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
#include <linux/component.h>
#include <linux/module.h>
#include <linux/of_graph.h>
#include <drm/drmP.h>
#include <drm/drm_crtc_helper.h>
#include "armada_crtc.h"
Expand Down Expand Up @@ -52,6 +54,11 @@ static const struct armada_drm_slave_config tda19988_config = {
};
#endif

static bool is_componentized(struct device *dev)
{
return dev->of_node || dev->platform_data;
}

static void armada_drm_unref_work(struct work_struct *work)
{
struct armada_private *priv =
Expand Down Expand Up @@ -166,26 +173,35 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
goto err_kms;
}

if (is_componentized(dev->dev)) {
ret = component_bind_all(dev->dev, dev);
if (ret)
goto err_kms;
} else {
#ifdef CONFIG_DRM_ARMADA_TDA1998X
ret = armada_drm_connector_slave_create(dev, &tda19988_config);
if (ret)
goto err_kms;
ret = armada_drm_connector_slave_create(dev, &tda19988_config);
if (ret)
goto err_kms;
#endif
}

ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
if (ret)
goto err_kms;
goto err_comp;

dev->vblank_disable_allowed = 1;

ret = armada_fbdev_init(dev);
if (ret)
goto err_kms;
goto err_comp;

drm_kms_helper_poll_init(dev);

return 0;

err_comp:
if (is_componentized(dev->dev))
component_unbind_all(dev->dev, dev);
err_kms:
drm_mode_config_cleanup(dev);
drm_mm_takedown(&priv->linear);
Expand All @@ -200,6 +216,10 @@ static int armada_drm_unload(struct drm_device *dev)

drm_kms_helper_poll_fini(dev);
armada_fbdev_fini(dev);

if (is_componentized(dev->dev))
component_unbind_all(dev->dev, dev);

drm_mode_config_cleanup(dev);
drm_mm_takedown(&priv->linear);
flush_work(&priv->fb_unref_work);
Expand Down Expand Up @@ -314,14 +334,135 @@ static struct drm_driver armada_drm_driver = {
.fops = &armada_drm_fops,
};

static int armada_drm_bind(struct device *dev)
{
return drm_platform_init(&armada_drm_driver, to_platform_device(dev));
}

static void armada_drm_unbind(struct device *dev)
{
drm_put_dev(dev_get_drvdata(dev));
}

static int compare_of(struct device *dev, void *data)
{
return dev->of_node == data;
}

static int compare_dev_name(struct device *dev, void *data)
{
const char *name = data;
return !strcmp(dev_name(dev), name);
}

static void armada_add_endpoints(struct device *dev,
struct component_match **match, struct device_node *port)
{
struct device_node *ep, *remote;

for_each_child_of_node(port, ep) {
remote = of_graph_get_remote_port_parent(ep);
if (!remote || !of_device_is_available(remote)) {
of_node_put(remote);
continue;
} else if (!of_device_is_available(remote->parent)) {
dev_warn(dev, "parent device of %s is not available\n",
remote->full_name);
of_node_put(remote);
continue;
}

component_match_add(dev, match, compare_of, remote);
of_node_put(remote);
}
}

static int armada_drm_find_components(struct device *dev,
struct component_match **match)
{
struct device_node *port;
int i;

if (dev->of_node) {
struct device_node *np = dev->of_node;

for (i = 0; ; i++) {
port = of_parse_phandle(np, "ports", i);
if (!port)
break;

component_match_add(dev, match, compare_of, port);
of_node_put(port);
}

if (i == 0) {
dev_err(dev, "missing 'ports' property\n");
return -ENODEV;
}

for (i = 0; ; i++) {
port = of_parse_phandle(np, "ports", i);
if (!port)
break;

armada_add_endpoints(dev, match, port);
of_node_put(port);
}
} else if (dev->platform_data) {
char **devices = dev->platform_data;
struct device *d;

for (i = 0; devices[i]; i++)
component_match_add(dev, match, compare_dev_name,
devices[i]);

if (i == 0) {
dev_err(dev, "missing 'ports' property\n");
return -ENODEV;
}

for (i = 0; devices[i]; i++) {
d = bus_find_device_by_name(&platform_bus_type, NULL,
devices[i]);
if (d && d->of_node) {
for_each_child_of_node(d->of_node, port)
armada_add_endpoints(dev, match, port);
}
put_device(d);
}
}

return 0;
}

static const struct component_master_ops armada_master_ops = {
.bind = armada_drm_bind,
.unbind = armada_drm_unbind,
};

static int armada_drm_probe(struct platform_device *pdev)
{
return drm_platform_init(&armada_drm_driver, pdev);
if (is_componentized(&pdev->dev)) {
struct component_match *match = NULL;
int ret;

ret = armada_drm_find_components(&pdev->dev, &match);
if (ret < 0)
return ret;

return component_master_add_with_match(&pdev->dev,
&armada_master_ops, match);
} else {
return drm_platform_init(&armada_drm_driver, pdev);
}
}

static int armada_drm_remove(struct platform_device *pdev)
{
drm_put_dev(platform_get_drvdata(pdev));
if (is_componentized(&pdev->dev))
component_master_del(&pdev->dev, &armada_master_ops);
else
drm_put_dev(platform_get_drvdata(pdev));
return 0;
}

Expand Down

0 comments on commit 0101fd0

Please sign in to comment.