These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / gpu / drm / tilcdc / tilcdc_drv.c
index 095fca9..876cad5 100644 (file)
 
 /* LCDC DRM driver, based on da8xx-fb */
 
+#include <linux/component.h>
+
 #include "tilcdc_drv.h"
 #include "tilcdc_regs.h"
 #include "tilcdc_tfp410.h"
-#include "tilcdc_slave.h"
 #include "tilcdc_panel.h"
+#include "tilcdc_external.h"
 
 #include "drm_fb_helper.h"
 
 static LIST_HEAD(module_list);
-static bool slave_probing;
 
 void tilcdc_module_init(struct tilcdc_module *mod, const char *name,
                const struct tilcdc_module_ops *funcs)
@@ -42,11 +43,6 @@ void tilcdc_module_cleanup(struct tilcdc_module *mod)
        list_del(&mod->list);
 }
 
-void tilcdc_slave_probedefer(bool defered)
-{
-       slave_probing = defered;
-}
-
 static struct of_device_id tilcdc_of_match[];
 
 static struct drm_framebuffer *tilcdc_fb_create(struct drm_device *dev,
@@ -80,13 +76,6 @@ static int modeset_init(struct drm_device *dev)
                mod->funcs->modeset_init(mod, dev);
        }
 
-       if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
-               /* oh nos! */
-               dev_err(dev->dev, "no encoders/connectors found\n");
-               drm_mode_config_cleanup(dev);
-               return -ENXIO;
-       }
-
        dev->mode_config.min_width = 0;
        dev->mode_config.min_height = 0;
        dev->mode_config.max_width = tilcdc_crtc_max_width(priv->crtc);
@@ -121,6 +110,8 @@ static int tilcdc_unload(struct drm_device *dev)
 {
        struct tilcdc_drm_private *priv = dev->dev_private;
 
+       tilcdc_remove_external_encoders(dev);
+
        drm_fbdev_cma_fini(priv->fbdev);
        drm_kms_helper_poll_fini(dev);
        drm_mode_config_cleanup(dev);
@@ -171,6 +162,9 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = priv;
 
+       priv->is_componentized =
+               tilcdc_get_external_components(dev->dev, NULL) > 0;
+
        priv->wq = alloc_ordered_workqueue("tilcdc", 0);
        if (!priv->wq) {
                ret = -ENOMEM;
@@ -233,6 +227,7 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
        DBG("Maximum Pixel Clock Value %dKHz", priv->max_pixelclock);
 
        pm_runtime_enable(dev->dev);
+       pm_runtime_irq_safe(dev->dev);
 
        /* Determine LCD IP Version */
        pm_runtime_get_sync(dev->dev);
@@ -260,10 +255,28 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                goto fail_cpufreq_unregister;
        }
 
+       platform_set_drvdata(pdev, dev);
+
+       if (priv->is_componentized) {
+               ret = component_bind_all(dev->dev, dev);
+               if (ret < 0)
+                       goto fail_mode_config_cleanup;
+
+               ret = tilcdc_add_external_encoders(dev, &bpp);
+               if (ret < 0)
+                       goto fail_component_cleanup;
+       }
+
+       if ((priv->num_encoders == 0) || (priv->num_connectors == 0)) {
+               dev_err(dev->dev, "no encoders/connectors found\n");
+               ret = -ENXIO;
+               goto fail_external_cleanup;
+       }
+
        ret = drm_vblank_init(dev, 1);
        if (ret < 0) {
                dev_err(dev->dev, "failed to initialize vblank\n");
-               goto fail_mode_config_cleanup;
+               goto fail_external_cleanup;
        }
 
        pm_runtime_get_sync(dev->dev);
@@ -274,9 +287,6 @@ static int tilcdc_load(struct drm_device *dev, unsigned long flags)
                goto fail_vblank_cleanup;
        }
 
