diff options
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_core.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_core.c | 179 |
1 files changed, 134 insertions, 45 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_core.c b/drivers/gpu/drm/exynos/exynos_drm_core.c index 1bef6dc77478..e23611eaa903 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_core.c +++ b/drivers/gpu/drm/exynos/exynos_drm_core.c @@ -14,24 +14,31 @@ #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; @@ -48,8 +55,8 @@ static int exynos_drm_create_enc_conn(struct drm_device *dev, goto err_destroy_encoder; } - subdrv->encoder = encoder; - subdrv->connector = connector; + display->encoder = encoder; + display->connector = connector; return 0; @@ -58,21 +65,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 +96,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 +200,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 +217,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) |