aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu')
-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