xref: /linux/drivers/gpu/drm/exynos/exynos_drm_vidi.c (revision 4949009eb8d40a441dcddcd96e101e77d31cf1b2)
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 	if (mgr_ops && mgr_ops->commit)
120 		mgr_ops->commit(mgr);
121 }
122 
123 static void vidi_commit(struct exynos_drm_manager *mgr)
124 {
125 	struct vidi_context *ctx = manager_to_vidi(mgr);
126 
127 	if (ctx->suspended)
128 		return;
129 }
130 
131 static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
132 {
133 	struct vidi_context *ctx = manager_to_vidi(mgr);
134 
135 	if (ctx->suspended)
136 		return -EPERM;
137 
138 	if (!test_and_set_bit(0, &ctx->irq_flags))
139 		ctx->vblank_on = true;
140 
141 	ctx->direct_vblank = true;
142 
143 	/*
144 	 * in case of page flip request, vidi_finish_pageflip function
145 	 * will not be called because direct_vblank is true and then
146 	 * that function will be called by manager_ops->win_commit callback
147 	 */
148 	schedule_work(&ctx->work);
149 
150 	return 0;
151 }
152 
153 static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
154 {
155 	struct vidi_context *ctx = manager_to_vidi(mgr);
156 
157 	if (ctx->suspended)
158 		return;
159 
160 	if (test_and_clear_bit(0, &ctx->irq_flags))
161 		ctx->vblank_on = false;
162 }
163 
164 static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
165 			struct exynos_drm_overlay *overlay)
166 {
167 	struct vidi_context *ctx = manager_to_vidi(mgr);
168 	struct vidi_win_data *win_data;
169 	int win;
170 	unsigned long offset;
171 
172 	if (!overlay) {
173 		DRM_ERROR("overlay is NULL\n");
174 		return;
175 	}
176 
177 	win = overlay->zpos;
178 	if (win == DEFAULT_ZPOS)
179 		win = ctx->default_win;
180 
181 	if (win < 0 || win >= WINDOWS_NR)
182 		return;
183 
184 	offset = overlay->fb_x * (overlay->bpp >> 3);
185 	offset += overlay->fb_y * overlay->pitch;
186 
187 	DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
188 
189 	win_data = &ctx->win_data[win];
190 
191 	win_data->offset_x = overlay->crtc_x;
192 	win_data->offset_y = overlay->crtc_y;
193 	win_data->ovl_width = overlay->crtc_width;
194 	win_data->ovl_height = overlay->crtc_height;
195 	win_data->fb_width = overlay->fb_width;
196 	win_data->fb_height = overlay->fb_height;
197 	win_data->dma_addr = overlay->dma_addr[0] + offset;
198 	win_data->bpp = overlay->bpp;
199 	win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
200 				(overlay->bpp >> 3);
201 	win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
202 
203 	/*
204 	 * some parts of win_data should be transferred to user side
205 	 * through specific ioctl.
206 	 */
207 
208 	DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
209 			win_data->offset_x, win_data->offset_y);
210 	DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
211 			win_data->ovl_width, win_data->ovl_height);
212 	DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
213 	DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
214 			overlay->fb_width, overlay->crtc_width);
215 }
216 
217 static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
218 {
219 	struct vidi_context *ctx = manager_to_vidi(mgr);
220 	struct vidi_win_data *win_data;
221 	int win = zpos;
222 
223 	if (ctx->suspended)
224 		return;
225 
226 	if (win == DEFAULT_ZPOS)
227 		win = ctx->default_win;
228 
229 	if (win < 0 || win >= WINDOWS_NR)
230 		return;
231 
232 	win_data = &ctx->win_data[win];
233 
234 	win_data->enabled = true;
235 
236 	DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
237 
238 	if (ctx->vblank_on)
239 		schedule_work(&ctx->work);
240 }
241 
242 static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
243 {
244 	struct vidi_context *ctx = manager_to_vidi(mgr);
245 	struct vidi_win_data *win_data;
246 	int win = zpos;
247 
248 	if (win == DEFAULT_ZPOS)
249 		win = ctx->default_win;
250 
251 	if (win < 0 || win >= WINDOWS_NR)
252 		return;
253 
254 	win_data = &ctx->win_data[win];
255 	win_data->enabled = false;
256 
257 	/* TODO. */
258 }
259 
260 static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
261 {
262 	struct vidi_context *ctx = manager_to_vidi(mgr);
263 
264 	DRM_DEBUG_KMS("%s\n", __FILE__);
265 
266 	if (enable != false && enable != true)
267 		return -EINVAL;
268 
269 	if (enable) {
270 		ctx->suspended = false;
271 
272 		/* if vblank was enabled status, enable it again. */
273 		if (test_and_clear_bit(0, &ctx->irq_flags))
274 			vidi_enable_vblank(mgr);
275 
276 		vidi_apply(mgr);
277 	} else {
278 		ctx->suspended = true;
279 	}
280 
281 	return 0;
282 }
283 
284 static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
285 {
286 	struct vidi_context *ctx = manager_to_vidi(mgr);
287 
288 	DRM_DEBUG_KMS("%d\n", mode);
289 
290 	mutex_lock(&ctx->lock);
291 
292 	switch (mode) {
293 	case DRM_MODE_DPMS_ON:
294 		vidi_power_on(mgr, true);
295 		break;
296 	case DRM_MODE_DPMS_STANDBY:
297 	case DRM_MODE_DPMS_SUSPEND:
298 	case DRM_MODE_DPMS_OFF:
299 		vidi_power_on(mgr, false);
300 		break;
301 	default:
302 		DRM_DEBUG_KMS("unspecified mode %d\n", mode);
303 		break;
304 	}
305 
306 	mutex_unlock(&ctx->lock);
307 }
308 
309 static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
310 			struct drm_device *drm_dev)
311 {
312 	struct vidi_context *ctx = manager_to_vidi(mgr);
313 	struct exynos_drm_private *priv = drm_dev->dev_private;
314 
315 	mgr->drm_dev = ctx->drm_dev = drm_dev;
316 	mgr->pipe = ctx->pipe = priv->pipe++;
317 
318 	return 0;
319 }
320 
321 static struct exynos_drm_manager_ops vidi_manager_ops = {
322 	.dpms = vidi_dpms,
323 	.commit = vidi_commit,
324 	.enable_vblank = vidi_enable_vblank,
325 	.disable_vblank = vidi_disable_vblank,
326 	.win_mode_set = vidi_win_mode_set,
327 	.win_commit = vidi_win_commit,
328 	.win_disable = vidi_win_disable,
329 };
330 
331 static void vidi_fake_vblank_handler(struct work_struct *work)
332 {
333 	struct vidi_context *ctx = container_of(work, struct vidi_context,
334 					work);
335 
336 	if (ctx->pipe < 0)
337 		return;
338 
339 	/* refresh rate is about 50Hz. */
340 	usleep_range(16000, 20000);
341 
342 	mutex_lock(&ctx->lock);
343 
344 	if (ctx->direct_vblank) {
345 		drm_handle_vblank(ctx->drm_dev, ctx->pipe);
346 		ctx->direct_vblank = false;
347 		mutex_unlock(&ctx->lock);
348 		return;
349 	}
350 
351 	mutex_unlock(&ctx->lock);
352 
353 	exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
354 }
355 
356 static int vidi_show_connection(struct device *dev,
357 				struct device_attribute *attr, char *buf)
358 {
359 	struct vidi_context *ctx = dev_get_drvdata(dev);
360 	int rc;
361 
362 	mutex_lock(&ctx->lock);
363 
364 	rc = sprintf(buf, "%d\n", ctx->connected);
365 
366 	mutex_unlock(&ctx->lock);
367 
368 	return rc;
369 }
370 
371 static int vidi_store_connection(struct device *dev,
372 				struct device_attribute *attr,
373 				const char *buf, size_t len)
374 {
375 	struct vidi_context *ctx = dev_get_drvdata(dev);
376 	int ret;
377 
378 	ret = kstrtoint(buf, 0, &ctx->connected);
379 	if (ret)
380 		return ret;
381 
382 	if (ctx->connected > 1)
383 		return -EINVAL;
384 
385 	/* use fake edid data for test. */
386 	if (!ctx->raw_edid)
387 		ctx->raw_edid = (struct edid *)fake_edid_info;
388 
389 	/* if raw_edid isn't same as fake data then it can't be tested. */
390 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
391 		DRM_DEBUG_KMS("edid data is not fake data.\n");
392 		return -EINVAL;
393 	}
394 
395 	DRM_DEBUG_KMS("requested connection.\n");
396 
397 	drm_helper_hpd_irq_event(ctx->drm_dev);
398 
399 	return len;
400 }
401 
402 static DEVICE_ATTR(connection, 0644, vidi_show_connection,
403 			vidi_store_connection);
404 
405 int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
406 				struct drm_file *file_priv)
407 {
408 	struct vidi_context *ctx = NULL;
409 	struct drm_encoder *encoder;
410 	struct exynos_drm_display *display;
411 	struct drm_exynos_vidi_connection *vidi = data;
412 
413 	if (!vidi) {
414 		DRM_DEBUG_KMS("user data for vidi is null.\n");
415 		return -EINVAL;
416 	}
417 
418 	if (vidi->connection > 1) {
419 		DRM_DEBUG_KMS("connection should be 0 or 1.\n");
420 		return -EINVAL;
421 	}
422 
423 	list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
424 								head) {
425 		display = exynos_drm_get_display(encoder);
426 
427 		if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
428 			ctx = display_to_vidi(display);
429 			break;
430 		}
431 	}
432 
433 	if (!ctx) {
434 		DRM_DEBUG_KMS("not found virtual device type encoder.\n");
435 		return -EINVAL;
436 	}
437 
438 	if (ctx->connected == vidi->connection) {
439 		DRM_DEBUG_KMS("same connection request.\n");
440 		return -EINVAL;
441 	}
442 
443 	if (vidi->connection) {
444 		struct edid *raw_edid  = (struct edid *)(uint32_t)vidi->edid;
445 		if (!drm_edid_is_valid(raw_edid)) {
446 			DRM_DEBUG_KMS("edid data is invalid.\n");
447 			return -EINVAL;
448 		}
449 		ctx->raw_edid = drm_edid_duplicate(raw_edid);
450 		if (!ctx->raw_edid) {
451 			DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
452 			return -ENOMEM;
453 		}
454 	} else {
455 		/*
456 		 * with connection = 0, free raw_edid
457 		 * only if raw edid data isn't same as fake data.
458 		 */
459 		if (ctx->raw_edid && ctx->raw_edid !=
460 				(struct edid *)fake_edid_info) {
461 			kfree(ctx->raw_edid);
462 			ctx->raw_edid = NULL;
463 		}
464 	}
465 
466 	ctx->connected = vidi->connection;
467 	drm_helper_hpd_irq_event(ctx->drm_dev);
468 
469 	return 0;
470 }
471 
472 static enum drm_connector_status vidi_detect(struct drm_connector *connector,
473 			bool force)
474 {
475 	struct vidi_context *ctx = ctx_from_connector(connector);
476 
477 	/*
478 	 * connection request would come from user side
479 	 * to do hotplug through specific ioctl.
480 	 */
481 	return ctx->connected ? connector_status_connected :
482 			connector_status_disconnected;
483 }
484 
485 static void vidi_connector_destroy(struct drm_connector *connector)
486 {
487 }
488 
489 static struct drm_connector_funcs vidi_connector_funcs = {
490 	.dpms = drm_helper_connector_dpms,
491 	.fill_modes = drm_helper_probe_single_connector_modes,
492 	.detect = vidi_detect,
493 	.destroy = vidi_connector_destroy,
494 };
495 
496 static int vidi_get_modes(struct drm_connector *connector)
497 {
498 	struct vidi_context *ctx = ctx_from_connector(connector);
499 	struct edid *edid;
500 	int edid_len;
501 
502 	/*
503 	 * the edid data comes from user side and it would be set
504 	 * to ctx->raw_edid through specific ioctl.
505 	 */
506 	if (!ctx->raw_edid) {
507 		DRM_DEBUG_KMS("raw_edid is null.\n");
508 		return -EFAULT;
509 	}
510 
511 	edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
512 	edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
513 	if (!edid) {
514 		DRM_DEBUG_KMS("failed to allocate edid\n");
515 		return -ENOMEM;
516 	}
517 
518 	drm_mode_connector_update_edid_property(connector, edid);
519 
520 	return drm_add_edid_modes(connector, edid);
521 }
522 
523 static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
524 {
525 	struct vidi_context *ctx = ctx_from_connector(connector);
526 
527 	return ctx->encoder;
528 }
529 
530 static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
531 	.get_modes = vidi_get_modes,
532 	.best_encoder = vidi_best_encoder,
533 };
534 
535 static int vidi_create_connector(struct exynos_drm_display *display,
536 				struct drm_encoder *encoder)
537 {
538 	struct vidi_context *ctx = display_to_vidi(display);
539 	struct drm_connector *connector = &ctx->connector;
540 	int ret;
541 
542 	ctx->encoder = encoder;
543 	connector->polled = DRM_CONNECTOR_POLL_HPD;
544 
545 	ret = drm_connector_init(ctx->drm_dev, connector,
546 			&vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
547 	if (ret) {
548 		DRM_ERROR("Failed to initialize connector with drm\n");
549 		return ret;
550 	}
551 
552 	drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
553 	drm_connector_register(connector);
554 	drm_mode_connector_attach_encoder(connector, encoder);
555 
556 	return 0;
557 }
558 
559 
560 static struct exynos_drm_display_ops vidi_display_ops = {
561 	.create_connector = vidi_create_connector,
562 };
563 
564 static int vidi_bind(struct device *dev, struct device *master, void *data)
565 {
566 	struct vidi_context *ctx = dev_get_drvdata(dev);
567 	struct drm_device *drm_dev = data;
568 	struct drm_crtc *crtc = ctx->crtc;
569 	int ret;
570 
571 	vidi_mgr_initialize(&ctx->manager, drm_dev);
572 
573 	ret = exynos_drm_crtc_create(&ctx->manager);
574 	if (ret) {
575 		DRM_ERROR("failed to create crtc.\n");
576 		return ret;
577 	}
578 
579 	ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
580 	if (ret) {
581 		crtc->funcs->destroy(crtc);
582 		DRM_ERROR("failed to create encoder and connector.\n");
583 		return ret;
584 	}
585 
586 	return 0;
587 }
588 
589 
590 static void vidi_unbind(struct device *dev, struct device *master, void *data)
591 {
592 }
593 
594 static const struct component_ops vidi_component_ops = {
595 	.bind	= vidi_bind,
596 	.unbind = vidi_unbind,
597 };
598 
599 static int vidi_probe(struct platform_device *pdev)
600 {
601 	struct vidi_context *ctx;
602 	int ret;
603 
604 	ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
605 	if (!ctx)
606 		return -ENOMEM;
607 
608 	ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
609 	ctx->manager.ops = &vidi_manager_ops;
610 	ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
611 	ctx->display.ops = &vidi_display_ops;
612 	ctx->default_win = 0;
613 	ctx->pdev = pdev;
614 
615 	ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
616 					ctx->manager.type);
617 	if (ret)
618 		return ret;
619 
620 	ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR,
621 					ctx->display.type);
622 	if (ret)
623 		goto err_del_crtc_component;
624 
625 	INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
626 
627 	mutex_init(&ctx->lock);
628 
629 	platform_set_drvdata(pdev, ctx);
630 
631 	ret = device_create_file(&pdev->dev, &dev_attr_connection);
632 	if (ret < 0) {
633 		DRM_ERROR("failed to create connection sysfs.\n");
634 		goto err_del_conn_component;
635 	}
636 
637 	ret = component_add(&pdev->dev, &vidi_component_ops);
638 	if (ret)
639 		goto err_remove_file;
640 
641 	return ret;
642 
643 err_remove_file:
644 	device_remove_file(&pdev->dev, &dev_attr_connection);
645 err_del_conn_component:
646 	exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
647 err_del_crtc_component:
648 	exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
649 
650 	return ret;
651 }
652 
653 static int vidi_remove(struct platform_device *pdev)
654 {
655 	struct vidi_context *ctx = platform_get_drvdata(pdev);
656 
657 	if (ctx->raw_edid != (struct edid *)fake_edid_info) {
658 		kfree(ctx->raw_edid);
659 		ctx->raw_edid = NULL;
660 
661 		return -EINVAL;
662 	}
663 
664 	component_del(&pdev->dev, &vidi_component_ops);
665 	exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
666 	exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
667 
668 	return 0;
669 }
670 
671 struct platform_driver vidi_driver = {
672 	.probe		= vidi_probe,
673 	.remove		= vidi_remove,
674 	.driver		= {
675 		.name	= "exynos-drm-vidi",
676 		.owner	= THIS_MODULE,
677 	},
678 };
679 
680 int exynos_drm_probe_vidi(void)
681 {
682 	struct platform_device *pdev;
683 	int ret;
684 
685 	pdev = platform_device_register_simple("exynos-drm-vidi", -1, NULL, 0);
686 	if (IS_ERR(pdev))
687 		return PTR_ERR(pdev);
688 
689 	ret = platform_driver_register(&vidi_driver);
690 	if (ret) {
691 		platform_device_unregister(pdev);
692 		return ret;
693 	}
694 
695 	return ret;
696 }
697 
698 static int exynos_drm_remove_vidi_device(struct device *dev, void *data)
699 {
700 	platform_device_unregister(to_platform_device(dev));
701 
702 	return 0;
703 }
704 
705 void exynos_drm_remove_vidi(void)
706 {
707 	int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
708 					 exynos_drm_remove_vidi_device);
709 	/* silence compiler warning */
710 	(void)ret;
711 
712 	platform_driver_unregister(&vidi_driver);
713 }
714