diff options
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c')
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 99 |
1 files changed, 73 insertions, 26 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c index 095fca91525c..0f283a3b932c 100644 --- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c +++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c | |||
@@ -17,16 +17,17 @@ | |||
17 | 17 | ||
18 | /* LCDC DRM driver, based on da8xx-fb */ | 18 | /* LCDC DRM driver, based on da8xx-fb */ |
19 | 19 | ||
20 | #include <linux/component.h> | ||
21 | |||
20 | #include "tilcdc_drv.h" | 22 | #include "tilcdc_drv.h" |
21 | #include "tilcdc_regs.h" | 23 | #include "tilcdc_regs.h" |
22 | #include "tilcdc_tfp410.h" | 24 | #include "tilcdc_tfp410.h" |
23 | #include "tilcdc_slave.h" | ||
24 | #include "tilcdc_panel.h" | 25 | #include "tilcdc_panel.h" |
26 | #include "tilcdc_external.h" | ||
25 | 27 | ||
26 | #include "drm_fb_helper.h" | 28 | #include "drm_fb_helper.h" |
27 | 29 | ||
28 | static LIST_HEAD(module_list); | 30 | static LIST_HEAD(module_list); |
29 | static bool slave_probing; | ||
30 | 31 | ||
31 | void tilcdc_module_init(struct tilcdc_module *mod, const char *name, | 32 | void tilcdc_module_init(struct tilcdc_module *mod, const char *name, |
32 | const struct tilcdc_module_ops *funcs) | 33 | const struct tilcdc_module_ops *funcs) |
@@ -42,11 +43,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod) | |||
42 | list_del(&mod->list); | 43 | list_del(&mod->list); |
43 | } | 44 | } |
44 | 45 | ||
45 | void tilcdc_slave_probedefer(bool defered) | ||
46 | { | ||
47 | slave_probing = defered; | ||
48 | } | ||
49 | |||
50 | static struct of_device_id tilcdc_of_match[]; | 46 | static struct of_device_id tilcdc_of_match[]; |
51 | 47 | ||
52 | static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, | 48 | static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev, |
@@ -80,13 +76,6 @@ static int modeset_init(struct drm_device *dev) | |||
80 | mod->funcs->modeset_init(mod, dev); | 76 | mod->funcs->modeset_init(mod, dev); |
81 | } | 77 | } |
82 | 78 | ||
83 | if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { | ||
84 | /* oh nos! */ | ||
85 | dev_err(dev->dev, "no encoders/connectors found\n"); | ||
86 | drm_mode_config_cleanup(dev); | ||
87 | return -ENXIO; | ||
88 | } | ||
89 | |||
90 | dev->mode_config.min_width = 0; | 79 | dev->mode_config.min_width = 0; |
91 | dev->mode_config.min_height = 0; | 80 | dev->mode_config.min_height = 0; |
92 | dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc); | 81 | dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc); |
@@ -121,6 +110,8 @@ static int tilcdc_unload(struct drm_device *dev) | |||
121 | { | 110 | { |
122 | struct tilcdc_drm_private *priv = dev->dev_private; | 111 | struct tilcdc_drm_private *priv = dev->dev_private; |
123 | 112 | ||
113 | tilcdc_remove_external_encoders(dev); | ||
114 | |||
124 | drm_fbdev_cma_fini(priv->fbdev); | 115 | drm_fbdev_cma_fini(priv->fbdev); |
125 | drm_kms_helper_poll_fini(dev); | 116 | drm_kms_helper_poll_fini(dev); |
126 | drm_mode_config_cleanup(dev); | 117 | drm_mode_config_cleanup(dev); |
@@ -171,6 +162,9 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
171 | 162 | ||
172 | dev->dev_private = priv; | 163 | dev->dev_private = priv; |
173 | 164 | ||
165 | priv->is_componentized = | ||
166 | tilcdc_get_external_components(dev->dev, NULL) > 0; | ||
167 | |||
174 | priv->wq = alloc_ordered_workqueue("tilcdc", 0); | 168 | priv->wq = alloc_ordered_workqueue("tilcdc", 0); |
175 | if (!priv->wq) { | 169 | if (!priv->wq) { |
176 | ret = -ENOMEM; | 170 | ret = -ENOMEM; |
@@ -233,6 +227,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
233 | DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); | 227 | DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock); |
234 | 228 | ||
235 | pm_runtime_enable(dev->dev); | 229 | pm_runtime_enable(dev->dev); |
230 | pm_runtime_irq_safe(dev->dev); | ||
236 | 231 | ||
237 | /* Determine LCD IP Version */ | 232 | /* Determine LCD IP Version */ |
238 | pm_runtime_get_sync(dev->dev); | 233 | pm_runtime_get_sync(dev->dev); |
@@ -260,10 +255,28 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
260 | goto fail_cpufreq_unregister; | 255 | goto fail_cpufreq_unregister; |
261 | } | 256 | } |
262 | 257 | ||
258 | platform_set_drvdata(pdev, dev); | ||
259 | |||
260 | if (priv->is_componentized) { | ||
261 | ret = component_bind_all(dev->dev, dev); | ||
262 | if (ret < 0) | ||
263 | goto fail_mode_config_cleanup; | ||
264 | |||
265 | ret = tilcdc_add_external_encoders(dev, &bpp); | ||
266 | if (ret < 0) | ||
267 | goto fail_component_cleanup; | ||
268 | } | ||
269 | |||
270 | if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) { | ||
271 | dev_err(dev->dev, "no encoders/connectors found\n"); | ||
272 | ret = -ENXIO; | ||
273 | goto fail_external_cleanup; | ||
274 | } | ||
275 | |||
263 | ret = drm_vblank_init(dev, 1); | 276 | ret = drm_vblank_init(dev, 1); |
264 | if (ret < 0) { | 277 | if (ret < 0) { |
265 | dev_err(dev->dev, "failed to initialize vblank\n"); | 278 | dev_err(dev->dev, "failed to initialize vblank\n"); |
266 | goto fail_mode_config_cleanup; | 279 | goto fail_external_cleanup; |
267 | } | 280 | } |
268 | 281 | ||
269 | pm_runtime_get_sync(dev->dev); | 282 | pm_runtime_get_sync(dev->dev); |
@@ -274,9 +287,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags) | |||
274 | goto fail_vblank_cleanup; | 287 | goto fail_vblank_cleanup; |
275 | } | 288 | } |
276 | 289 | ||
277 | platform_set_drvdata(pdev, dev); | ||
278 | |||
279 | |||
280 | list_for_each_entry(mod, &module_list, list) { | 290 | list_for_each_entry(mod, &module_list, list) { |
281 | DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); | 291 | DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp); |
282 | bpp = mod->preferred_bpp; | 292 | bpp = mod->preferred_bpp; |
@@ -307,6 +317,13 @@ fail_vblank_cleanup: | |||
307 | fail_mode_config_cleanup: | 317 | fail_mode_config_cleanup: |
308 | drm_mode_config_cleanup(dev); | 318 | drm_mode_config_cleanup(dev); |
309 | 319 | ||
320 | fail_component_cleanup: | ||
321 | if (priv->is_componentized) | ||
322 | component_unbind_all(dev->dev, dev); | ||
323 | |||
324 | fail_external_cleanup: | ||
325 | tilcdc_remove_external_encoders(dev); | ||
326 | |||
310 | fail_cpufreq_unregister: | 327 | fail_cpufreq_unregister: |
311 | pm_runtime_disable(dev->dev); | 328 | pm_runtime_disable(dev->dev); |
312 | #ifdef CONFIG_CPU_FREQ | 329 | #ifdef CONFIG_CPU_FREQ |
@@ -612,24 +629,56 @@ static const struct dev_pm_ops tilcdc_pm_ops = { | |||
612 | * Platform driver: | 629 | * Platform driver: |
613 | */ | 630 | */ |
614 | 631 | ||
632 | static int tilcdc_bind(struct device *dev) | ||
633 | { | ||
634 | return drm_platform_init(&tilcdc_driver, to_platform_device(dev)); | ||
635 | } | ||
636 | |||
637 | static void tilcdc_unbind(struct device *dev) | ||
638 | { | ||
639 | drm_put_dev(dev_get_drvdata(dev)); | ||
640 | } | ||
641 | |||
642 | static const struct component_master_ops tilcdc_comp_ops = { | ||
643 | .bind = tilcdc_bind, | ||
644 | .unbind = tilcdc_unbind, | ||
645 | }; | ||
646 | |||
615 | static int tilcdc_pdev_probe(struct platform_device *pdev) | 647 | static int tilcdc_pdev_probe(struct platform_device *pdev) |
616 | { | 648 | { |
649 | struct component_match *match = NULL; | ||
650 | int ret; | ||
651 | |||
617 | /* bail out early if no DT data: */ | 652 | /* bail out early if no DT data: */ |
618 | if (!pdev->dev.of_node) { | 653 | if (!pdev->dev.of_node) { |
619 | dev_err(&pdev->dev, "device-tree data is missing\n"); | 654 | dev_err(&pdev->dev, "device-tree data is missing\n"); |
620 | return -ENXIO; | 655 | return -ENXIO; |
621 | } | 656 | } |
622 | 657 | ||
623 | /* defer probing if slave is in deferred probing */ | 658 | ret = tilcdc_get_external_components(&pdev->dev, &match); |
624 | if (slave_probing == true) | 659 | if (ret < 0) |
625 | return -EPROBE_DEFER; | 660 | return ret; |
626 | 661 | else if (ret == 0) | |
627 | return drm_platform_init(&tilcdc_driver, pdev); | 662 | return drm_platform_init(&tilcdc_driver, pdev); |
663 | else | ||
664 | return component_master_add_with_match(&pdev->dev, | ||
665 | &tilcdc_comp_ops, | ||
666 | match); | ||
628 | } | 667 | } |
629 | 668 | ||
630 | static int tilcdc_pdev_remove(struct platform_device *pdev) | 669 | static int tilcdc_pdev_remove(struct platform_device *pdev) |
631 | { | 670 | { |
632 | drm_put_dev(platform_get_drvdata(pdev)); | 671 | struct drm_device *ddev = dev_get_drvdata(&pdev->dev); |
672 | struct tilcdc_drm_private *priv = ddev->dev_private; | ||
673 | |||
674 | /* Check if a subcomponent has already triggered the unloading. */ | ||
675 | if (!priv) | ||
676 | return 0; | ||
677 | |||
678 | if (priv->is_componentized) | ||
679 | component_master_del(&pdev->dev, &tilcdc_comp_ops); | ||
680 | else | ||
681 | drm_put_dev(platform_get_drvdata(pdev)); | ||
633 | 682 | ||
634 | return 0; | 683 | return 0; |
635 | } | 684 | } |
@@ -654,7 +703,6 @@ static int __init tilcdc_drm_init(void) | |||
654 | { | 703 | { |
655 | DBG("init"); | 704 | DBG("init"); |
656 | tilcdc_tfp410_init(); | 705 | tilcdc_tfp410_init(); |
657 | tilcdc_slave_init(); | ||
658 | tilcdc_panel_init(); | 706 | tilcdc_panel_init(); |
659 | return platform_driver_register(&tilcdc_platform_driver); | 707 | return platform_driver_register(&tilcdc_platform_driver); |
660 | } | 708 | } |
@@ -664,7 +712,6 @@ static void __exit tilcdc_drm_fini(void) | |||
664 | DBG("fini"); | 712 | DBG("fini"); |
665 | platform_driver_unregister(&tilcdc_platform_driver); | 713 | platform_driver_unregister(&tilcdc_platform_driver); |
666 | tilcdc_panel_fini(); | 714 | tilcdc_panel_fini(); |
667 | tilcdc_slave_fini(); | ||
668 | tilcdc_tfp410_fini(); | 715 | tilcdc_tfp410_fini(); |
669 | } | 716 | } |
670 | 717 | ||