drm/exynos: remove drm_dev from struct exynos_drm_manager
[deliverable/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 <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 */
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>
b73d1230
ID
23
24#include "exynos_drm_drv.h"
25#include "exynos_drm_crtc.h"
26#include "exynos_drm_encoder.h"
e30655d0 27#include "exynos_drm_vidi.h"
b73d1230
ID
28
29/* vidi has totally three virtual windows. */
30#define WINDOWS_NR 3
31
ce6cb556
SP
32#define ctx_from_connector(c) container_of(c, struct vidi_context, \
33 connector)
b73d1230
ID
34
35struct 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;
b73d1230
ID
44 unsigned int buf_offsize;
45 unsigned int line_size; /* bytes */
46 bool enabled;
47};
48
49struct vidi_context {
f01833cd 50 struct exynos_drm_manager manager;
7340426a 51 struct exynos_drm_display display;
1d50aa9c 52 struct platform_device *pdev;
080be03d 53 struct drm_device *drm_dev;
b73d1230 54 struct drm_crtc *crtc;
ce6cb556
SP
55 struct drm_encoder *encoder;
56 struct drm_connector connector;
b73d1230
ID
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;
291257cf 65 bool direct_vblank;
b73d1230
ID
66 struct work_struct work;
67 struct mutex lock;
080be03d 68 int pipe;
b73d1230
ID
69};
70
e1819aad
AH
71static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
72{
73 return container_of(m, struct vidi_context, manager);
74}
75
2f26bd72
AH
76static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
77{
78 return container_of(d, struct vidi_context, display);
79}
80
b73d1230
ID
81static 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
bb7704d6 106static void vidi_apply(struct exynos_drm_manager *mgr)
b73d1230 107{
e1819aad 108 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230 109 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
b73d1230
ID
110 struct vidi_win_data *win_data;
111 int i;
112
b73d1230
ID
113 for (i = 0; i < WINDOWS_NR; i++) {
114 win_data = &ctx->win_data[i];
1c6244c3 115 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
bb7704d6 116 mgr_ops->win_commit(mgr, i);
b73d1230 117 }
b73d1230
ID
118}
119
bb7704d6 120static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
b73d1230 121{
e1819aad 122 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230 123
b73d1230
ID
124 if (ctx->suspended)
125 return -EPERM;
126
127 if (!test_and_set_bit(0, &ctx->irq_flags))
128 ctx->vblank_on = true;
129
291257cf
ID
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
1c6244c3 135 * that function will be called by manager_ops->win_commit callback
291257cf
ID
136 */
137 schedule_work(&ctx->work);
138
b73d1230
ID
139 return 0;
140}
141
bb7704d6 142static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
b73d1230 143{
e1819aad 144 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230 145
b73d1230
ID
146 if (ctx->suspended)
147 return;
148
149 if (test_and_clear_bit(0, &ctx->irq_flags))
150 ctx->vblank_on = false;
151}
152
bb7704d6 153static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
8837deea 154 struct exynos_drm_plane *plane)
b73d1230 155{
e1819aad 156 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230
ID
157 struct vidi_win_data *win_data;
158 int win;
159 unsigned long offset;
160
8837deea
GP
161 if (!plane) {
162 DRM_ERROR("plane is NULL\n");
b73d1230
ID
163 return;
164 }
165
8837deea 166 win = plane->zpos;
b73d1230
ID
167 if (win == DEFAULT_ZPOS)
168 win = ctx->default_win;
169
a7f98d6a 170 if (win < 0 || win >= WINDOWS_NR)
b73d1230
ID
171 return;
172
8837deea
GP
173 offset = plane->fb_x * (plane->bpp >> 3);
174 offset += plane->fb_y * plane->pitch;
b73d1230 175
8837deea 176 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
b73d1230
ID
177
178 win_data = &ctx->win_data[win];
179
8837deea
GP
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);
b73d1230
ID
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);
ddd8e959 201 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
b73d1230 202 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
8837deea 203 plane->fb_width, plane->crtc_width);
b73d1230
ID
204}
205
bb7704d6 206static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
b73d1230 207{
e1819aad 208 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230
ID
209 struct vidi_win_data *win_data;
210 int win = zpos;
211
b73d1230
ID
212 if (ctx->suspended)
213 return;
214
215 if (win == DEFAULT_ZPOS)
216 win = ctx->default_win;
217
a7f98d6a 218 if (win < 0 || win >= WINDOWS_NR)
b73d1230
ID
219 return;
220
221 win_data = &ctx->win_data[win];
222
223 win_data->enabled = true;
224
b8eade24 225 DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
b73d1230
ID
226
227 if (ctx->vblank_on)
228 schedule_work(&ctx->work);
229}
230
bb7704d6 231static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
b73d1230 232{
e1819aad 233 struct vidi_context *ctx = manager_to_vidi(mgr);
b73d1230
ID
234 struct vidi_win_data *win_data;
235 int win = zpos;
236
b73d1230
ID
237 if (win == DEFAULT_ZPOS)
238 win = ctx->default_win;
239
a7f98d6a 240 if (win < 0 || win >= WINDOWS_NR)
b73d1230
ID
241 return;
242
243 win_data = &ctx->win_data[win];
244 win_data->enabled = false;
245
246 /* TODO. */
247}
248
af65c804
SP
249static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
250{
e1819aad 251 struct vidi_context *ctx = manager_to_vidi(mgr);
af65c804
SP
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
273static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
274{
e1819aad 275 struct vidi_context *ctx = manager_to_vidi(mgr);
af65c804
SP
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
080be03d 298static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
f37cd5e8 299 struct drm_device *drm_dev)
080be03d 300{
e1819aad 301 struct vidi_context *ctx = manager_to_vidi(mgr);
f37cd5e8 302 struct exynos_drm_private *priv = drm_dev->dev_private;
080be03d 303
eb88e422 304 ctx->drm_dev = drm_dev;
8a326edd 305 ctx->pipe = priv->pipe++;
080be03d 306
080be03d
SP
307 return 0;
308}
309
1c6244c3
SP
310static struct exynos_drm_manager_ops vidi_manager_ops = {
311 .dpms = vidi_dpms,
1c6244c3
SP
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,
b73d1230
ID
317};
318
b73d1230
ID
319static void vidi_fake_vblank_handler(struct work_struct *work)
320{
321 struct vidi_context *ctx = container_of(work, struct vidi_context,
322 work);
b73d1230 323
080be03d 324 if (ctx->pipe < 0)
b73d1230
ID
325 return;
326
327 /* refresh rate is about 50Hz. */
328 usleep_range(16000, 20000);
329
291257cf
ID
330 mutex_lock(&ctx->lock);
331
332 if (ctx->direct_vblank) {
080be03d 333 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
291257cf
ID
334 ctx->direct_vblank = false;
335 mutex_unlock(&ctx->lock);
336 return;
337 }
338
339 mutex_unlock(&ctx->lock);
340
080be03d 341 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
b73d1230
ID
342}
343
b73d1230
ID
344static int vidi_show_connection(struct device *dev,
345 struct device_attribute *attr, char *buf)
346{
f01833cd 347 struct vidi_context *ctx = dev_get_drvdata(dev);
b73d1230 348 int rc;
b73d1230
ID
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
359static int vidi_store_connection(struct device *dev,
360 struct device_attribute *attr,
361 const char *buf, size_t len)
362{
f01833cd 363 struct vidi_context *ctx = dev_get_drvdata(dev);
b73d1230
ID
364 int ret;
365
b73d1230
ID
366 ret = kstrtoint(buf, 0, &ctx->connected);
367 if (ret)
368 return ret;
369
370 if (ctx->connected > 1)
371 return -EINVAL;
372
d07d39df
ID
373 /* use fake edid data for test. */
374 if (!ctx->raw_edid)
375 ctx->raw_edid = (struct edid *)fake_edid_info;
376
d7b8478a
ID
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
b73d1230
ID
383 DRM_DEBUG_KMS("requested connection.\n");
384
080be03d 385 drm_helper_hpd_irq_event(ctx->drm_dev);
b73d1230
ID
386
387 return len;
388}
389
390static DEVICE_ATTR(connection, 0644, vidi_show_connection,
391 vidi_store_connection);
392
393int 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;
080be03d 398 struct exynos_drm_display *display;
b73d1230
ID
399 struct drm_exynos_vidi_connection *vidi = data;
400
b73d1230
ID
401 if (!vidi) {
402 DRM_DEBUG_KMS("user data for vidi is null.\n");
403 return -EINVAL;
404 }
405
b73d1230
ID
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) {
080be03d 413 display = exynos_drm_get_display(encoder);
b73d1230 414
080be03d 415 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
2f26bd72 416 ctx = display_to_vidi(display);
b73d1230
ID
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
d3b62dbf 431 if (vidi->connection) {
e7808df1
SWK
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");
d3b62dbf
ID
435 return -EINVAL;
436 }
4ddc773b 437 ctx->raw_edid = drm_edid_duplicate(raw_edid);
d3b62dbf
ID
438 if (!ctx->raw_edid) {
439 DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
440 return -ENOMEM;
441 }
d3b62dbf
ID
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 }
b73d1230
ID
453
454 ctx->connected = vidi->connection;
080be03d 455 drm_helper_hpd_irq_event(ctx->drm_dev);
b73d1230
ID
456
457 return 0;
458}
459
ce6cb556
SP
460static 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
473static void vidi_connector_destroy(struct drm_connector *connector)
474{
475}
476
477static 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
484static 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
ce6cb556
SP
511static 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
518static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
519 .get_modes = vidi_get_modes,
ce6cb556
SP
520 .best_encoder = vidi_best_encoder,
521};
522
523static int vidi_create_connector(struct exynos_drm_display *display,
524 struct drm_encoder *encoder)
525{
2f26bd72 526 struct vidi_context *ctx = display_to_vidi(display);
ce6cb556
SP
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);
34ea3d38 541 drm_connector_register(connector);
ce6cb556
SP
542 drm_mode_connector_attach_encoder(connector, encoder);
543
544 return 0;
545}
546
547
548static struct exynos_drm_display_ops vidi_display_ops = {
549 .create_connector = vidi_create_connector,
550};
551
1d50aa9c 552static int vidi_bind(struct device *dev, struct device *master, void *data)
f37cd5e8 553{
f01833cd 554 struct vidi_context *ctx = dev_get_drvdata(dev);
1d50aa9c 555 struct drm_device *drm_dev = data;
f37cd5e8
ID
556 struct drm_crtc *crtc = ctx->crtc;
557 int ret;
558
f01833cd 559 vidi_mgr_initialize(&ctx->manager, drm_dev);
f37cd5e8 560
eb88e422 561 ret = exynos_drm_crtc_create(&ctx->manager, drm_dev, ctx->pipe,
5d1741ad 562 EXYNOS_DISPLAY_TYPE_VIDI);
f37cd5e8
ID
563 if (ret) {
564 DRM_ERROR("failed to create crtc.\n");
565 return ret;
566 }
567
7340426a 568 ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
f37cd5e8
ID
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
1d50aa9c
ID
578
579static void vidi_unbind(struct device *dev, struct device *master, void *data)
580{
581}
582
583static const struct component_ops vidi_component_ops = {
584 .bind = vidi_bind,
585 .unbind = vidi_unbind,
586};
587
56550d94 588static int vidi_probe(struct platform_device *pdev)
b73d1230 589{
b73d1230 590 struct vidi_context *ctx;
b73d1230
ID
591 int ret;
592
f37cd5e8 593 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
b73d1230
ID
594 if (!ctx)
595 return -ENOMEM;
596
f01833cd 597 ctx->manager.ops = &vidi_manager_ops;
7340426a
AH
598 ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
599 ctx->display.ops = &vidi_display_ops;
b73d1230 600 ctx->default_win = 0;
1d50aa9c
ID
601 ctx->pdev = pdev;
602
603 ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
5d1741ad 604 EXYNOS_DISPLAY_TYPE_VIDI);
1d50aa9c
ID
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;
b73d1230
ID
612
613 INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
614
b73d1230
ID
615 mutex_init(&ctx->lock);
616
f01833cd 617 platform_set_drvdata(pdev, ctx);
b73d1230 618
f37cd5e8
ID
619 ret = device_create_file(&pdev->dev, &dev_attr_connection);
620 if (ret < 0) {
1d50aa9c
ID
621 DRM_ERROR("failed to create connection sysfs.\n");
622 goto err_del_conn_component;
f37cd5e8 623 }
b73d1230 624
1d50aa9c
ID
625 ret = component_add(&pdev->dev, &vidi_component_ops);
626 if (ret)
627 goto err_remove_file;
628
629 return ret;
630
631err_remove_file:
632 device_remove_file(&pdev->dev, &dev_attr_connection);
633err_del_conn_component:
634 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
635err_del_crtc_component:
636 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
637
638 return ret;
b73d1230
ID
639}
640
56550d94 641static int vidi_remove(struct platform_device *pdev)
b73d1230 642{
f01833cd 643 struct vidi_context *ctx = platform_get_drvdata(pdev);
b73d1230 644
d3b62dbf
ID
645 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
646 kfree(ctx->raw_edid);
647 ctx->raw_edid = NULL;
f37cd5e8
ID
648
649 return -EINVAL;
d3b62dbf
ID
650 }
651
1d50aa9c
ID
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
b73d1230
ID
656 return 0;
657}
658
b73d1230
ID
659struct platform_driver vidi_driver = {
660 .probe = vidi_probe,
56550d94 661 .remove = vidi_remove,
b73d1230
ID
662 .driver = {
663 .name = "exynos-drm-vidi",
664 .owner = THIS_MODULE,
b73d1230
ID
665 },
666};
f37cd5e8
ID
667
668int 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
f01833cd
AH
686static 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
f37cd5e8
ID
693void exynos_drm_remove_vidi(void)
694{
f01833cd
AH
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;
f37cd5e8
ID
699
700 platform_driver_unregister(&vidi_driver);
f37cd5e8 701}
This page took 0.287132 seconds and 5 git commands to generate.