imx-drm: convert to componentised device support
[deliverable/linux.git] / drivers / staging / imx-drm / imx-drm-core.c
index 09ef5fb8bae6f9cb4b99f936b2fcb52739f9edd9..82b0337096b073803c456240f949af34d6424e4f 100644 (file)
@@ -13,7 +13,7 @@
  * GNU General Public License for more details.
  *
  */
-
+#include <linux/component.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <drm/drmP.h>
@@ -34,10 +34,12 @@ struct crtc_cookie {
        struct list_head list;
 };
 
+struct imx_drm_crtc;
+
 struct imx_drm_device {
        struct drm_device                       *drm;
        struct device                           *dev;
-       struct list_head                        crtc_list;
+       struct imx_drm_crtc                     *crtc[MAX_CRTC];
        struct list_head                        encoder_list;
        struct list_head                        connector_list;
        struct mutex                            mutex;
@@ -47,12 +49,12 @@ struct imx_drm_device {
 
 struct imx_drm_crtc {
        struct drm_crtc                         *crtc;
-       struct list_head                        list;
        struct imx_drm_device                   *imxdrm;
        int                                     pipe;
        struct imx_drm_crtc_helper_funcs        imx_drm_helper_funcs;
        struct module                           *owner;
        struct crtc_cookie                      cookie;
+       int                                     mux_id;
 };
 
 struct imx_drm_encoder {
@@ -68,6 +70,8 @@ struct imx_drm_connector {
        struct module                           *owner;
 };
 
+static struct imx_drm_device *__imx_drm_device(void);
+
 int imx_drm_crtc_id(struct imx_drm_crtc *crtc)
 {
        return crtc->pipe;
@@ -86,85 +90,78 @@ static int imx_drm_driver_unload(struct drm_device *drm)
 {
        struct imx_drm_device *imxdrm = drm->dev_private;
 
+       component_unbind_all(drm->dev, drm);
+
        imx_drm_device_put();
 
-       drm_vblank_cleanup(imxdrm->drm);
-       drm_kms_helper_poll_fini(imxdrm->drm);
-       drm_mode_config_cleanup(imxdrm->drm);
+       drm_vblank_cleanup(drm);
+       drm_kms_helper_poll_fini(drm);
+       drm_mode_config_cleanup(drm);
 
        return 0;
 }
 
-/*
- * We don't care at all for crtc numbers, but the core expects the
- * crtcs to be numbered
- */
-static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm,
-               int num)
+struct imx_drm_crtc *imx_drm_find_crtc(struct drm_crtc *crtc)
 {
-       struct imx_drm_crtc *imx_drm_crtc;
+       struct imx_drm_device *imxdrm = __imx_drm_device();
+       unsigned i;
+
+       for (i = 0; i < MAX_CRTC; i++)
+               if (imxdrm->crtc[i] && imxdrm->crtc[i]->crtc == crtc)
+                       return imxdrm->crtc[i];
 
-       list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list)
-               if (imx_drm_crtc->pipe == num)
-                       return imx_drm_crtc;
        return NULL;
 }
 
-int imx_drm_crtc_panel_format_pins(struct drm_crtc *crtc, u32 encoder_type,
+int imx_drm_panel_format_pins(struct drm_encoder *encoder,
                u32 interface_pix_fmt, int hsync_pin, int vsync_pin)
 {
-       struct imx_drm_device *imxdrm = crtc->dev->dev_private;
-       struct imx_drm_crtc *imx_crtc;
        struct imx_drm_crtc_helper_funcs *helper;
+       struct imx_drm_crtc *imx_crtc;
 
-       list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list)
-               if (imx_crtc->crtc == crtc)
-                       goto found;
+       imx_crtc = imx_drm_find_crtc(encoder->crtc);
+       if (!imx_crtc)
+               return -EINVAL;
 
-       return -EINVAL;
-found:
        helper = &imx_crtc->imx_drm_helper_funcs;
        if (helper->set_interface_pix_fmt)
-               return helper->set_interface_pix_fmt(crtc,
-                               encoder_type, interface_pix_fmt,
+               return helper->set_interface_pix_fmt(encoder->crtc,
+                               encoder->encoder_type, interface_pix_fmt,
                                hsync_pin, vsync_pin);
        return 0;
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format_pins);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
 
-int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type,
-               u32 interface_pix_fmt)
+int imx_drm_panel_format(struct drm_encoder *encoder, u32 interface_pix_fmt)
 {
-       return imx_drm_crtc_panel_format_pins(crtc, encoder_type,
-                                             interface_pix_fmt, 2, 3);
+       return imx_drm_panel_format_pins(encoder, interface_pix_fmt, 2, 3);
 }
-EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format);
+EXPORT_SYMBOL_GPL(imx_drm_panel_format);
 
 int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc)
 {
-       return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       return drm_vblank_get(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get);
 
 void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc)
 {
-       drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       drm_vblank_put(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put);
 
 void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc)
 {
-       drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe);
+       drm_handle_vblank(imx_drm_crtc->crtc->dev, imx_drm_crtc->pipe);
 }
 EXPORT_SYMBOL_GPL(imx_drm_handle_vblank);
 
 static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 {
        struct imx_drm_device *imxdrm = drm->dev_private;
-       struct imx_drm_crtc *imx_drm_crtc;
+       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
        int ret;
 
-       imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
        if (!imx_drm_crtc)
                return -EINVAL;
 
@@ -180,9 +177,8 @@ static int imx_drm_enable_vblank(struct drm_device *drm, int crtc)
 static void imx_drm_disable_vblank(struct drm_device *drm, int crtc)
 {
        struct imx_drm_device *imxdrm = drm->dev_private;
-       struct imx_drm_crtc *imx_drm_crtc;
+       struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[crtc];
 
-       imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc);
        if (!imx_drm_crtc)
                return;
 
@@ -215,6 +211,13 @@ static const struct file_operations imx_drm_driver_fops = {
        .llseek = noop_llseek,
 };
 
+int imx_drm_connector_mode_valid(struct drm_connector *connector,
+       struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+EXPORT_SYMBOL(imx_drm_connector_mode_valid);
+
 static struct imx_drm_device *imx_drm_device;
 
 static struct imx_drm_device *__imx_drm_device(void)
@@ -370,34 +373,8 @@ static void imx_drm_connector_unregister(
 }
 
 /*
- * register a crtc to the drm core
- */
-static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc)
-{
-       struct imx_drm_device *imxdrm = __imx_drm_device();
-       int ret;
-
-       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
-       if (ret)
-               return ret;
-
-       drm_crtc_helper_add(imx_drm_crtc->crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
-
-       drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc,
-                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
-
-       drm_mode_group_reinit(imxdrm->drm);
-
-       return 0;
-}
-
-/*
- * Called by the CRTC driver when all CRTCs are registered. This
- * puts all the pieces together and initializes the driver.
- * Once this is called no more CRTCs can be registered since
- * the drm core has hardcoded the number of crtcs in several
- * places.
+ * Main DRM initialisation. This binds, initialises and registers
+ * with DRM the subcomponents of the driver.
  */
 static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 {
@@ -424,15 +401,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
        mutex_lock(&imxdrm->mutex);
 
-       drm_kms_helper_poll_init(imxdrm->drm);
+       drm_kms_helper_poll_init(drm);
 
        /* setup the grouping for the legacy output */
-       ret = drm_mode_group_init_legacy_group(imxdrm->drm,
-                       &imxdrm->drm->primary->mode_group);
+       ret = drm_mode_group_init_legacy_group(drm,
+                       &drm->primary->mode_group);
        if (ret)
                goto err_kms;
 
-       ret = drm_vblank_init(imxdrm->drm, MAX_CRTC);
+       ret = drm_vblank_init(drm, MAX_CRTC);
        if (ret)
                goto err_kms;
 
@@ -441,7 +418,7 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
         * by drm timer once a current process gives up ownership of
         * vblank event.(after drm_vblank_put function is called)
         */
-       imxdrm->drm->vblank_disable_allowed = true;
+       drm->vblank_disable_allowed = true;
 
        if (!imx_drm_device_get()) {
                ret = -EINVAL;
@@ -450,8 +427,15 @@ static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags)
 
        platform_set_drvdata(drm->platformdev, drm);
        mutex_unlock(&imxdrm->mutex);
+
+       /* Now try and bind all our sub-components */
+       ret = component_bind_all(drm->dev, drm);
+       if (ret)
+               goto err_relock;
        return 0;
 
+err_relock:
+       mutex_lock(&imxdrm->mutex);
 err_vblank:
        drm_vblank_cleanup(drm);
 err_kms:
@@ -526,20 +510,28 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
        imx_drm_crtc->pipe = imxdrm->pipes++;
        imx_drm_crtc->cookie.cookie = cookie;
        imx_drm_crtc->cookie.id = id;
-
+       imx_drm_crtc->mux_id = imx_drm_crtc->pipe;
        imx_drm_crtc->crtc = crtc;
        imx_drm_crtc->imxdrm = imxdrm;
 
        imx_drm_crtc->owner = owner;
 
-       list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list);
+       imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
 
        *new_crtc = imx_drm_crtc;
 
-       ret = imx_drm_crtc_register(imx_drm_crtc);
+       ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256);
        if (ret)
                goto err_register;
 
+       drm_crtc_helper_add(crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs);
+
+       drm_crtc_init(imxdrm->drm, crtc,
+                       imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs);
+
+       drm_mode_group_reinit(imxdrm->drm);
+
        imx_drm_update_possible_crtcs();
 
        mutex_unlock(&imxdrm->mutex);
@@ -547,7 +539,7 @@ int imx_drm_add_crtc(struct drm_crtc *crtc,
        return 0;
 
 err_register:
-       list_del(&imx_drm_crtc->list);
+       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
        kfree(imx_drm_crtc);
 err_alloc:
 err_busy:
@@ -567,7 +559,7 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
 
        drm_crtc_cleanup(imx_drm_crtc->crtc);
 
-       list_del(&imx_drm_crtc->list);
+       imxdrm->crtc[imx_drm_crtc->pipe] = NULL;
 
        drm_mode_group_reinit(imxdrm->drm);
 
@@ -672,22 +664,11 @@ int imx_drm_encoder_add_possible_crtcs(
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs);
 
-int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder,
-               struct drm_crtc *crtc)
+int imx_drm_encoder_get_mux_id(struct drm_encoder *encoder)
 {
-       struct imx_drm_device *imxdrm = __imx_drm_device();
-       struct imx_drm_crtc *imx_crtc;
-       int i = 0;
-
-       list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) {
-               if (imx_crtc->crtc == crtc)
-                       goto found;
-               i++;
-       }
+       struct imx_drm_crtc *imx_crtc = imx_drm_find_crtc(encoder->crtc);
 
-       return -EINVAL;
-found:
-       return i;
+       return imx_crtc ? imx_crtc->mux_id : -EINVAL;
 }
 EXPORT_SYMBOL_GPL(imx_drm_encoder_get_mux_id);
 
