aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-02-04 06:57:06 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-07-11 10:40:12 -0400
commit0101fd0043075a2855ea98f07e6f2c7a72a5cbab (patch)
tree6992b157915bbb3994cd2aa36b053c1d4b4889bc /drivers
parent2f2d27026c4728533d60ac0b7b98df18f6b2cd0c (diff)
drm/armada: convert to componentized support
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/armada/armada_drv.c155
1 files changed, 148 insertions, 7 deletions
diff --git a/drivers/gpu/drm/armada/armada_drv.c b/drivers/gpu/drm/armada/armada_drv.c
index 3995be3c686b..2b6fc6cf62f2 100644
--- a/drivers/gpu/drm/armada/armada_drv.c
+++ b/drivers/gpu/drm/armada/armada_drv.c
@@ -6,7 +6,9 @@
6 * published by the Free Software Foundation. 6 * published by the Free Software Foundation.
7 */ 7 */
8#include <linux/clk.h> 8#include <linux/clk.h>
9#include <linux/component.h>
9#include <linux/module.h> 10#include <linux/module.h>
11#include <linux/of_graph.h>
10#include <drm/drmP.h> 12#include <drm/drmP.h>
11#include <drm/drm_crtc_helper.h> 13#include <drm/drm_crtc_helper.h>
12#include "armada_crtc.h" 14#include "armada_crtc.h"
@@ -52,6 +54,11 @@ static const struct armada_drm_slave_config tda19988_config = {
52}; 54};
53#endif 55#endif
54 56
57static bool is_componentized(struct device *dev)
58{
59 return dev->of_node || dev->platform_data;
60}
61
55static void armada_drm_unref_work(struct work_struct *work) 62static void armada_drm_unref_work(struct work_struct *work)
56{ 63{
57 struct armada_private *priv = 64 struct armada_private *priv =
@@ -166,26 +173,35 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
166 goto err_kms; 173 goto err_kms;
167 } 174 }
168 175
176 if (is_componentized(dev->dev)) {
177 ret = component_bind_all(dev->dev, dev);
178 if (ret)
179 goto err_kms;
180 } else {
169#ifdef CONFIG_DRM_ARMADA_TDA1998X 181#ifdef CONFIG_DRM_ARMADA_TDA1998X
170 ret = armada_drm_connector_slave_create(dev, &tda19988_config); 182 ret = armada_drm_connector_slave_create(dev, &tda19988_config);
171 if (ret) 183 if (ret)
172 goto err_kms; 184 goto err_kms;
173#endif 185#endif
186 }
174 187
175 ret = drm_vblank_init(dev, dev->mode_config.num_crtc); 188 ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
176 if (ret) 189 if (ret)
177 goto err_kms; 190 goto err_comp;
178 191
179 dev->vblank_disable_allowed = 1; 192 dev->vblank_disable_allowed = 1;
180 193
181 ret = armada_fbdev_init(dev); 194 ret = armada_fbdev_init(dev);
182 if (ret) 195 if (ret)
183 goto err_kms; 196 goto err_comp;
184 197
185 drm_kms_helper_poll_init(dev); 198 drm_kms_helper_poll_init(dev);
186 199
187 return 0; 200 return 0;
188 201
202 err_comp:
203 if (is_componentized(dev->dev))
204 component_unbind_all(dev->dev, dev);
189 err_kms: 205 err_kms:
190 drm_mode_config_cleanup(dev); 206 drm_mode_config_cleanup(dev);
191 drm_mm_takedown(&priv->linear); 207 drm_mm_takedown(&priv->linear);
@@ -200,6 +216,10 @@ static int armada_drm_unload(struct drm_device *dev)
200 216
201 drm_kms_helper_poll_fini(dev); 217 drm_kms_helper_poll_fini(dev);
202 armada_fbdev_fini(dev); 218 armada_fbdev_fini(dev);
219
220 if (is_componentized(dev->dev))
221 component_unbind_all(dev->dev, dev);
222
203 drm_mode_config_cleanup(dev); 223 drm_mode_config_cleanup(dev);
204 drm_mm_takedown(&priv->linear); 224 drm_mm_takedown(&priv->linear);
205 flush_work(&priv->fb_unref_work); 225 flush_work(&priv->fb_unref_work);
@@ -314,14 +334,135 @@ static struct drm_driver armada_drm_driver = {
314 .fops = &armada_drm_fops, 334 .fops = &armada_drm_fops,
315}; 335};
316 336
337static int armada_drm_bind(struct device *dev)
338{
339 return drm_platform_init(&armada_drm_driver, to_platform_device(dev));
340}
341
342static void armada_drm_unbind(struct device *dev)
343{
344 drm_put_dev(dev_get_drvdata(dev));
345}
346
347static int compare_of(struct device *dev, void *data)
348{
349 return dev->of_node == data;
350}
351
352static int compare_dev_name(struct device *dev, void *data)
353{
354 const char *name = data;
355 return !strcmp(dev_name(dev), name);
356}
357
358static void armada_add_endpoints(struct device *dev,
359 struct component_match **match, struct device_node *port)
360{
361 struct device_node *ep, *remote;
362
363 for_each_child_of_node(port, ep) {
364 remote = of_graph_get_remote_port_parent(ep);
365 if (!remote || !of_device_is_available(remote)) {
366 of_node_put(remote);
367 continue;
368 } else if (!of_device_is_available(remote->parent)) {
369 dev_warn(dev, "parent device of %s is not available\n",
370 remote->full_name);
371 of_node_put(remote);
372 continue;
373 }
374
375 component_match_add(dev, match, compare_of, remote);
376 of_node_put(remote);
377 }
378}
379
380static int armada_drm_find_components(struct device *dev,
381 struct component_match **match)
382{
383 struct device_node *port;
384 int i;
385
386 if (dev->of_node) {
387 struct device_node *np = dev->of_node;
388
389 for (i = 0; ; i++) {
390 port = of_parse_phandle(np, "ports", i);
391 if (!port)
392 break;
393
394 component_match_add(dev, match, compare_of, port);
395 of_node_put(port);
396 }
397
398 if (i == 0) {
399 dev_err(dev, "missing 'ports' property\n");
400 return -ENODEV;
401 }
402
403 for (i = 0; ; i++) {
404 port = of_parse_phandle(np, "ports", i);
405 if (!port)
406 break;
407
408 armada_add_endpoints(dev, match, port);
409 of_node_put(port);
410 }
411 } else if (dev->platform_data) {
412 char **devices = dev->platform_data;
413 struct device *d;
414
415 for (i = 0; devices[i]; i++)
416 component_match_add(dev, match, compare_dev_name,
417 devices[i]);
418
419 if (i == 0) {
420 dev_err(dev, "missing 'ports' property\n");
421 return -ENODEV;
422 }
423
424 for (i = 0; devices[i]; i++) {
425 d = bus_find_device_by_name(&platform_bus_type, NULL,
426 devices[i]);
427 if (d && d->of_node) {
428 for_each_child_of_node(d->of_node, port)
429 armada_add_endpoints(dev, match, port);
430 }
431 put_device(d);
432 }
433 }
434
435 return 0;
436}
437
438static const struct component_master_ops armada_master_ops = {
439 .bind = armada_drm_bind,
440 .unbind = armada_drm_unbind,
441};
442
317static int armada_drm_probe(struct platform_device *pdev) 443static int armada_drm_probe(struct platform_device *pdev)
318{ 444{
319 return drm_platform_init(&armada_drm_driver, pdev); 445 if (is_componentized(&pdev->dev)) {
446 struct component_match *match = NULL;
447 int ret;
448
449 ret = armada_drm_find_components(&pdev->dev, &match);
450 if (ret < 0)
451 return ret;
452
453 return component_master_add_with_match(&pdev->dev,
454 &armada_master_ops, match);
455 } else {
456 return drm_platform_init(&armada_drm_driver, pdev);
457 }
320} 458}
321 459
322static int armada_drm_remove(struct platform_device *pdev) 460static int armada_drm_remove(struct platform_device *pdev)
323{ 461{
324 drm_put_dev(platform_get_drvdata(pdev)); 462 if (is_componentized(&pdev->dev))
463 component_master_del(&pdev->dev, &armada_master_ops);
464 else
465 drm_put_dev(platform_get_drvdata(pdev));
325 return 0; 466 return 0;
326} 467}
327 468