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