-       platform_set_drvdata(pdev, dev);
-
-
        list_for_each_entry(mod, &module_list, list) {
                DBG("%s: preferred_bpp: %d", mod->name, mod->preferred_bpp);
                bpp = mod->preferred_bpp;
@@ -307,6 +317,13 @@ fail_vblank_cleanup:
 fail_mode_config_cleanup:
        drm_mode_config_cleanup(dev);
 
+fail_component_cleanup:
+       if (priv->is_componentized)
+               component_unbind_all(dev->dev, dev);
+
+fail_external_cleanup:
+       tilcdc_remove_external_encoders(dev);
+
 fail_cpufreq_unregister:
        pm_runtime_disable(dev->dev);
 #ifdef CONFIG_CPU_FREQ
@@ -408,13 +425,13 @@ static void enable_vblank(struct drm_device *dev, bool enable)
                tilcdc_clear(dev, reg, mask);
 }
 
-static int tilcdc_enable_vblank(struct drm_device *dev, int crtc)
+static int tilcdc_enable_vblank(struct drm_device *dev, unsigned int pipe)
 {
        enable_vblank(dev, true);
        return 0;
 }
 
-static void tilcdc_disable_vblank(struct drm_device *dev, int crtc)
+static void tilcdc_disable_vblank(struct drm_device *dev, unsigned int pipe)
 {
        enable_vblank(dev, false);
 }
@@ -546,7 +563,7 @@ static struct drm_driver tilcdc_driver = {
        .irq_preinstall     = tilcdc_irq_preinstall,
        .irq_postinstall    = tilcdc_irq_postinstall,
        .irq_uninstall      = tilcdc_irq_uninstall,
-       .get_vblank_counter = drm_vblank_count,
+       .get_vblank_counter = drm_vblank_no_hw_counter,
        .enable_vblank      = tilcdc_enable_vblank,
        .disable_vblank     = tilcdc_disable_vblank,
        .gem_free_object    = drm_gem_cma_free_object,
@@ -612,24 +629,56 @@ static const struct dev_pm_ops tilcdc_pm_ops = {
  * Platform driver:
  */
 
+static int tilcdc_bind(struct device *dev)
+{
+       return drm_platform_init(&tilcdc_driver, to_platform_device(dev));
+}
+
+static void tilcdc_unbind(struct device *dev)
+{
+       drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops tilcdc_comp_ops = {
+       .bind = tilcdc_bind,
+       .unbind = tilcdc_unbind,
+};
+
 static int tilcdc_pdev_probe(struct platform_device *pdev)
 {
+       struct component_match *match = NULL;
+       int ret;
+
        /* bail out early if no DT data: */
        if (!pdev->dev.of_node) {
                dev_err(&pdev->dev, "device-tree data is missing\n");
                return -ENXIO;
        }
 
-       /* defer probing if slave is in deferred probing */
-       if (slave_probing == true)
-               return -EPROBE_DEFER;
-
-       return drm_platform_init(&tilcdc_driver, pdev);
+       ret = tilcdc_get_external_components(&pdev->dev, &match);
+       if (ret < 0)
+               return ret;
+       else if (ret == 0)
+               return drm_platform_init(&tilcdc_driver, pdev);
+       else
+               return component_master_add_with_match(&pdev->dev,
+                                                      &tilcdc_comp_ops,
+                                                      match);
 }
 
 static int tilcdc_pdev_remove(struct platform_device *pdev)
 {
-       drm_put_dev(platform_get_drvdata(pdev));
+       struct drm_device *ddev = dev_get_drvdata(&pdev->dev);
+       struct tilcdc_drm_private *priv = ddev->dev_private;
+
+       /* Check if a subcomponent has already triggered the unloading. */
+       if (!priv)
+               return 0;
+
+       if (priv->is_componentized)
+               component_master_del(&pdev->dev, &tilcdc_comp_ops);
+       else
+               drm_put_dev(platform_get_drvdata(pdev));
 
        return 0;
 }
@@ -654,7 +703,6 @@ static int __init tilcdc_drm_init(void)
 {
        DBG("init");
        tilcdc_tfp410_init();
-       tilcdc_slave_init();
        tilcdc_panel_init();
        return platform_driver_register(&tilcdc_platform_driver);
 }
@@ -664,7 +712,6 @@ static void __exit tilcdc_drm_fini(void)
        DBG("fini");
        platform_driver_unregister(&tilcdc_platform_driver);
        tilcdc_panel_fini();
-       tilcdc_slave_fini();
        tilcdc_tfp410_fini();
 }