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