summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/tilcdc/tilcdc_drv.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/tilcdc/tilcdc_drv.c')
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c85
1 files changed, 72 insertions, 13 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 0f1e09986f56..fcc0508c58c0 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -17,10 +17,13 @@
/* 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_panel.h"
+#include "tilcdc_external.h"
#include "drm_fb_helper.h"
@@ -73,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);
@@ -114,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);
@@ -164,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;
@@ -253,10 +254,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);
@@ -267,9 +286,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;
@@ -300,6 +316,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
@@ -605,20 +628,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;
}
- 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;
}