diff options
-rw-r--r-- | drivers/gpu/drm/armada/armada_drv.c | 155 |
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 | ||
57 | static bool is_componentized(struct device *dev) | ||
58 | { | ||
59 | return dev->of_node || dev->platform_data; | ||
60 | } | ||
61 | |||
55 | static void armada_drm_unref_work(struct work_struct *work) | 62 | static 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 | ||
337 | static int armada_drm_bind(struct device *dev) | ||
338 | { | ||
339 | return drm_platform_init(&armada_drm_driver, to_platform_device(dev)); | ||
340 | } | ||
341 | |||
342 | static void armada_drm_unbind(struct device *dev) | ||
343 | { | ||
344 | drm_put_dev(dev_get_drvdata(dev)); | ||
345 | } | ||
346 | |||
347 | static int compare_of(struct device *dev, void *data) | ||
348 | { | ||
349 | return dev->of_node == data; | ||
350 | } | ||
351 | |||
352 | static int compare_dev_name(struct device *dev, void *data) | ||
353 | { | ||
354 | const char *name = data; | ||
355 | return !strcmp(dev_name(dev), name); | ||
356 | } | ||
357 | |||
358 | static 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 | |||
380 | static 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 | |||
438 | static const struct component_master_ops armada_master_ops = { | ||
439 | .bind = armada_drm_bind, | ||
440 | .unbind = armada_drm_unbind, | ||
441 | }; | ||
442 | |||
317 | static int armada_drm_probe(struct platform_device *pdev) | 443 | static 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 | ||
322 | static int armada_drm_remove(struct platform_device *pdev) | 460 | static 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 | ||