]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/exynos/exynos_drm_core.c
Merge branch 'x86-vdso-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-linux.git] / drivers / gpu / drm / exynos / exynos_drm_core.c
index 1bef6dc774782efe81b4b2839c9fa09e9f264b4e..0e9e06ce36b860ae8fb5a91d40faf31d917b180a 100644 (file)
 
 #include <drm/drmP.h>
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
+static LIST_HEAD(exynos_drm_manager_list);
+static LIST_HEAD(exynos_drm_display_list);
 
 static int exynos_drm_create_enc_conn(struct drm_device *dev,
-                                       struct exynos_drm_subdrv *subdrv)
+                                       struct exynos_drm_display *display)
 {
        struct drm_encoder *encoder;
-       struct drm_connector *connector;
+       struct exynos_drm_manager *manager;
        int ret;
+       unsigned long possible_crtcs = 0;
 
-       subdrv->manager->dev = subdrv->dev;
+       /* Find possible crtcs for this display */
+       list_for_each_entry(manager, &exynos_drm_manager_list, list)
+               if (manager->type == display->type)
+                       possible_crtcs |= 1 << manager->pipe;
 
        /* create and initialize a encoder for this sub driver. */
-       encoder = exynos_drm_encoder_create(dev, subdrv->manager,
-                       (1 << MAX_CRTC) - 1);
+       encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
        if (!encoder) {
                DRM_ERROR("failed to create encoder\n");
                return -EFAULT;
        }
 
-       /*
-        * create and initialize a connector for this sub driver and
-        * attach the encoder created above to the connector.
-        */
-       connector = exynos_drm_connector_create(dev, encoder);
-       if (!connector) {
-               DRM_ERROR("failed to create connector\n");
-               ret = -EFAULT;
+       display->encoder = encoder;
+
+       ret = display->ops->create_connector(display, encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
                goto err_destroy_encoder;
        }
 
-       subdrv->encoder = encoder;
-       subdrv->connector = connector;
-
        return 0;
 
 err_destroy_encoder:
@@ -58,21 +57,6 @@ err_destroy_encoder:
        return ret;
 }
 
-static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
-{
-       if (subdrv->encoder) {
-               struct drm_encoder *encoder = subdrv->encoder;
-               encoder->funcs->destroy(encoder);
-               subdrv->encoder = NULL;
-       }
-
-       if (subdrv->connector) {
-               struct drm_connector *connector = subdrv->connector;
-               connector->funcs->destroy(connector);
-               subdrv->connector = NULL;
-       }
-}
-
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
                                        struct exynos_drm_subdrv *subdrv)
 {
@@ -104,10 +88,98 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev,
                subdrv->remove(dev, subdrv->dev);
 }
 
+int exynos_drm_initialize_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+       int ret, pipe = 0;
+
+       list_for_each_entry(manager, &exynos_drm_manager_list, list) {
+               if (manager->ops->initialize) {
+                       ret = manager->ops->initialize(manager, dev, pipe);
+                       if (ret) {
+                               DRM_ERROR("Mgr init [%d] failed with %d\n",
+                                               manager->type, ret);
+                               goto err;
+                       }
+               }
+
+               manager->drm_dev = dev;
+               manager->pipe = pipe++;
+
+               ret = exynos_drm_crtc_create(manager);
+               if (ret) {
+                       DRM_ERROR("CRTC create [%d] failed with %d\n",
+                                       manager->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
+               if (pipe-- > 0)
+                       exynos_drm_manager_unregister(manager);
+               else
+                       list_del(&manager->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
+               exynos_drm_manager_unregister(manager);
+}
+
+int exynos_drm_initialize_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+       int ret, initialized = 0;
+
+       list_for_each_entry(display, &exynos_drm_display_list, list) {
+               if (display->ops->initialize) {
+                       ret = display->ops->initialize(display, dev);
+                       if (ret) {
+                               DRM_ERROR("Display init [%d] failed with %d\n",
+                                               display->type, ret);
+                               goto err;
+                       }
+               }
+
+               initialized++;
+
+               ret = exynos_drm_create_enc_conn(dev, display);
+               if (ret) {
+                       DRM_ERROR("Encoder create [%d] failed with %d\n",
+                                       display->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
+               if (initialized-- > 0)
+                       exynos_drm_display_unregister(display);
+               else
+                       list_del(&display->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
+               exynos_drm_display_unregister(display);
+}
+
 int exynos_drm_device_register(struct drm_device *dev)
 {
        struct exynos_drm_subdrv *subdrv, *n;
-       unsigned int fine_cnt = 0;
        int err;
 
        if (!dev)
@@ -120,30 +192,8 @@ int exynos_drm_device_register(struct drm_device *dev)
                        list_del(&subdrv->list);
                        continue;
                }
-
-               /*
-                * if manager is null then it means that this sub driver
-                * doesn't need encoder and connector.
-                */
-               if (!subdrv->manager) {
-                       fine_cnt++;
-                       continue;
-               }
-
-               err = exynos_drm_create_enc_conn(dev, subdrv);
-               if (err) {
-                       DRM_DEBUG("failed to create encoder and connector.\n");
-                       exynos_drm_subdrv_remove(dev, subdrv);
-                       list_del(&subdrv->list);
-                       continue;
-               }
-
-               fine_cnt++;
        }
 
-       if (!fine_cnt)
-               return -EINVAL;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -159,13 +209,44 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 
        list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
                exynos_drm_subdrv_remove(dev, subdrv);
-               exynos_drm_destroy_enc_conn(subdrv);
        }
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
 
+int exynos_drm_manager_register(struct exynos_drm_manager *manager)
+{
+       BUG_ON(!manager->ops);
+       list_add_tail(&manager->list, &exynos_drm_manager_list);
+       return 0;
+}
+
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
+{
+       if (manager->ops->remove)
+               manager->ops->remove(manager);
+
+       list_del(&manager->list);
+       return 0;
+}
+
+int exynos_drm_display_register(struct exynos_drm_display *display)
+{
+       BUG_ON(!display->ops);
+       list_add_tail(&display->list, &exynos_drm_display_list);
+       return 0;
+}
+
+int exynos_drm_display_unregister(struct exynos_drm_display *display)
+{
+       if (display->ops->remove)
+               display->ops->remove(display);
+
+       list_del(&display->list);
+       return 0;
+}
+
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
        if (!subdrv)