Version:  2.0.40 2.2.26 2.4.37 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1

Linux/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         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 
126 err_cleanup_vblank:
127         drm_vblank_cleanup(dev);
128 err_unbind_all:
129         component_unbind_all(dev->dev, dev);
130 err_mode_config_cleanup:
131         drm_mode_config_cleanup(dev);
132         drm_release_iommu_mapping(dev);
133 err_free_private:
134         kfree(private);
135 
136         return ret;
137 }
138 
139 static 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 
157 static 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 
176 static 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 
194 static 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 
211 err_file_priv_free:
212         kfree(file_priv);
213         file->driver_priv = NULL;
214         return ret;
215 }
216 
217 static void exynos_drm_preclose(struct drm_device *dev,
218                                         struct drm_file *file)
219 {
220         exynos_drm_subdrv_close(dev, file);
221 }
222 
223 static 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 
243 static void exynos_drm_lastclose(struct drm_device *dev)
244 {
245         exynos_drm_fbdev_restore_mode(dev);
246 }
247 
248 static 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 
254 static 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 
277 static 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 
290 static 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
324 static 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 
336 static 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 
347 static 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 
351 int 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 
419 void 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 
454 static int compare_dev(struct device *dev, void *data)
455 {
456         return dev == (struct device *)data;
457 }
458 
459 static 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 
504 out_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 
513 static int exynos_drm_bind(struct device *dev)
514 {
515         return drm_platform_init(&exynos_drm_driver, to_platform_device(dev));
516 }
517 
518 static void exynos_drm_unbind(struct device *dev)
519 {
520         drm_put_dev(dev_get_drvdata(dev));
521 }
522 
523 static const struct component_master_ops exynos_drm_ops = {
524         .bind           = exynos_drm_bind,
525         .unbind         = exynos_drm_unbind,
526 };
527 
528 static 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 
547 static 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 
565 static 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 
581 static int exynos_drm_platform_remove(struct platform_device *pdev)
582 {
583         component_master_del(&pdev->dev, &exynos_drm_ops);
584         return 0;
585 }
586 
587 static const char * const strings[] = {
588         "samsung,exynos3",
589         "samsung,exynos4",
590         "samsung,exynos5",
591         "samsung,exynos7",
592 };
593 
594 static 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 
603 static 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 
658 err_unregister_resources:
659 #ifdef CONFIG_DRM_EXYNOS_IPP
660         exynos_platform_device_ipp_unregister();
661 #endif
662 
663 err_unregister_non_kms_drivers:
664         while (--j >= 0)
665                 platform_driver_unregister(exynos_drm_non_kms_drivers[j]);
666 
667 err_unregister_kms_drivers:
668         while (--i >= 0)
669                 platform_driver_unregister(exynos_drm_kms_drivers[i]);
670 
671         exynos_drm_remove_vidi();
672 
673 err_unregister_pd:
674         platform_device_unregister(exynos_drm_pdev);
675 
676         return ret;
677 }
678 
679 static 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 
700 module_init(exynos_drm_init);
701 module_exit(exynos_drm_exit);
702 
703 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
704 MODULE_AUTHOR("Joonyoung Shim <jy0922.shim@samsung.com>");
705 MODULE_AUTHOR("Seung-Woo Kim <sw0312.kim@samsung.com>");
706 MODULE_DESCRIPTION("Samsung SoC DRM Driver");
707 MODULE_LICENSE("GPL");
708 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us