linux/drivers/gpu/drm/exynos/exynos_drm_drv.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 Samsung Electronics Co., Ltd.
   3 * Authors:
   4 *      Inki Dae <inki.dae@samsung.com>
   5 *      Joonyoung Shim <jy0922.shim@samsung.com>
   6 *      Seung-Woo Kim <sw0312.kim@samsung.com>
   7 *
   8 * This program is free software; you can redistribute  it and/or modify it
   9 * under  the terms of  the GNU General  Public License as published by the
  10 * Free Software Foundation;  either version 2 of the  License, or (at your
  11 * option) any later version.
  12 */
  13
  14#include <linux/pm_runtime.h>
  15#include <drm/drmP.h>
  16#include <drm/drm_crtc_helper.h>
  17
  18#include <linux/component.h>
  19
  20#include <drm/exynos_drm.h>
  21
  22#include "exynos_drm_drv.h"
  23#include "exynos_drm_crtc.h"
  24#include "exynos_drm_encoder.h"
  25#include "exynos_drm_fbdev.h"
  26#include "exynos_drm_fb.h"
  27#include "exynos_drm_gem.h"
  28#include "exynos_drm_plane.h"
  29#include "exynos_drm_vidi.h"
  30#include "exynos_drm_dmabuf.h"
  31#include "exynos_drm_g2d.h"
  32#include "exynos_drm_ipp.h"
  33#include "exynos_drm_iommu.h"
  34
  35#define DRIVER_NAME     "exynos"
  36#define DRIVER_DESC     "Samsung SoC DRM"
  37#define DRIVER_DATE     "20110530"
  38#define DRIVER_MAJOR    1
  39#define DRIVER_MINOR    0
  40
  41static struct platform_device *exynos_drm_pdev;
  42
  43static DEFINE_MUTEX(drm_component_lock);
  44static LIST_HEAD(drm_component_list);
  45
  46struct component_dev {
  47        struct list_head list;
  48        struct device *crtc_dev;
  49        struct device *conn_dev;
  50        enum exynos_drm_output_type out_type;
  51        unsigned int dev_type_flag;
  52};
  53
  54static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
  55{
  56        struct exynos_drm_private *private;
  57        int ret;
  58
  59        private = kzalloc(sizeof(struct exynos_drm_private), GFP_KERNEL);
  60        if (!private)
  61                return -ENOMEM;
  62
  63        dev_set_drvdata(dev->dev, dev);
  64        dev->dev_private = (void *)private;
  65
  66        /*
  67         * create mapping to manage iommu table and set a pointer to iommu
  68         * mapping structure to iommu_mapping of private data.
  69         * also this iommu_mapping can be used to check if iommu is supported
  70         * or not.
  71         */
  72        ret = drm_create_iommu_mapping(dev);
  73        if (ret < 0) {
  74                DRM_ERROR("failed to create iommu mapping.\n");
  75                goto err_free_private;
  76        }
  77
  78        drm_mode_config_init(dev);
  79
  80        exynos_drm_mode_config_init(dev);
  81
  82        /* setup possible_clones. */
  83        exynos_drm_encoder_setup(dev);
  84
  85        platform_set_drvdata(dev->platformdev, dev);
  86
  87        /* Try to bind all sub drivers. */
  88        ret = component_bind_all(dev->dev, dev);
  89        if (ret)
  90                goto err_mode_config_cleanup;
  91
  92        ret = drm_vblank_init(dev, dev->mode_config.num_crtc);
  93        if (ret)
  94                goto err_unbind_all;
  95
  96        /* Probe non kms sub drivers and virtual display driver. */
  97        ret = exynos_drm_device_subdrv_probe(dev);
  98        if (ret)
  99                goto err_cleanup_vblank;
 100
 101        /*
 102         * enable drm irq mode.
 103         * - with irq_enabled = true, we can use the vblank feature.
 104         *
 105         * P.S. note that we wouldn't use drm irq handler but
 106         *      just specific driver own one instead because
 107         *      drm framework supports only one irq handler.
 108         */
 109        dev->irq_enabled = true;
 110
 111        /*
 112         * with vblank_disable_allowed = true, vblank interrupt will be disabled
 113         * by drm timer once a current process gives up ownership of
 114         * vblank event.(after drm_vblank_put function is called)
 115         */
 116        dev->vblank_disable_allowed = true;
 117
 118        /* init kms poll for handling hpd */
 119        drm_kms_helper_poll_init(dev);
 120
 121        /* force connectors detection */
 122        drm_helper_hpd_irq_event(dev);
 123
 124        return 0;
 125
 126err_cleanup_vblank:
 127        drm_vblank_cleanup(dev);
 128err_unbind_all:
 129        component_unbind_all(dev->dev, dev);
 130err_mode_config_cleanup:
 131        drm_mode_config_cleanup(dev);
 132        drm_release_iommu_mapping(dev);
 133err_free_private:
 134        kfree(private);
 135
 136        return ret;
 137}
 138
 139static int exynos_drm_unload(struct drm_device *dev)
 140{
 141        exynos_drm_device_subdrv_remove(dev);
 142
 143        exynos_drm_fbdev_fini(dev);
 144        drm_kms_helper_poll_fini(dev);
 145
 146        drm_vblank_cleanup(dev);
 147        component_unbind_all(dev->dev, dev);
 148        drm_mode_config_cleanup(dev);
 149        drm_release_iommu_mapping(dev);
 150
 151        kfree(dev->dev_private);
 152        dev->dev_private = NULL;
 153
 154        return 0;
 155}
 156
 157static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
 158{
 159        struct drm_connector *connector;
 160
 161        drm_modeset_lock_all(dev);
 162        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 163                int old_dpms = connector->dpms;
 164
 165                if (connector->funcs->dpms)
 166                        connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
 167
 168                /* Set the old mode back to the connector for resume */
 169                connector->dpms = old_dpms;
 170        }
 171        drm_modeset_unlock_all(dev);
 172
 173        return 0;
 174}
 175
 176static int exynos_drm_resume(struct drm_device *dev)
 177{
 178        struct drm_connector *connector;
 179
 180        drm_modeset_lock_all(dev);
 181        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
 182                if (connector->funcs->dpms) {
 183                        int dpms = connector->dpms;
 184
 185                        connector->dpms = DRM_MODE_DPMS_OFF;
 186                        connector->funcs->dpms(connector, dpms);
 187                }
 188        }
 189        drm_modeset_unlock_all(dev);
 190
 191        return 0;
 192}
 193
 194static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 195{
 196        struct drm_exynos_file_private *file_priv;
 197        int ret;
 198
 199        file_priv = kzalloc(sizeof(*file_priv), GFP_KERNEL);
 200        if (!file_priv)
 201                return -ENOMEM;
 202
 203        file->driver_priv = file_priv;
 204
 205        ret = exynos_drm_subdrv_open(dev, file);
 206        if (ret)
 207                goto err_file_priv_free;
 208
 209        return ret;
 210
 211err_file_priv_free:
 212        kfree(file_priv);
 213        file->driver_priv = NULL;
 214        return ret;
 215}
 216
 217static void exynos_drm_preclose(struct drm_device *dev,
 218                                        struct drm_file *file)
 219{
 220        exynos_drm_subdrv_close(dev, file);
 221}
 222
 223static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
 224{
 225        struct drm_pending_event *e, *et;
 226        unsigned long flags;
 227
 228        if (!file->driver_priv)
 229                return;
 230
 231        spin_lock_irqsave(&dev->event_lock, flags);
 232        /* Release all events handled by page flip handler but not freed. */
 233        list_for_each_entry_safe(e, et, &file->event_list, link) {
 234                list_del(&e->link);
 235                e->destroy(e);
 236        }
 237        spin_unlock_irqrestore(&dev->event_lock, flags);
 238
 239        kfree(file->driver_priv);
 240        file->driver_priv = NULL;
 241}
 242
 243static void exynos_drm_lastclose(struct drm_device *dev)
 244{
 245        exynos_drm_fbdev_restore_mode(dev);
 246}
 247
 248static const struct vm_operations_struct exynos_drm_gem_vm_ops = {
 249        .fault = exynos_drm_gem_fault,
 250        .open = drm_gem_vm_open,
 251        .close = drm_gem_vm_close,
 252};
 253
 254static const struct drm_ioctl_desc exynos_ioctls[] = {
 255        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_CREATE, exynos_drm_gem_create_ioctl,
 256                        DRM_UNLOCKED | DRM_AUTH),
 257        DRM_IOCTL_DEF_DRV(EXYNOS_GEM_GET,
 258                        exynos_drm_gem_get_ioctl, DRM_UNLOCKED),
 259        DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
 260                        vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
 261        DRM_IOCTL_DEF_DRV(EXYNOS_G2D_GET_VER,
 262                        exynos_g2d_get_ver_ioctl, DRM_UNLOCKED | DRM_AUTH),
 263        DRM_IOCTL_DEF_DRV(EXYNOS_G2D_SET_CMDLIST,
 264                        exynos_g2d_set_cmdlist_ioctl, DRM_UNLOCKED | DRM_AUTH),
 265        DRM_IOCTL_DEF_DRV(EXYNOS_G2D_EXEC,
 266                        exynos_g2d_exec_ioctl, DRM_UNLOCKED | DRM_AUTH),
 267        DRM_IOCTL_DEF_DRV(EXYNOS_IPP_GET_PROPERTY,
 268                        exynos_drm_ipp_get_property, DRM_UNLOCKED | DRM_AUTH),
 269        DRM_IOCTL_DEF_DRV(EXYNOS_IPP_SET_PROPERTY,
 270                        exynos_drm_ipp_set_property, DRM_UNLOCKED | DRM_AUTH),
 271        DRM_IOCTL_DEF_DRV(EXYNOS_IPP_QUEUE_BUF,
 272                        exynos_drm_ipp_queue_buf, DRM_UNLOCKED | DRM_AUTH),
 273        DRM_IOCTL_DEF_DRV(EXYNOS_IPP_CMD_CTRL,
 274                        exynos_drm_ipp_cmd_ctrl, DRM_UNLOCKED | DRM_AUTH),
 275};
 276
 277static const struct file_operations exynos_drm_driver_fops = {
 278        .owner          = THIS_MODULE,
 279        .open           = drm_open,
 280        .mmap           = exynos_drm_gem_mmap,
 281        .poll           = drm_poll,
 282        .read           = drm_read,
 283        .unlocked_ioctl = drm_ioctl,
 284#ifdef CONFIG_COMPAT
 285        .compat_ioctl = drm_compat_ioctl,
 286#endif
 287        .release        = drm_release,
 288};
 289
 290static struct drm_driver exynos_drm_driver = {
 291        .driver_features        = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
 292        .load                   = exynos_drm_load,
 293        .unload                 = exynos_drm_unload,
 294        .suspend                = exynos_drm_suspend,
 295        .resume                 = exynos_drm_resume,
 296        .open                   = exynos_drm_open,
 297        .preclose               = exynos_drm_preclose,
 298        .lastclose              = exynos_drm_lastclose,
 299        .postclose              = exynos_drm_postclose,
 300        .set_busid              = drm_platform_set_busid,
 301        .get_vblank_counter     = drm_vblank_count,
 302        .enable_vblank          = exynos_drm_crtc_enable_vblank,
 303        .disable_vblank         = exynos_drm_crtc_disable_vblank,
 304        .gem_free_object        = exynos_drm_gem_free_object,
 305        .gem_vm_ops             = &exynos_drm_gem_vm_ops,
 306        .dumb_create            = exynos_drm_gem_dumb_create,
 307        .dumb_map_offset        = exynos_drm_gem_dumb_map_offset,
 308        .dumb_destroy           = drm_gem_dumb_destroy,
 309        .prime_handle_to_fd     = drm_gem_prime_handle_to_fd,
 310        .prime_fd_to_handle     = drm_gem_prime_fd_to_handle,
 311        .gem_prime_export       = exynos_dmabuf_prime_export,
 312        .gem_prime_import       = exynos_dmabuf_prime_import,
 313        .ioctls                 = exynos_ioctls,
 314        .num_ioctls             = ARRAY_SIZE(exynos_ioctls),
 315        .fops                   = &exynos_drm_driver_fops,
 316        .name   = DRIVER_NAME,
 317        .desc   = DRIVER_DESC,
 318        .date   = DRIVER_DATE,
 319        .major  = DRIVER_MAJOR,
 320        .minor  = DRIVER_MINOR,
 321};
 322
 323#ifdef CONFIG_PM_SLEEP
 324static int exynos_drm_sys_suspend(struct device *dev)
 325{
 326        struct drm_device *drm_dev = dev_get_drvdata(dev);
 327        pm_message_t message;
 328
 329        if (pm_runtime_suspended(dev) || !drm_dev)
 330                return 0;
 331
 332        message.event = PM_EVENT_SUSPEND;
 333        return exynos_drm_suspend(drm_dev, message);
 334}
 335
 336static int exynos_drm_sys_resume(struct device *dev)
 337{
 338        struct drm_device *drm_dev = dev_get_drvdata(dev);
 339
 340        if (pm_runtime_suspended(dev) || !drm_dev)
 341                return 0;
 342
 343        return exynos_drm_resume(drm_dev);
 344}
 345#endif
 346
 347static const struct dev_pm_ops exynos_drm_pm_ops = {
 348        SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
 349};
 350
 351int exynos_drm_component_add(struct device *dev,
 352                                enum exynos_drm_device_type dev_type,
 353                                enum exynos_drm_output_type out_type)
 354{
 355        struct component_dev *cdev;
 356
 357        if (dev_type != EXYNOS_DEVICE_TYPE_CRTC &&
 358                        dev_type != EXYNOS_DEVICE_TYPE_CONNECTOR) {
 359                DRM_ERROR("invalid device type.\n");
 360                return -EINVAL;
 361        }
 362
 363        mutex_lock(&drm_component_lock);
 364
 365        /*
 366         * Make sure to check if there is a component which has two device
 367         * objects, for connector and for encoder/connector.
 368         * It should make sure that crtc and encoder/connector drivers are
 369         * ready before exynos drm core binds them.
 370         */
 371        list_for_each_entry(cdev, &drm_component_list, list) {
 372                if (cdev->out_type == out_type) {
 373                        /*
 374                         * If crtc and encoder/connector device objects are
 375                         * added already just return.
 376                         */
 377                        if (cdev->dev_type_flag == (EXYNOS_DEVICE_TYPE_CRTC |
 378                                                EXYNOS_DEVICE_TYPE_CONNECTOR)) {
 379                                mutex_unlock(&drm_component_lock);
 380                                return 0;
 381                        }
 382
 383                        if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
 384                                cdev->crtc_dev = dev;
 385                                cdev->dev_type_flag |= dev_type;
 386                        }
 387
 388                        if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
 389                                cdev->conn_dev = dev;
 390                                cdev->dev_type_flag |= dev_type;
 391                        }
 392
 393                        mutex_unlock(&drm_component_lock);
 394                        return 0;
 395                }
 396        }
 397
 398        mutex_unlock(&drm_component_lock);
 399
 400        cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
 401        if (!cdev)
 402                return -ENOMEM;
 403
 404        if (dev_type == EXYNOS_DEVICE_TYPE_CRTC)
 405                cdev->crtc_dev = dev;
 406        if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR)
 407                cdev->conn_dev = dev;
 408
 409        cdev->out_type = out_type;
 410        cdev->dev_type_flag = dev_type;
 411
 412        mutex_lock(&drm_component_lock);
 413        list_add_tail(&cdev->list, &drm_component_list);
 414        mutex_unlock(&drm_component_lock);
 415
 416        return 0;
 417}
 418
 419void exynos_drm_component_del(struct device *dev,
 420                                enum exynos_drm_device_type dev_type)
 421{
 422        struct component_dev *cdev, *next;
 423
 424        mutex_lock(&drm_component_lock);
 425
 426        list_for_each_entry_safe(cdev, next, &drm_component_list, list) {
 427                if (dev_type == EXYNOS_DEVICE_TYPE_CRTC) {
 428                        if (cdev->crtc_dev == dev) {
 429                                cdev->crtc_dev = NULL;
 430                                cdev->dev_type_flag &= ~dev_type;
 431                        }
 432                }
 433
 434                if (dev_type == EXYNOS_DEVICE_TYPE_CONNECTOR) {
 435                        if (cdev->conn_dev == dev) {
 436                                cdev->conn_dev = NULL;
 437                                cdev->dev_type_flag &= ~dev_type;
 438                        }
 439                }
 440
 441                /*
 442                 * Release cdev object only in case that both of crtc and
 443                 * encoder/connector device objects are NULL.
 444                 */
 445                if (!cdev->crtc_dev && !cdev->conn_dev) {
 446                        list_del(&cdev->list);
 447                        kfree(cdev);
 448                }
 449        }
 450
 451        mutex_unlock(&drm_component_lock);
 452}
 453
 454static int compare_dev(struct device *dev, void *data)
 455{
 456        return dev == (struct device *)data;
 457}
 458
 459static struct component_match *exynos_drm_match_add(struct device *dev)
 460{
 461        struct component_match *match = NULL;
 462        struct component_dev *cdev;
 463        unsigned int attach_cnt = 0;
 464
 465        mutex_lock(&drm_component_lock);
 466
 467        /* Do not retry to probe if there is no any kms driver regitered. */
 468        if (list_empty(&drm_component_list)) {
 469                mutex_unlock(&drm_component_lock);
 470                return ERR_PTR(-ENODEV);
 471        }
 472
 473        list_for_each_entry(cdev, &drm_component_list, list) {
 474                /*
 475                 * Add components to master only in case that crtc and
 476                 * encoder/connector device objects exist.
 477                 */
 478                if (!cdev->crtc_dev || !cdev->conn_dev)
 479                        continue;
 480
 481                attach_cnt++;
 482
 483                mutex_unlock(&drm_component_lock);
 484
 485                /*
 486                 * fimd and dpi modules have same device object so add
 487                 * only crtc device object in this case.
 488                 */
 489                if (cdev->crtc_dev == cdev->conn_dev) {
 490                        component_match_add(dev, &match, compare_dev,
 491                                                cdev->crtc_dev);
 492                        goto out_lock;
 493                }
 494
 495                /*
 496                 * Do not chage below call order.
 497                 * crtc device first should be added to master because
 498                 * connector/encoder need pipe number of crtc when they
 499                 * are created.
 500                 */
 501                component_match_add(dev, &match, compare_dev, cdev->crtc_dev);
 502                component_match_add(dev, &match, compare_dev, cdev->conn_dev);
 503
 504out_lock:
 505                mutex_lock(&drm_component_lock);
 506        }
 507
 508        mutex_unlock(&drm_component_lock);
 509
 510        return attach_cnt ? match : ERR_PTR(-EPROBE_DEFER);
 511}
 512
 513static int exynos_drm_bind(struct device *dev)
 514{
 515        return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
 516}
 517
 518static void exynos_drm_unbind(struct device *dev)
 519{
 520        drm_put_dev(dev_get_drvdata(dev));
 521}
 522
 523static const struct component_master_ops exynos_drm_ops = {
 524        .bind           = exynos_drm_bind,
 525        .unbind         = exynos_drm_unbind,
 526};
 527
 528static struct platform_driver *const exynos_drm_kms_drivers[] = {
 529#ifdef CONFIG_DRM_EXYNOS_FIMD
 530        &fimd_driver,
 531#endif
 532#ifdef CONFIG_DRM_EXYNOS7_DECON
 533        &decon_driver,
 534#endif
 535#ifdef CONFIG_DRM_EXYNOS_DP
 536        &dp_driver,
 537#endif
 538#ifdef CONFIG_DRM_EXYNOS_DSI
 539        &dsi_driver,
 540#endif
 541#ifdef CONFIG_DRM_EXYNOS_HDMI
 542        &mixer_driver,
 543        &hdmi_driver,
 544#endif
 545};
 546
 547static struct platform_driver *const exynos_drm_non_kms_drivers[] = {
 548#ifdef CONFIG_DRM_EXYNOS_G2D
 549        &g2d_driver,
 550#endif
 551#ifdef CONFIG_DRM_EXYNOS_FIMC
 552        &fimc_driver,
 553#endif
 554#ifdef CONFIG_DRM_EXYNOS_ROTATOR
 555        &rotator_driver,
 556#endif
 557#ifdef CONFIG_DRM_EXYNOS_GSC
 558        &gsc_driver,
 559#endif
 560#ifdef CONFIG_DRM_EXYNOS_IPP
 561        &ipp_driver,
 562#endif
 563};
 564
 565static int exynos_drm_platform_probe(struct platform_device *pdev)
 566{
 567        struct component_match *match;
 568
 569        pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
 570        exynos_drm_driver.num_ioctls = ARRAY_SIZE(exynos_ioctls);
 571
 572        match = exynos_drm_match_add(&pdev->dev);
 573        if (IS_ERR(match)) {
 574                return PTR_ERR(match);
 575        }
 576
 577        return component_master_add_with_match(&pdev->dev, &exynos_drm_ops,
 578                                               match);
 579}
 580
 581static int exynos_drm_platform_remove(struct platform_device *pdev)
 582{
 583        component_master_del(&pdev->dev, &exynos_drm_ops);
 584        return 0;
 585}
 586
 587static const char * const strings[] = {
 588        "samsung,exynos3",
 589        "samsung,exynos4",
 590        "samsung,exynos5",
 591        "samsung,exynos7",
 592};
 593
 594static struct platform_driver exynos_drm_platform_driver = {
 595        .probe  = exynos_drm_platform_probe,
 596        .remove = exynos_drm_platform_remove,
 597        .driver = {
 598                .name   = "exynos-drm",
 599                .pm     = &exynos_drm_pm_ops,
 600        },
 601};
 602
 603static int exynos_drm_init(void)
 604{
 605        bool is_exynos = false;
 606        int ret, i, j;
 607
 608        /*
 609         * Register device object only in case of Exynos SoC.
 610         *
 611         * Below codes resolves temporarily infinite loop issue incurred
 612         * by Exynos drm driver when using multi-platform kernel.
 613         * So these codes will be replaced with more generic way later.
 614         */
 615        for (i = 0; i < ARRAY_SIZE(strings); i++) {
 616                if (of_machine_is_compatible(strings[i])) {
 617                        is_exynos = true;
 618                        break;
 619                }
 620        }
 621
 622        if (!is_exynos)
 623                return -ENODEV;
 624
 625        exynos_drm_pdev = platform_device_register_simple("exynos-drm", -1,
 626                                                                NULL, 0);
 627        if (IS_ERR(exynos_drm_pdev))
 628                return PTR_ERR(exynos_drm_pdev);
 629
 630        ret = exynos_drm_probe_vidi();
 631        if (ret < 0)
 632                goto err_unregister_pd;
 633
 634        for (i = 0; i < ARRAY_SIZE(exynos_drm_kms_drivers); ++i) {
 635                ret = platform_driver_register(exynos_drm_kms_drivers[i]);
 636                if (ret < 0)
 637                        goto err_unregister_kms_drivers;
 638        }
 639
 640        for (j = 0; j < ARRAY_SIZE(exynos_drm_non_kms_drivers); ++j) {
 641                ret = platform_driver_register(exynos_drm_non_kms_drivers[j]);
 642                if (ret < 0)
 643                        goto err_unregister_non_kms_drivers;
 644        }
 645
 646#ifdef CONFIG_DRM_EXYNOS_IPP
 647        ret = exynos_platform_device_ipp_register();
 648        if (ret < 0)
 649                goto err_unregister_non_kms_drivers;
 650#endif
 651
 652        ret = platform_driver_register(&exynos_drm_platform_driver);
 653        if (ret)
 654                goto err_unregister_resources;
 655
 656        return 0;
 657
 658err_unregister_resources:
 659#ifdef CONFIG_DRM_EXYNOS_IPP
 660        exynos_platform_device_ipp_unregister();
 661#endif
 662
 663err_unregister_non_kms_drivers:
 664        while (--j >= 0)
 665                platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
 666
 667err_unregister_kms_drivers:
 668        while (--i >= 0)
 669                platform_driver_unregister(exynos_drm_kms_drivers[i]);
 670
 671        exynos_drm_remove_vidi();
 672
 673err_unregister_pd:
 674        platform_device_unregister(exynos_drm_pdev);
 675
 676        return ret;
 677}
 678
 679static void exynos_drm_exit(void)
 680{
 681        int i;
 682
 683#ifdef CONFIG_DRM_EXYNOS_IPP
 684        exynos_platform_device_ipp_unregister();
 685#endif
 686
 687        for (i = ARRAY_SIZE(exynos_drm_non_kms_drivers) - 1; i >= 0; --i)
 688                platform_driver_unregister(exynos_drm_non_kms_drivers[i]);
 689
 690        for (i = ARRAY_SIZE(exynos_drm_kms_drivers) - 1; i >= 0; --i)
 691                platform_driver_unregister(exynos_drm_kms_drivers[i]);
 692
 693        platform_driver_unregister(&exynos_drm_platform_driver);
 694
 695        exynos_drm_remove_vidi();
 696
 697        platform_device_unregister(exynos_drm_pdev);
 698}
 699
 700module_init(exynos_drm_init);
 701module_exit(exynos_drm_exit);
 702
 703MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
 704MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
 705MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
 706MODULE_DESCRIPTION("Samsung SoC DRM Driver");
 707MODULE_LICENSE("GPL");
 708