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