@@ -834,6 +815,70 @@ static struct drm_driver imx_drm_driver = {
        .patchlevel             = 0,
 };
 
+static int compare_parent_of(struct device *dev, void *data)
+{
+       struct of_phandle_args *args = data;
+       return dev->parent && dev->parent->of_node == args->np;
+}
+
+static int compare_of(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int imx_drm_add_components(struct device *master, struct master *m)
+{
+       struct device_node *np = master->of_node;
+       unsigned i;
+       int ret;
+
+       for (i = 0; ; i++) {
+               struct of_phandle_args args;
+
+               ret = of_parse_phandle_with_fixed_args(np, "crtcs", 1,
+                                                      i, &args);
+               if (ret)
+                       break;
+
+               ret = component_master_add_child(m, compare_parent_of, &args);
+               of_node_put(args.np);
+
+               if (ret)
+                       return ret;
+       }
+
+       for (i = 0; ; i++) {
+               struct device_node *node;
+
+               node = of_parse_phandle(np, "connectors", i);
+               if (!node)
+                       break;
+
+               ret = component_master_add_child(m, compare_of, node);
+               of_node_put(node);
+
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+static int imx_drm_bind(struct device *dev)
+{
+       return drm_platform_init(&imx_drm_driver, to_platform_device(dev));
+}
+
+static void imx_drm_unbind(struct device *dev)
+{
+       drm_put_dev(dev_get_drvdata(dev));
+}
+
+static const struct component_master_ops imx_drm_ops = {
+       .add_components = imx_drm_add_components,
+       .bind = imx_drm_bind,
+       .unbind = imx_drm_unbind,
+};
+
 static int imx_drm_platform_probe(struct platform_device *pdev)
 {
        int ret;
@@ -844,27 +889,31 @@ static int imx_drm_platform_probe(struct platform_device *pdev)
 
        imx_drm_device->dev = &pdev->dev;
 
-       return drm_platform_init(&imx_drm_driver, pdev);
+       return component_master_add(&pdev->dev, &imx_drm_ops);
 }
 
 static int imx_drm_platform_remove(struct platform_device *pdev)
 {
-       drm_put_dev(platform_get_drvdata(pdev));
-
+       component_master_del(&pdev->dev, &imx_drm_ops);
        return 0;
 }
 
+static const struct of_device_id imx_drm_dt_ids[] = {
+       { .compatible = "fsl,imx-drm", },
+       { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, imx_drm_dt_ids);
+
 static struct platform_driver imx_drm_pdrv = {
        .probe          = imx_drm_platform_probe,
        .remove         = imx_drm_platform_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "imx-drm",
+               .of_match_table = imx_drm_dt_ids,
        },
 };
 
-static struct platform_device *imx_drm_pdev;
-
 static int __init imx_drm_init(void)
 {
        int ret;
@@ -874,16 +923,9 @@ static int __init imx_drm_init(void)
                return -ENOMEM;
 
        mutex_init(&imx_drm_device->mutex);
-       INIT_LIST_HEAD(&imx_drm_device->crtc_list);
        INIT_LIST_HEAD(&imx_drm_device->connector_list);
        INIT_LIST_HEAD(&imx_drm_device->encoder_list);
 
-       imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0);
-       if (IS_ERR(imx_drm_pdev)) {
-               ret = PTR_ERR(imx_drm_pdev);
-               goto err_pdev;
-       }
-
        ret = platform_driver_register(&imx_drm_pdrv);
        if (ret)
                goto err_pdrv;
@@ -891,8 +933,6 @@ static int __init imx_drm_init(void)
        return 0;
 
 err_pdrv:
-       platform_device_unregister(imx_drm_pdev);
-err_pdev:
        kfree(imx_drm_device);
 
        return ret;
@@ -900,7 +940,6 @@ err_pdev:
 
 static void __exit imx_drm_exit(void)
 {
-       platform_device_unregister(imx_drm_pdev);
        platform_driver_unregister(&imx_drm_pdrv);
 
        kfree(imx_drm_device);
This page took 0.031825 seconds and 5 git commands to generate.