2 * Freescale i.MX drm driver
4 * Copyright (C) 2011 Sascha Hauer, Pengutronix
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
17 #include <linux/device.h>
18 #include <linux/platform_device.h>
20 #include <drm/drm_fb_helper.h>
21 #include <drm/drm_crtc_helper.h>
23 #include <linux/module.h>
24 #include <drm/drm_gem_cma_helper.h>
25 #include <drm/drm_fb_cma_helper.h>
34 struct list_head list
;
37 struct imx_drm_device
{
38 struct drm_device
*drm
;
40 struct list_head crtc_list
;
41 struct list_head encoder_list
;
42 struct list_head connector_list
;
46 struct drm_fbdev_cma
*fbhelper
;
50 struct drm_crtc
*crtc
;
51 struct list_head list
;
52 struct imx_drm_device
*imxdrm
;
54 struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs
;
56 struct crtc_cookie cookie
;
59 struct imx_drm_encoder
{
60 struct drm_encoder
*encoder
;
61 struct list_head list
;
63 struct list_head possible_crtcs
;
66 struct imx_drm_connector
{
67 struct drm_connector
*connector
;
68 struct list_head list
;
72 static int imx_drm_driver_firstopen(struct drm_device
*drm
)
74 if (!imx_drm_device_get())
80 static void imx_drm_driver_lastclose(struct drm_device
*drm
)
82 struct imx_drm_device
*imxdrm
= drm
->dev_private
;
85 drm_fbdev_cma_restore_mode(imxdrm
->fbhelper
);
90 static int imx_drm_driver_unload(struct drm_device
*drm
)
92 struct imx_drm_device
*imxdrm
= drm
->dev_private
;
94 drm_mode_config_cleanup(imxdrm
->drm
);
95 drm_kms_helper_poll_fini(imxdrm
->drm
);
101 * We don't care at all for crtc numbers, but the core expects the
102 * crtcs to be numbered
104 static struct imx_drm_crtc
*imx_drm_crtc_by_num(struct imx_drm_device
*imxdrm
,
107 struct imx_drm_crtc
*imx_drm_crtc
;
109 list_for_each_entry(imx_drm_crtc
, &imxdrm
->crtc_list
, list
)
110 if (imx_drm_crtc
->pipe
== num
)
115 int imx_drm_crtc_panel_format(struct drm_crtc
*crtc
, u32 encoder_type
,
116 u32 interface_pix_fmt
)
118 struct imx_drm_device
*imxdrm
= crtc
->dev
->dev_private
;
119 struct imx_drm_crtc
*imx_crtc
;
120 struct imx_drm_crtc_helper_funcs
*helper
;
122 mutex_lock(&imxdrm
->mutex
);
124 list_for_each_entry(imx_crtc
, &imxdrm
->crtc_list
, list
)
125 if (imx_crtc
->crtc
== crtc
)
128 mutex_unlock(&imxdrm
->mutex
);
132 mutex_unlock(&imxdrm
->mutex
);
134 helper
= &imx_crtc
->imx_drm_helper_funcs
;
135 if (helper
->set_interface_pix_fmt
)
136 return helper
->set_interface_pix_fmt(crtc
,
137 encoder_type
, interface_pix_fmt
);
141 int imx_drm_crtc_vblank_get(struct imx_drm_crtc
*imx_drm_crtc
)
143 return drm_vblank_get(imx_drm_crtc
->imxdrm
->drm
, imx_drm_crtc
->pipe
);
145 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get
);
147 void imx_drm_crtc_vblank_put(struct imx_drm_crtc
*imx_drm_crtc
)
149 drm_vblank_put(imx_drm_crtc
->imxdrm
->drm
, imx_drm_crtc
->pipe
);
151 EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put
);
153 void imx_drm_handle_vblank(struct imx_drm_crtc
*imx_drm_crtc
)
155 drm_handle_vblank(imx_drm_crtc
->imxdrm
->drm
, imx_drm_crtc
->pipe
);
157 EXPORT_SYMBOL_GPL(imx_drm_handle_vblank
);
159 static int imx_drm_enable_vblank(struct drm_device
*drm
, int crtc
)
161 struct imx_drm_device
*imxdrm
= drm
->dev_private
;
162 struct imx_drm_crtc
*imx_drm_crtc
;
165 imx_drm_crtc
= imx_drm_crtc_by_num(imxdrm
, crtc
);
169 if (!imx_drm_crtc
->imx_drm_helper_funcs
.enable_vblank
)
172 ret
= imx_drm_crtc
->imx_drm_helper_funcs
.enable_vblank(
178 static void imx_drm_disable_vblank(struct drm_device
*drm
, int crtc
)
180 struct imx_drm_device
*imxdrm
= drm
->dev_private
;
181 struct imx_drm_crtc
*imx_drm_crtc
;
183 imx_drm_crtc
= imx_drm_crtc_by_num(imxdrm
, crtc
);
187 if (!imx_drm_crtc
->imx_drm_helper_funcs
.disable_vblank
)
190 imx_drm_crtc
->imx_drm_helper_funcs
.disable_vblank(imx_drm_crtc
->crtc
);
193 static const struct file_operations imx_drm_driver_fops
= {
194 .owner
= THIS_MODULE
,
196 .release
= drm_release
,
197 .unlocked_ioctl
= drm_ioctl
,
198 .mmap
= drm_gem_cma_mmap
,
200 .fasync
= drm_fasync
,
202 .llseek
= noop_llseek
,
205 static struct imx_drm_device
*imx_drm_device
;
207 static struct imx_drm_device
*__imx_drm_device(void)
209 return imx_drm_device
;
212 struct drm_device
*imx_drm_device_get(void)
214 struct imx_drm_device
*imxdrm
= __imx_drm_device();
215 struct imx_drm_encoder
*enc
;
216 struct imx_drm_connector
*con
;
217 struct imx_drm_crtc
*crtc
;
219 mutex_lock(&imxdrm
->mutex
);
221 list_for_each_entry(enc
, &imxdrm
->encoder_list
, list
) {
222 if (!try_module_get(enc
->owner
)) {
223 dev_err(imxdrm
->dev
, "could not get module %s\n",
224 module_name(enc
->owner
));
229 list_for_each_entry(con
, &imxdrm
->connector_list
, list
) {
230 if (!try_module_get(con
->owner
)) {
231 dev_err(imxdrm
->dev
, "could not get module %s\n",
232 module_name(con
->owner
));
237 list_for_each_entry(crtc
, &imxdrm
->crtc_list
, list
) {
238 if (!try_module_get(crtc
->owner
)) {
239 dev_err(imxdrm
->dev
, "could not get module %s\n",
240 module_name(crtc
->owner
));
245 imxdrm
->references
++;
247 mutex_unlock(&imxdrm
->mutex
);
252 list_for_each_entry_continue_reverse(crtc
, &imxdrm
->crtc_list
, list
)
253 module_put(crtc
->owner
);
255 list_for_each_entry_continue_reverse(con
, &imxdrm
->connector_list
, list
)
256 module_put(con
->owner
);
258 list_for_each_entry_continue_reverse(enc
, &imxdrm
->encoder_list
, list
)
259 module_put(enc
->owner
);
261 mutex_unlock(&imxdrm
->mutex
);
266 EXPORT_SYMBOL_GPL(imx_drm_device_get
);
268 void imx_drm_device_put(void)
270 struct imx_drm_device
*imxdrm
= __imx_drm_device();
271 struct imx_drm_encoder
*enc
;
272 struct imx_drm_connector
*con
;
273 struct imx_drm_crtc
*crtc
;
275 mutex_lock(&imxdrm
->mutex
);
277 list_for_each_entry(crtc
, &imxdrm
->crtc_list
, list
)
278 module_put(crtc
->owner
);
280 list_for_each_entry(con
, &imxdrm
->connector_list
, list
)
281 module_put(con
->owner
);
283 list_for_each_entry(enc
, &imxdrm
->encoder_list
, list
)
284 module_put(enc
->owner
);
286 imxdrm
->references
--;
288 mutex_unlock(&imxdrm
->mutex
);
290 EXPORT_SYMBOL_GPL(imx_drm_device_put
);
292 static int drm_mode_group_reinit(struct drm_device
*dev
)
294 struct drm_mode_group
*group
= &dev
->primary
->mode_group
;
295 uint32_t *id_list
= group
->id_list
;
298 ret
= drm_mode_group_init_legacy_group(dev
, group
);
307 * register an encoder to the drm core
309 static int imx_drm_encoder_register(struct imx_drm_encoder
*imx_drm_encoder
)
311 struct imx_drm_device
*imxdrm
= __imx_drm_device();
313 INIT_LIST_HEAD(&imx_drm_encoder
->possible_crtcs
);
315 drm_encoder_init(imxdrm
->drm
, imx_drm_encoder
->encoder
,
316 imx_drm_encoder
->encoder
->funcs
,
317 imx_drm_encoder
->encoder
->encoder_type
);
319 drm_mode_group_reinit(imxdrm
->drm
);
325 * unregister an encoder from the drm core
327 static void imx_drm_encoder_unregister(struct imx_drm_encoder
330 struct imx_drm_device
*imxdrm
= __imx_drm_device();
332 drm_encoder_cleanup(imx_drm_encoder
->encoder
);
334 drm_mode_group_reinit(imxdrm
->drm
);
338 * register a connector to the drm core
340 static int imx_drm_connector_register(
341 struct imx_drm_connector
*imx_drm_connector
)
343 struct imx_drm_device
*imxdrm
= __imx_drm_device();
345 drm_connector_init(imxdrm
->drm
, imx_drm_connector
->connector
,
346 imx_drm_connector
->connector
->funcs
,
347 imx_drm_connector
->connector
->connector_type
);
348 drm_mode_group_reinit(imxdrm
->drm
);
350 return drm_sysfs_connector_add(imx_drm_connector
->connector
);
354 * unregister a connector from the drm core
356 static void imx_drm_connector_unregister(
357 struct imx_drm_connector
*imx_drm_connector
)
359 struct imx_drm_device
*imxdrm
= __imx_drm_device();
361 drm_sysfs_connector_remove(imx_drm_connector
->connector
);
362 drm_connector_cleanup(imx_drm_connector
->connector
);
364 drm_mode_group_reinit(imxdrm
->drm
);
368 * register a crtc to the drm core
370 static int imx_drm_crtc_register(struct imx_drm_crtc
*imx_drm_crtc
)
372 struct imx_drm_device
*imxdrm
= __imx_drm_device();
375 drm_crtc_init(imxdrm
->drm
, imx_drm_crtc
->crtc
,
376 imx_drm_crtc
->imx_drm_helper_funcs
.crtc_funcs
);
377 ret
= drm_mode_crtc_set_gamma_size(imx_drm_crtc
->crtc
, 256);
381 drm_crtc_helper_add(imx_drm_crtc
->crtc
,
382 imx_drm_crtc
->imx_drm_helper_funcs
.crtc_helper_funcs
);
384 drm_mode_group_reinit(imxdrm
->drm
);
390 * Called by the CRTC driver when all CRTCs are registered. This
391 * puts all the pieces together and initializes the driver.
392 * Once this is called no more CRTCs can be registered since
393 * the drm core has hardcoded the number of crtcs in several
396 static int imx_drm_driver_load(struct drm_device
*drm
, unsigned long flags
)
398 struct imx_drm_device
*imxdrm
= __imx_drm_device();
403 drm
->dev_private
= imxdrm
;
406 * enable drm irq mode.
407 * - with irq_enabled = 1, we can use the vblank feature.
409 * P.S. note that we wouldn't use drm irq handler but
410 * just specific driver own one instead because
411 * drm framework supports only one irq handler and
412 * drivers can well take care of their interrupts
414 drm
->irq_enabled
= 1;
416 drm_mode_config_init(drm
);
417 imx_drm_mode_config_init(drm
);
419 mutex_lock(&imxdrm
->mutex
);
421 drm_kms_helper_poll_init(imxdrm
->drm
);
423 /* setup the grouping for the legacy output */
424 ret
= drm_mode_group_init_legacy_group(imxdrm
->drm
,
425 &imxdrm
->drm
->primary
->mode_group
);
429 ret
= drm_vblank_init(imxdrm
->drm
, MAX_CRTC
);
434 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
435 * by drm timer once a current process gives up ownership of
436 * vblank event.(after drm_vblank_put function is called)
438 imxdrm
->drm
->vblank_disable_allowed
= 1;
443 mutex_unlock(&imxdrm
->mutex
);
448 static void imx_drm_update_possible_crtcs(void)
450 struct imx_drm_device
*imxdrm
= __imx_drm_device();
451 struct imx_drm_crtc
*imx_drm_crtc
;
452 struct imx_drm_encoder
*enc
;
453 struct crtc_cookie
*cookie
;
455 list_for_each_entry(enc
, &imxdrm
->encoder_list
, list
) {
456 u32 possible_crtcs
= 0;
458 list_for_each_entry(cookie
, &enc
->possible_crtcs
, list
) {
459 list_for_each_entry(imx_drm_crtc
, &imxdrm
->crtc_list
, list
) {
460 if (imx_drm_crtc
->cookie
.cookie
== cookie
->cookie
&&
461 imx_drm_crtc
->cookie
.id
== cookie
->id
) {
462 possible_crtcs
|= 1 << imx_drm_crtc
->pipe
;
466 enc
->encoder
->possible_crtcs
= possible_crtcs
;
467 enc
->encoder
->possible_clones
= possible_crtcs
;
472 * imx_drm_add_crtc - add a new crtc
474 * The return value if !NULL is a cookie for the caller to pass to
475 * imx_drm_remove_crtc later.
477 int imx_drm_add_crtc(struct drm_crtc
*crtc
,
478 struct imx_drm_crtc
**new_crtc
,
479 const struct imx_drm_crtc_helper_funcs
*imx_drm_helper_funcs
,
480 struct module
*owner
, void *cookie
, int id
)
482 struct imx_drm_device
*imxdrm
= __imx_drm_device();
483 struct imx_drm_crtc
*imx_drm_crtc
;
484 const struct drm_crtc_funcs
*crtc_funcs
;
487 mutex_lock(&imxdrm
->mutex
);
489 if (imxdrm
->references
) {
494 imx_drm_crtc
= kzalloc(sizeof(*imx_drm_crtc
), GFP_KERNEL
);
500 imx_drm_crtc
->imx_drm_helper_funcs
= *imx_drm_helper_funcs
;
501 imx_drm_crtc
->pipe
= imxdrm
->pipes
++;
502 imx_drm_crtc
->cookie
.cookie
= cookie
;
503 imx_drm_crtc
->cookie
.id
= id
;
505 crtc_funcs
= imx_drm_helper_funcs
->crtc_funcs
;
507 imx_drm_crtc
->crtc
= crtc
;
508 imx_drm_crtc
->imxdrm
= imxdrm
;
510 imx_drm_crtc
->owner
= owner
;
512 list_add_tail(&imx_drm_crtc
->list
, &imxdrm
->crtc_list
);
514 *new_crtc
= imx_drm_crtc
;
516 ret
= imx_drm_crtc_register(imx_drm_crtc
);
520 imx_drm_update_possible_crtcs();
522 mutex_unlock(&imxdrm
->mutex
);
530 mutex_unlock(&imxdrm
->mutex
);
533 EXPORT_SYMBOL_GPL(imx_drm_add_crtc
);
536 * imx_drm_remove_crtc - remove a crtc
538 int imx_drm_remove_crtc(struct imx_drm_crtc
*imx_drm_crtc
)
540 struct imx_drm_device
*imxdrm
= imx_drm_crtc
->imxdrm
;
542 mutex_lock(&imxdrm
->mutex
);
544 drm_crtc_cleanup(imx_drm_crtc
->crtc
);
546 list_del(&imx_drm_crtc
->list
);
548 drm_mode_group_reinit(imxdrm
->drm
);
550 mutex_unlock(&imxdrm
->mutex
);
556 EXPORT_SYMBOL_GPL(imx_drm_remove_crtc
);
559 * imx_drm_add_encoder - add a new encoder
561 int imx_drm_add_encoder(struct drm_encoder
*encoder
,
562 struct imx_drm_encoder
**newenc
, struct module
*owner
)
564 struct imx_drm_device
*imxdrm
= __imx_drm_device();
565 struct imx_drm_encoder
*imx_drm_encoder
;
568 mutex_lock(&imxdrm
->mutex
);
570 if (imxdrm
->references
) {
575 imx_drm_encoder
= kzalloc(sizeof(*imx_drm_encoder
), GFP_KERNEL
);
576 if (!imx_drm_encoder
) {
581 imx_drm_encoder
->encoder
= encoder
;
582 imx_drm_encoder
->owner
= owner
;
584 ret
= imx_drm_encoder_register(imx_drm_encoder
);
586 kfree(imx_drm_encoder
);
591 list_add_tail(&imx_drm_encoder
->list
, &imxdrm
->encoder_list
);
593 *newenc
= imx_drm_encoder
;
595 mutex_unlock(&imxdrm
->mutex
);
600 kfree(imx_drm_encoder
);
603 mutex_unlock(&imxdrm
->mutex
);
607 EXPORT_SYMBOL_GPL(imx_drm_add_encoder
);
609 int imx_drm_encoder_add_possible_crtcs(
610 struct imx_drm_encoder
*imx_drm_encoder
,
611 struct device_node
*np
)
613 struct imx_drm_device
*imxdrm
= __imx_drm_device();
614 struct of_phandle_args args
;
615 struct crtc_cookie
*c
;
619 if (!list_empty(&imx_drm_encoder
->possible_crtcs
))
622 for (i
= 0; !ret
; i
++) {
623 ret
= of_parse_phandle_with_args(np
, "crtcs",
624 "#crtc-cells", i
, &args
);
628 c
= kzalloc(sizeof(*c
), GFP_KERNEL
);
630 of_node_put(args
.np
);
635 c
->id
= args
.args_count
> 0 ? args
.args
[0] : 0;
637 of_node_put(args
.np
);
639 mutex_lock(&imxdrm
->mutex
);
641 list_add_tail(&c
->list
, &imx_drm_encoder
->possible_crtcs
);
643 mutex_unlock(&imxdrm
->mutex
);
646 imx_drm_update_possible_crtcs();
651 int imx_drm_encoder_get_mux_id(struct imx_drm_encoder
*imx_drm_encoder
,
652 struct drm_crtc
*crtc
)
654 struct imx_drm_device
*imxdrm
= __imx_drm_device();
655 struct imx_drm_crtc
*imx_crtc
;
658 mutex_lock(&imxdrm
->mutex
);
660 list_for_each_entry(imx_crtc
, &imxdrm
->crtc_list
, list
) {
661 if (imx_crtc
->crtc
== crtc
)
666 mutex_unlock(&imxdrm
->mutex
);
670 mutex_unlock(&imxdrm
->mutex
);
676 * imx_drm_remove_encoder - remove an encoder
678 int imx_drm_remove_encoder(struct imx_drm_encoder
*imx_drm_encoder
)
680 struct imx_drm_device
*imxdrm
= __imx_drm_device();
681 struct crtc_cookie
*c
, *tmp
;
683 mutex_lock(&imxdrm
->mutex
);
685 imx_drm_encoder_unregister(imx_drm_encoder
);
687 list_del(&imx_drm_encoder
->list
);
689 list_for_each_entry_safe(c
, tmp
, &imx_drm_encoder
->possible_crtcs
,
693 mutex_unlock(&imxdrm
->mutex
);
695 kfree(imx_drm_encoder
);
699 EXPORT_SYMBOL_GPL(imx_drm_remove_encoder
);
702 * imx_drm_add_connector - add a connector
704 int imx_drm_add_connector(struct drm_connector
*connector
,
705 struct imx_drm_connector
**new_con
,
706 struct module
*owner
)
708 struct imx_drm_device
*imxdrm
= __imx_drm_device();
709 struct imx_drm_connector
*imx_drm_connector
;
712 mutex_lock(&imxdrm
->mutex
);
714 if (imxdrm
->references
) {
719 imx_drm_connector
= kzalloc(sizeof(*imx_drm_connector
), GFP_KERNEL
);
720 if (!imx_drm_connector
) {
725 imx_drm_connector
->connector
= connector
;
726 imx_drm_connector
->owner
= owner
;
728 ret
= imx_drm_connector_register(imx_drm_connector
);
732 list_add_tail(&imx_drm_connector
->list
, &imxdrm
->connector_list
);
734 *new_con
= imx_drm_connector
;
736 mutex_unlock(&imxdrm
->mutex
);
741 kfree(imx_drm_connector
);
744 mutex_unlock(&imxdrm
->mutex
);
748 EXPORT_SYMBOL_GPL(imx_drm_add_connector
);
750 void imx_drm_fb_helper_set(struct drm_fbdev_cma
*fbdev_helper
)
752 struct imx_drm_device
*imxdrm
= __imx_drm_device();
754 imxdrm
->fbhelper
= fbdev_helper
;
756 EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set
);
759 * imx_drm_remove_connector - remove a connector
761 int imx_drm_remove_connector(struct imx_drm_connector
*imx_drm_connector
)
763 struct imx_drm_device
*imxdrm
= __imx_drm_device();
765 mutex_lock(&imxdrm
->mutex
);
767 imx_drm_connector_unregister(imx_drm_connector
);
769 list_del(&imx_drm_connector
->list
);
771 mutex_unlock(&imxdrm
->mutex
);
773 kfree(imx_drm_connector
);
777 EXPORT_SYMBOL_GPL(imx_drm_remove_connector
);
779 static struct drm_ioctl_desc imx_drm_ioctls
[] = {
783 static struct drm_driver imx_drm_driver
= {
784 .driver_features
= DRIVER_MODESET
| DRIVER_GEM
,
785 .load
= imx_drm_driver_load
,
786 .unload
= imx_drm_driver_unload
,
787 .firstopen
= imx_drm_driver_firstopen
,
788 .lastclose
= imx_drm_driver_lastclose
,
789 .gem_free_object
= drm_gem_cma_free_object
,
790 .gem_vm_ops
= &drm_gem_cma_vm_ops
,
791 .dumb_create
= drm_gem_cma_dumb_create
,
792 .dumb_map_offset
= drm_gem_cma_dumb_map_offset
,
793 .dumb_destroy
= drm_gem_cma_dumb_destroy
,
795 .get_vblank_counter
= drm_vblank_count
,
796 .enable_vblank
= imx_drm_enable_vblank
,
797 .disable_vblank
= imx_drm_disable_vblank
,
798 .ioctls
= imx_drm_ioctls
,
799 .num_ioctls
= ARRAY_SIZE(imx_drm_ioctls
),
800 .fops
= &imx_drm_driver_fops
,
802 .desc
= "i.MX DRM graphics",
809 static int imx_drm_platform_probe(struct platform_device
*pdev
)
811 imx_drm_device
->dev
= &pdev
->dev
;
813 return drm_platform_init(&imx_drm_driver
, pdev
);
816 static int imx_drm_platform_remove(struct platform_device
*pdev
)
818 drm_platform_exit(&imx_drm_driver
, pdev
);
823 static struct platform_driver imx_drm_pdrv
= {
824 .probe
= imx_drm_platform_probe
,
825 .remove
= __devexit_p(imx_drm_platform_remove
),
827 .owner
= THIS_MODULE
,
832 static struct platform_device
*imx_drm_pdev
;
834 static int __init
imx_drm_init(void)
838 imx_drm_device
= kzalloc(sizeof(*imx_drm_device
), GFP_KERNEL
);
842 mutex_init(&imx_drm_device
->mutex
);
843 INIT_LIST_HEAD(&imx_drm_device
->crtc_list
);
844 INIT_LIST_HEAD(&imx_drm_device
->connector_list
);
845 INIT_LIST_HEAD(&imx_drm_device
->encoder_list
);
847 imx_drm_pdev
= platform_device_register_simple("imx-drm", -1, NULL
, 0);
853 imx_drm_pdev
->dev
.coherent_dma_mask
= DMA_BIT_MASK(32),
855 ret
= platform_driver_register(&imx_drm_pdrv
);
862 platform_device_unregister(imx_drm_pdev
);
864 kfree(imx_drm_device
);
869 static void __exit
imx_drm_exit(void)
871 platform_device_unregister(imx_drm_pdev
);
872 platform_driver_unregister(&imx_drm_pdrv
);
874 kfree(imx_drm_device
);
877 module_init(imx_drm_init
);
878 module_exit(imx_drm_exit
);
880 MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
881 MODULE_DESCRIPTION("i.MX drm driver core");
882 MODULE_LICENSE("GPL");