drm/exynos/vidi: stop using display->ctx pointer
[linux-drm-fsl-dcu.git] / drivers / gpu / drm / exynos / exynos_drm_vidi.c
1 /* exynos_drm_vidi.c
2  *
3  * Copyright (C) 2012 Samsung Electronics Co.Ltd
4  * Authors:
5  *      Inki Dae <inki.dae@samsung.com>
6  *
7  * This program is free software; you can redistribute  it and/or modify it
8  * under  the terms of  the GNU General  Public License as published by the
9  * Free Software Foundation;  either version 2 of the  License, or (at your
10  * option) any later version.
11  *
12  */
13 #include <drm/drmP.h>
14
15 #include <linux/kernel.h>
16 #include <linux/platform_device.h>
17
18 #include <drm/exynos_drm.h>
19
20 #include <drm/drm_edid.h>
21 #include <drm/drm_crtc_helper.h>
22
23 #include "exynos_drm_drv.h"
24 #include "exynos_drm_crtc.h"
25 #include "exynos_drm_encoder.h"
26 #include "exynos_drm_vidi.h"
27
28 /* vidi has totally three virtual windows. */
29 #define WINDOWS_NR              3
30
31 #define ctx_from_connector(c)   container_of(c, struct vidi_context, \
32                                         connector)
33
34 struct vidi_win_data {
35         unsigned int            offset_x;
36         unsigned int            offset_y;
37         unsigned int            ovl_width;
38         unsigned int            ovl_height;
39         unsigned int            fb_width;
40         unsigned int            fb_height;
41         unsigned int            bpp;
42         dma_addr_t              dma_addr;
43         unsigned int            buf_offsize;
44         unsigned int            line_size;      /* bytes */
45         bool                    enabled;
46 };
47
48 struct vidi_context {
49         struct exynos_drm_manager       manager;
50         struct exynos_drm_display       display;
51         struct drm_device               *drm_dev;
52         struct drm_crtc                 *crtc;
53         struct drm_encoder              *encoder;
54         struct drm_connector            connector;
55         struct exynos_drm_subdrv        subdrv;
56         struct vidi_win_data            win_data[WINDOWS_NR];
57         struct edid                     *raw_edid;
58         unsigned int                    clkdiv;
59         unsigned int                    default_win;
60         unsigned long                   irq_flags;
61         unsigned int                    connected;
62         bool                            vblank_on;
63         bool                            suspended;
64         bool                            direct_vblank;
65         struct work_struct              work;
66         struct mutex                    lock;
67         int                             pipe;
68 };
69
70 static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
71 {
72         return container_of(m, struct vidi_context, manager);
73 }
74
75 static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
76 {
77         return container_of(d, struct vidi_context, display);
78 }
79
80 static const char fake_edid_info[] = {
81         0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
82         0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
83         0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
84         0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
85         0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
86         0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
87         0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
88         0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
89         0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
90         0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
91         0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
92         0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
93         0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
94         0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
95         0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
96         0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
97         0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
98         0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
99         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
100         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
101         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102         0x00, 0x00, 0x00, 0x06
103 };
104
105 static void vidi_apply(struct exynos_drm_manager *mgr)
106 {
107         struct vidi_context *ctx = manager_to_vidi(mgr);
108         struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
109         struct vidi_win_data *win_data;
110         int i;
111
112         for (i = 0; i < WINDOWS_NR; i++) {
113                 win_data = &ctx->win_data[i];
114                 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
115                         mgr_ops->win_commit(mgr, i);
116         }
117
118         if (mgr_ops && mgr_ops->commit)
119                 mgr_ops->commit(mgr);
120 }
121
122 static void vidi_commit(struct exynos_drm_manager *mgr)
123 {
124         struct vidi_context *ctx = manager_to_vidi(mgr);
125
126         if (ctx->suspended)
127                 return;
128 }
129
130 static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
131 {
132         struct vidi_context *ctx = manager_to_vidi(mgr);
133
134         if (ctx->suspended)
135                 return -EPERM;
136
137         if (!test_and_set_bit(0, &ctx->irq_flags))
138                 ctx->vblank_on = true;
139
140         ctx->direct_vblank = true;
141
142         /*
143          * in case of page flip request, vidi_finish_pageflip function
144          * will not be called because direct_vblank is true and then
145          * that function will be called by manager_ops->win_commit callback
146          */
147         schedule_work(&ctx->work);
148
149         return 0;
150 }
151
152 static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
153 {
154         struct vidi_context *ctx = manager_to_vidi(mgr);
155
156         if (ctx->suspended)
157                 return;
158
159         if (test_and_clear_bit(0, &ctx->irq_flags))
160                 ctx->vblank_on = false;
161 }
162
163 static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
164                         struct exynos_drm_overlay *overlay)
165 {
166         struct vidi_context *ctx = manager_to_vidi(mgr);
167         struct vidi_win_data *win_data;
168         int win;
169         unsigned long offset;
170
171         if (!overlay) {
172                 DRM_ERROR("overlay is NULL\n");
173                 return;
174         }
175
176         win = overlay->zpos;
177         if (win == DEFAULT_ZPOS)
178                 win = ctx->default_win;
179
180         if (win < 0 || win >= WINDOWS_NR)
181                 return;
182
183         offset = overlay->fb_x * (overlay->bpp >> 3);
184         offset += overlay->fb_y * overlay->pitch;
185
186         DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
187
188         win_data = &ctx->win_data[win];
189
190         win_data->offset_x = overlay->crtc_x;
191         win_data->offset_y = overlay->crtc_y;
192         win_data->ovl_width = overlay->crtc_width;
193         win_data->ovl_height = overlay->crtc_height;
194         win_data->fb_width = overlay->fb_width;
195         win_data->fb_height = overlay->fb_height;
196         win_data->dma_addr = overlay->dma_addr[0] + offset;
197         win_data->bpp = overlay->bpp;
198         win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
199                                 (overlay->bpp >> 3);
200         win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
201
202         /*
203          * some parts of win_data should be transferred to user side
204          * through specific ioctl.
205          */
206
207         DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
208                         win_data->offset_x, win_data->offset_y);
209         DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
210                         win_data->ovl_width, win_data->ovl_height);
211         DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
212         DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
213                         overlay->fb_width, overlay->crtc_width);
214 }
215
216 static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
217 {
218         struct vidi_context *ctx = manager_to_vidi(mgr);
219         struct vidi_win_data *win_data;
220         int win = zpos;
221
222         if (ctx->suspended)
223                 return;
224
225         if (win == DEFAULT_ZPOS)
226                 win = ctx->default_win;
227
228         if (win < 0 || win >= WINDOWS_NR)
229                 return;
230
231         win_data = &ctx->win_data[win];
232
233         win_data->enabled = true;
234
235         DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
236
237         if (ctx->vblank_on)
238                 schedule_work(&ctx->work);
239 }
240
241 static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
242 {
243         struct vidi_context *ctx = manager_to_vidi(mgr);
244         struct vidi_win_data *win_data;
245         int win = zpos;
246
247         if (win == DEFAULT_ZPOS)
248                 win = ctx->default_win;
249
250         if (win < 0 || win >= WINDOWS_NR)
251                 return;
252
253         win_data = &ctx->win_data[win];
254         win_data->enabled = false;
255
256         /* TODO. */
257 }
258
259 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
260 {
261         struct vidi_context *ctx = manager_to_vidi(mgr);
262
263         DRM_DEBUG_KMS("%s\n", __FILE__);
264
265         if (enable != false && enable != true)
266                 return -EINVAL;
267
268         if (enable) {
269                 ctx->suspended = false;
270
271                 /* if vblank was enabled status, enable it again. */
272                 if (test_and_clear_bit(0, &ctx->irq_flags))
273                         vidi_enable_vblank(mgr);
274
275                 vidi_apply(mgr);
276         } else {
277                 ctx->suspended = true;
278         }
279
280         return 0;
281 }
282
283 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
284 {
285         struct vidi_context *ctx = manager_to_vidi(mgr);
286
287         DRM_DEBUG_KMS("%d\n", mode);
288
289         mutex_lock(&ctx->lock);
290
291         switch (mode) {
292         case DRM_MODE_DPMS_ON:
293                 vidi_power_on(mgr, true);
294                 break;
295         case DRM_MODE_DPMS_STANDBY:
296         case DRM_MODE_DPMS_SUSPEND:
297         case DRM_MODE_DPMS_OFF:
298                 vidi_power_on(mgr, false);
299                 break;
300         default:
301                 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
302                 break;
303         }
304
305         mutex_unlock(&ctx->lock);
306 }
307
308 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
309                         struct drm_device *drm_dev)
310 {
311         struct vidi_context *ctx = manager_to_vidi(mgr);
312         struct exynos_drm_private *priv = drm_dev->dev_private;
313
314         mgr->drm_dev = ctx->drm_dev = drm_dev;
315         mgr->pipe = ctx->pipe = priv->pipe++;
316
317         return 0;
318 }
319
320 static struct exynos_drm_manager_ops vidi_manager_ops = {
321         .dpms = vidi_dpms,
322         .commit = vidi_commit,
323         .enable_vblank = vidi_enable_vblank,
324         .disable_vblank = vidi_disable_vblank,
325         .win_mode_set = vidi_win_mode_set,
326         .win_commit = vidi_win_commit,
327         .win_disable = vidi_win_disable,
328 };
329
330 static void vidi_fake_vblank_handler(struct work_struct *work)
331 {
332         struct vidi_context *ctx = container_of(work, struct vidi_context,
333                                         work);
334
335         if (ctx->pipe < 0)
336                 return;
337
338         /* refresh rate is about 50Hz. */
339         usleep_range(16000, 20000);
340
341         mutex_lock(&ctx->lock);
342
343         if (ctx->direct_vblank) {
344                 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
345                 ctx->direct_vblank = false;
346                 mutex_unlock(&ctx->lock);
347                 return;
348         }
349
350         mutex_unlock(&ctx->lock);
351
352         exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
353 }
354
355 static int vidi_show_connection(struct device *dev,
356                                 struct device_attribute *attr, char *buf)
357 {
358         struct vidi_context *ctx = dev_get_drvdata(dev);
359         int rc;
360
361         mutex_lock(&ctx->lock);
362
363         rc = sprintf(buf, "%d\n", ctx->connected);
364
365         mutex_unlock(&ctx->lock);
366
367         return rc;
368 }
369
370 static int vidi_store_connection(struct device *dev,
371                                 struct device_attribute *attr,
372                                 const char *buf, size_t len)
373 {
374         struct vidi_context *ctx = dev_get_drvdata(dev);
375         int ret;
376
377         ret = kstrtoint(buf, 0, &ctx->connected);
378         if (ret)
379                 return ret;
380
381         if (ctx->connected > 1)
382                 return -EINVAL;
383
384         /* use fake edid data for test. */
385         if (!ctx->raw_edid)
386                 ctx->raw_edid = (struct edid *)fake_edid_info;
387
388         /* if raw_edid isn't same as fake data then it can't be tested. */
389         if (ctx->raw_edid != (struct edid *)fake_edid_info) {
390                 DRM_DEBUG_KMS("edid data is not fake data.\n");
391                 return -EINVAL;
392         }
393
394         DRM_DEBUG_KMS("requested connection.\n");
395
396         drm_helper_hpd_irq_event(ctx->drm_dev);
397
398         return len;
399 }
400
401 static DEVICE_ATTR(connection, 0644, vidi_show_connection,
402                         vidi_store_connection);
403
404 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
405                                 struct drm_file *file_priv)
406 {
407         struct vidi_context *ctx = NULL;
408         struct drm_encoder *encoder;
409         struct exynos_drm_display *display;
410         struct drm_exynos_vidi_connection *vidi = data;
411
412         if (!vidi) {
413                 DRM_DEBUG_KMS("user data for vidi is null.\n");
414                 return -EINVAL;
415         }
416
417         if (vidi->connection > 1) {
418                 DRM_DEBUG_KMS("connection should be 0 or 1.\n");
419                 return -EINVAL;
420         }
421
422         list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
423                                                                 head) {
424                 display = exynos_drm_get_display(encoder);
425
426                 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
427                         ctx = display_to_vidi(display);
428                         break;
429                 }
430         }
431
432         if (!ctx) {
433                 DRM_DEBUG_KMS("not found virtual device type encoder.\n");
434                 return -EINVAL;
435         }
436
437         if (ctx->connected == vidi->connection) {
438                 DRM_DEBUG_KMS("same connection request.\n");
439                 return -EINVAL;
440         }
441
442         if (vidi->connection) {
443                 struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
444                 if (!drm_edid_is_valid(raw_edid)) {
445                         DRM_DEBUG_KMS("edid data is invalid.\n");
446                         return -EINVAL;
447                 }
448                 ctx->raw_edid = drm_edid_duplicate(raw_edid);
449                 if (!ctx->raw_edid) {
450                         DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
451                         return -ENOMEM;
452                 }
453         } else {
454                 /*
455                  * with connection = 0, free raw_edid
456                  * only if raw edid data isn't same as fake data.
457                  */
458                 if (ctx->raw_edid && ctx->raw_edid !=
459                                 (struct edid *)fake_edid_info) {
460                         kfree(ctx->raw_edid);
461                         ctx->raw_edid = NULL;
462                 }
463         }
464
465         ctx->connected = vidi->connection;
466         drm_helper_hpd_irq_event(ctx->drm_dev);
467
468         return 0;
469 }
470
471 static enum drm_connector_status vidi_detect(struct drm_connector *connector,
472                         bool force)
473 {
474         struct vidi_context *ctx = ctx_from_connector(connector);
475
476         /*
477          * connection request would come from user side
478          * to do hotplug through specific ioctl.
479          */
480         return ctx->connected ? connector_status_connected :
481                         connector_status_disconnected;
482 }
483
484 static void vidi_connector_destroy(struct drm_connector *connector)
485 {
486 }
487
488 static struct drm_connector_funcs vidi_connector_funcs = {
489         .dpms = drm_helper_connector_dpms,
490         .fill_modes = drm_helper_probe_single_connector_modes,
491         .detect = vidi_detect,
492         .destroy = vidi_connector_destroy,
493 };
494
495 static int vidi_get_modes(struct drm_connector *connector)
496 {
497         struct vidi_context *ctx = ctx_from_connector(connector);
498         struct edid *edid;
499         int edid_len;
500
501         /*
502          * the edid data comes from user side and it would be set
503          * to ctx->raw_edid through specific ioctl.
504          */
505         if (!ctx->raw_edid) {
506                 DRM_DEBUG_KMS("raw_edid is null.\n");
507                 return -EFAULT;
508         }
509
510         edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
511         edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
512         if (!edid) {
513                 DRM_DEBUG_KMS("failed to allocate edid\n");
514                 return -ENOMEM;
515         }
516
517         drm_mode_connector_update_edid_property(connector, edid);
518
519         return drm_add_edid_modes(connector, edid);
520 }
521
522 static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
523 {
524         struct vidi_context *ctx = ctx_from_connector(connector);
525
526         return ctx->encoder;
527 }
528
529 static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
530         .get_modes = vidi_get_modes,
531         .best_encoder = vidi_best_encoder,
532 };
533
534 static int vidi_create_connector(struct exynos_drm_display *display,
535                                 struct drm_encoder *encoder)
536 {
537         struct vidi_context *ctx = display_to_vidi(display);
538         struct drm_connector *connector = &ctx->connector;
539         int ret;
540
541         ctx->encoder = encoder;
542         connector->polled = DRM_CONNECTOR_POLL_HPD;
543
544         ret = drm_connector_init(ctx->drm_dev, connector,
545                         &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
546         if (ret) {
547                 DRM_ERROR("Failed to initialize connector with drm\n");
548                 return ret;
549         }
550
551         drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
552         drm_connector_register(connector);
553         drm_mode_connector_attach_encoder(connector, encoder);
554
555         return 0;
556 }
557
558
559 static struct exynos_drm_display_ops vidi_display_ops = {
560         .create_connector = vidi_create_connector,
561 };
562
563 static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
564 {
565         struct vidi_context *ctx = dev_get_drvdata(dev);
566         struct drm_crtc *crtc = ctx->crtc;
567         int ret;
568
569         vidi_mgr_initialize(&ctx->manager, drm_dev);
570
571         ret = exynos_drm_crtc_create(&ctx->manager);
572         if (ret) {
573                 DRM_ERROR("failed to create crtc.\n");
574                 return ret;
575         }
576
577         ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
578         if (ret) {
579                 crtc->funcs->destroy(crtc);
580                 DRM_ERROR("failed to create encoder and connector.\n");
581                 return ret;
582         }
583
584         return 0;
585 }
586
587 static int vidi_probe(struct platform_device *pdev)
588 {
589         struct exynos_drm_subdrv *subdrv;
590         struct vidi_context *ctx;
591         int ret;
592
593         ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
594         if (!ctx)
595                 return -ENOMEM;
596
597         ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
598         ctx->manager.ops = &vidi_manager_ops;
599         ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
600         ctx->display.ops = &vidi_display_ops;
601         ctx->default_win = 0;
602
603         INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
604
605         mutex_init(&ctx->lock);
606
607         platform_set_drvdata(pdev, ctx);
608
609         subdrv = &ctx->subdrv;
610         subdrv->dev = &pdev->dev;
611         subdrv->probe = vidi_subdrv_probe;
612
613         ret = exynos_drm_subdrv_register(subdrv);
614         if (ret < 0) {
615                 dev_err(&pdev->dev, "failed to register drm vidi device\n");
616                 return ret;
617         }
618
619         ret = device_create_file(&pdev->dev, &dev_attr_connection);
620         if (ret < 0) {
621                 exynos_drm_subdrv_unregister(subdrv);
622                 DRM_INFO("failed to create connection sysfs.\n");
623         }
624
625         return 0;
626 }
627
628 static int vidi_remove(struct platform_device *pdev)
629 {
630         struct vidi_context *ctx = platform_get_drvdata(pdev);
631
632         if (ctx->raw_edid != (struct edid *)fake_edid_info) {
633                 kfree(ctx->raw_edid);
634                 ctx->raw_edid = NULL;
635
636                 return -EINVAL;
637         }
638
639         return 0;
640 }
641
642 struct platform_driver vidi_driver = {
643         .probe          = vidi_probe,
644         .remove         = vidi_remove,
645         .driver         = {
646                 .name   = "exynos-drm-vidi",
647                 .owner  = THIS_MODULE,
648         },
649 };
650
651 int exynos_drm_probe_vidi(void)
652 {
653         struct platform_device *pdev;
654         int ret;
655
656         pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
657         if (IS_ERR(pdev))
658                 return PTR_ERR(pdev);
659
660         ret = platform_driver_register(&vidi_driver);
661         if (ret) {
662                 platform_device_unregister(pdev);
663                 return ret;
664         }
665
666         return ret;
667 }
668
669 static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
670 {
671         platform_device_unregister(to_platform_device(dev));
672
673         return 0;
674 }
675
676 void exynos_drm_remove_vidi(void)
677 {
678         int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
679                                          exynos_drm_remove_vidi_device);
680         /* silence compiler warning */
681         (void)ret;
682
683         platform_driver_unregister(&vidi_driver);
684 }