]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/gpu/drm/exynos/exynos_drm_vidi.c
drm/exynos: Implement drm_connector directly in dp driver
[mirror_ubuntu-artful-kernel.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
ID
16#include <linux/platform_device.h>
17
18#include <drm/exynos_drm.h>
19
760285e7
DH
20#include <drm/drm_edid.h>
21#include <drm/drm_crtc_helper.h>
b73d1230
ID
22
23#include "exynos_drm_drv.h"
24#include "exynos_drm_crtc.h"
25#include "exynos_drm_encoder.h"
e30655d0 26#include "exynos_drm_vidi.h"
b73d1230
ID
27
28/* vidi has totally three virtual windows. */
29#define WINDOWS_NR 3
30
bb7704d6 31#define get_vidi_mgr(dev) platform_get_drvdata(to_platform_device(dev))
b73d1230
ID
32
33struct vidi_win_data {
34 unsigned int offset_x;
35 unsigned int offset_y;
36 unsigned int ovl_width;
37 unsigned int ovl_height;
38 unsigned int fb_width;
39 unsigned int fb_height;
40 unsigned int bpp;
41 dma_addr_t dma_addr;
b73d1230
ID
42 unsigned int buf_offsize;
43 unsigned int line_size; /* bytes */
44 bool enabled;
45};
46
47struct vidi_context {
080be03d 48 struct drm_device *drm_dev;
b73d1230
ID
49 struct drm_crtc *crtc;
50 struct vidi_win_data win_data[WINDOWS_NR];
51 struct edid *raw_edid;
52 unsigned int clkdiv;
53 unsigned int default_win;
54 unsigned long irq_flags;
55 unsigned int connected;
56 bool vblank_on;
57 bool suspended;
291257cf 58 bool direct_vblank;
b73d1230
ID
59 struct work_struct work;
60 struct mutex lock;
080be03d 61 int pipe;
b73d1230
ID
62};
63
64static const char fake_edid_info[] = {
65 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
66 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
67 0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
68 0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
69 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
70 0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
71 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
72 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
73 0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
74 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
75 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
76 0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
77 0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
78 0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
79 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
80 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
81 0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
82 0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 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, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
86 0x00, 0x00, 0x00, 0x06
87};
88
080be03d 89static bool vidi_display_is_connected(struct exynos_drm_display *display)
b73d1230 90{
080be03d 91 struct vidi_context *ctx = display->ctx;
b73d1230 92
b73d1230
ID
93 /*
94 * connection request would come from user side
95 * to do hotplug through specific ioctl.
96 */
97 return ctx->connected ? true : false;
98}
99
080be03d 100static struct edid *vidi_get_edid(struct exynos_drm_display *display,
9c08e4ba 101 struct drm_connector *connector)
b73d1230 102{
080be03d 103 struct vidi_context *ctx = display->ctx;
9c08e4ba 104 struct edid *edid;
b73d1230 105
b73d1230
ID
106 /*
107 * the edid data comes from user side and it would be set
108 * to ctx->raw_edid through specific ioctl.
109 */
110 if (!ctx->raw_edid) {
111 DRM_DEBUG_KMS("raw_edid is null.\n");
9c08e4ba 112 return ERR_PTR(-EFAULT);
b73d1230
ID
113 }
114
4ddc773b 115 edid = drm_edid_duplicate(ctx->raw_edid);
9c08e4ba
RS
116 if (!edid) {
117 DRM_DEBUG_KMS("failed to allocate edid\n");
118 return ERR_PTR(-ENOMEM);
119 }
b73d1230 120
9c08e4ba 121 return edid;
b73d1230
ID
122}
123
080be03d
SP
124static int vidi_check_mode(struct exynos_drm_display *display,
125 struct drm_display_mode *mode)
b73d1230 126{
b73d1230
ID
127 /* TODO. */
128
129 return 0;
130}
131
b73d1230 132static struct exynos_drm_display_ops vidi_display_ops = {
b73d1230
ID
133 .is_connected = vidi_display_is_connected,
134 .get_edid = vidi_get_edid,
16844fb1 135 .check_mode = vidi_check_mode,
b73d1230
ID
136};
137
080be03d
SP
138static struct exynos_drm_display vidi_display = {
139 .type = EXYNOS_DISPLAY_TYPE_VIDI,
140 .ops = &vidi_display_ops,
141};
142
bb7704d6 143static void vidi_apply(struct exynos_drm_manager *mgr)
b73d1230 144{
bb7704d6 145 struct vidi_context *ctx = mgr->ctx;
b73d1230 146 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
b73d1230
ID
147 struct vidi_win_data *win_data;
148 int i;
149
b73d1230
ID
150 for (i = 0; i < WINDOWS_NR; i++) {
151 win_data = &ctx->win_data[i];
1c6244c3 152 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
bb7704d6 153 mgr_ops->win_commit(mgr, i);
b73d1230
ID
154 }
155
156 if (mgr_ops && mgr_ops->commit)
bb7704d6 157 mgr_ops->commit(mgr);
b73d1230
ID
158}
159
bb7704d6 160static void vidi_commit(struct exynos_drm_manager *mgr)
b73d1230 161{
bb7704d6 162 struct vidi_context *ctx = mgr->ctx;
b73d1230 163
b73d1230
ID
164 if (ctx->suspended)
165 return;
166}
167
bb7704d6 168static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
b73d1230 169{
bb7704d6 170 struct vidi_context *ctx = mgr->ctx;
b73d1230 171
b73d1230
ID
172 if (ctx->suspended)
173 return -EPERM;
174
175 if (!test_and_set_bit(0, &ctx->irq_flags))
176 ctx->vblank_on = true;
177
291257cf
ID
178 ctx->direct_vblank = true;
179
180 /*
181 * in case of page flip request, vidi_finish_pageflip function
182 * will not be called because direct_vblank is true and then
1c6244c3 183 * that function will be called by manager_ops->win_commit callback
291257cf
ID
184 */
185 schedule_work(&ctx->work);
186
b73d1230
ID
187 return 0;
188}
189
bb7704d6 190static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
b73d1230 191{
bb7704d6 192 struct vidi_context *ctx = mgr->ctx;
b73d1230 193
b73d1230
ID
194 if (ctx->suspended)
195 return;
196
197 if (test_and_clear_bit(0, &ctx->irq_flags))
198 ctx->vblank_on = false;
199}
200
bb7704d6
SP
201static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
202 struct exynos_drm_overlay *overlay)
b73d1230 203{
bb7704d6 204 struct vidi_context *ctx = mgr->ctx;
b73d1230
ID
205 struct vidi_win_data *win_data;
206 int win;
207 unsigned long offset;
208
b73d1230 209 if (!overlay) {
bb7704d6 210 DRM_ERROR("overlay is NULL\n");
b73d1230
ID
211 return;
212 }
213
214 win = overlay->zpos;
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 offset = overlay->fb_x * (overlay->bpp >> 3);
222 offset += overlay->fb_y * overlay->pitch;
223
224 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
225
226 win_data = &ctx->win_data[win];
227
228 win_data->offset_x = overlay->crtc_x;
229 win_data->offset_y = overlay->crtc_y;
230 win_data->ovl_width = overlay->crtc_width;
231 win_data->ovl_height = overlay->crtc_height;
232 win_data->fb_width = overlay->fb_width;
233 win_data->fb_height = overlay->fb_height;
234 win_data->dma_addr = overlay->dma_addr[0] + offset;
b73d1230
ID
235 win_data->bpp = overlay->bpp;
236 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
237 (overlay->bpp >> 3);
238 win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
239
240 /*
241 * some parts of win_data should be transferred to user side
242 * through specific ioctl.
243 */
244
245 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
246 win_data->offset_x, win_data->offset_y);
247 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
248 win_data->ovl_width, win_data->ovl_height);
ddd8e959 249 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
b73d1230
ID
250 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
251 overlay->fb_width, overlay->crtc_width);
252}
253
bb7704d6 254static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
b73d1230 255{
bb7704d6 256 struct vidi_context *ctx = mgr->ctx;
b73d1230
ID
257 struct vidi_win_data *win_data;
258 int win = zpos;
259
b73d1230
ID
260 if (ctx->suspended)
261 return;
262
263 if (win == DEFAULT_ZPOS)
264 win = ctx->default_win;
265
a7f98d6a 266 if (win < 0 || win >= WINDOWS_NR)
b73d1230
ID
267 return;
268
269 win_data = &ctx->win_data[win];
270
271 win_data->enabled = true;
272
273 DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
274
275 if (ctx->vblank_on)
276 schedule_work(&ctx->work);
277}
278
bb7704d6 279static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
b73d1230 280{
bb7704d6 281 struct vidi_context *ctx = mgr->ctx;
b73d1230
ID
282 struct vidi_win_data *win_data;
283 int win = zpos;
284
b73d1230
ID
285 if (win == DEFAULT_ZPOS)
286 win = ctx->default_win;
287
a7f98d6a 288 if (win < 0 || win >= WINDOWS_NR)
b73d1230
ID
289 return;
290
291 win_data = &ctx->win_data[win];
292 win_data->enabled = false;
293
294 /* TODO. */
295}
296
af65c804
SP
297static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
298{
299 struct vidi_context *ctx = mgr->ctx;
300
301 DRM_DEBUG_KMS("%s\n", __FILE__);
302
303 if (enable != false && enable != true)
304 return -EINVAL;
305
306 if (enable) {
307 ctx->suspended = false;
308
309 /* if vblank was enabled status, enable it again. */
310 if (test_and_clear_bit(0, &ctx->irq_flags))
311 vidi_enable_vblank(mgr);
312
313 vidi_apply(mgr);
314 } else {
315 ctx->suspended = true;
316 }
317
318 return 0;
319}
320
321static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
322{
323 struct vidi_context *ctx = mgr->ctx;
324
325 DRM_DEBUG_KMS("%d\n", mode);
326
327 mutex_lock(&ctx->lock);
328
329 switch (mode) {
330 case DRM_MODE_DPMS_ON:
331 vidi_power_on(mgr, true);
332 break;
333 case DRM_MODE_DPMS_STANDBY:
334 case DRM_MODE_DPMS_SUSPEND:
335 case DRM_MODE_DPMS_OFF:
336 vidi_power_on(mgr, false);
337 break;
338 default:
339 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
340 break;
341 }
342
343 mutex_unlock(&ctx->lock);
344}
345
080be03d
SP
346static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
347 struct drm_device *drm_dev, int pipe)
348{
349 struct vidi_context *ctx = mgr->ctx;
350
351 DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
352
353 ctx->drm_dev = drm_dev;
354 ctx->pipe = pipe;
355
356 /*
357 * enable drm irq mode.
358 * - with irq_enabled = 1, we can use the vblank feature.
359 *
360 * P.S. note that we wouldn't use drm irq handler but
361 * just specific driver own one instead because
362 * drm framework supports only one irq handler.
363 */
364 drm_dev->irq_enabled = 1;
365
366 /*
367 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
368 * by drm timer once a current process gives up ownership of
369 * vblank event.(after drm_vblank_put function is called)
370 */
371 drm_dev->vblank_disable_allowed = 1;
372
373 return 0;
374}
375
1c6244c3 376static struct exynos_drm_manager_ops vidi_manager_ops = {
080be03d 377 .initialize = vidi_mgr_initialize,
1c6244c3 378 .dpms = vidi_dpms,
1c6244c3
SP
379 .commit = vidi_commit,
380 .enable_vblank = vidi_enable_vblank,
381 .disable_vblank = vidi_disable_vblank,
382 .win_mode_set = vidi_win_mode_set,
383 .win_commit = vidi_win_commit,
384 .win_disable = vidi_win_disable,
b73d1230
ID
385};
386
677e84c1 387static struct exynos_drm_manager vidi_manager = {
080be03d
SP
388 .type = EXYNOS_DISPLAY_TYPE_VIDI,
389 .ops = &vidi_manager_ops,
677e84c1
JS
390};
391
b73d1230
ID
392static void vidi_fake_vblank_handler(struct work_struct *work)
393{
394 struct vidi_context *ctx = container_of(work, struct vidi_context,
395 work);
b73d1230 396
080be03d 397 if (ctx->pipe < 0)
b73d1230
ID
398 return;
399
400 /* refresh rate is about 50Hz. */
401 usleep_range(16000, 20000);
402
291257cf
ID
403 mutex_lock(&ctx->lock);
404
405 if (ctx->direct_vblank) {
080be03d 406 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
291257cf
ID
407 ctx->direct_vblank = false;
408 mutex_unlock(&ctx->lock);
409 return;
410 }
411
412 mutex_unlock(&ctx->lock);
413
080be03d 414 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
b73d1230
ID
415}
416
b73d1230
ID
417static int vidi_show_connection(struct device *dev,
418 struct device_attribute *attr, char *buf)
419{
420 int rc;
bb7704d6
SP
421 struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
422 struct vidi_context *ctx = mgr->ctx;
b73d1230
ID
423
424 mutex_lock(&ctx->lock);
425
426 rc = sprintf(buf, "%d\n", ctx->connected);
427
428 mutex_unlock(&ctx->lock);
429
430 return rc;
431}
432
433static int vidi_store_connection(struct device *dev,
434 struct device_attribute *attr,
435 const char *buf, size_t len)
436{
bb7704d6
SP
437 struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
438 struct vidi_context *ctx = mgr->ctx;
b73d1230
ID
439 int ret;
440
b73d1230
ID
441 ret = kstrtoint(buf, 0, &ctx->connected);
442 if (ret)
443 return ret;
444
445 if (ctx->connected > 1)
446 return -EINVAL;
447
d07d39df
ID
448 /* use fake edid data for test. */
449 if (!ctx->raw_edid)
450 ctx->raw_edid = (struct edid *)fake_edid_info;
451
d7b8478a
ID
452 /* if raw_edid isn't same as fake data then it can't be tested. */
453 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
454 DRM_DEBUG_KMS("edid data is not fake data.\n");
455 return -EINVAL;
456 }
457
b73d1230
ID
458 DRM_DEBUG_KMS("requested connection.\n");
459
080be03d 460 drm_helper_hpd_irq_event(ctx->drm_dev);
b73d1230
ID
461
462 return len;
463}
464
465static DEVICE_ATTR(connection, 0644, vidi_show_connection,
466 vidi_store_connection);
467
468int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
469 struct drm_file *file_priv)
470{
471 struct vidi_context *ctx = NULL;
472 struct drm_encoder *encoder;
080be03d 473 struct exynos_drm_display *display;
b73d1230
ID
474 struct drm_exynos_vidi_connection *vidi = data;
475
b73d1230
ID
476 if (!vidi) {
477 DRM_DEBUG_KMS("user data for vidi is null.\n");
478 return -EINVAL;
479 }
480
b73d1230
ID
481 if (vidi->connection > 1) {
482 DRM_DEBUG_KMS("connection should be 0 or 1.\n");
483 return -EINVAL;
484 }
485
486 list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
487 head) {
080be03d 488 display = exynos_drm_get_display(encoder);
b73d1230 489
080be03d
SP
490 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
491 ctx = display->ctx;
b73d1230
ID
492 break;
493 }
494 }
495
496 if (!ctx) {
497 DRM_DEBUG_KMS("not found virtual device type encoder.\n");
498 return -EINVAL;
499 }
500
501 if (ctx->connected == vidi->connection) {
502 DRM_DEBUG_KMS("same connection request.\n");
503 return -EINVAL;
504 }
505
d3b62dbf 506 if (vidi->connection) {
e7808df1
SWK
507 struct edid *raw_edid = (struct edid *)(uint32_t)vidi->edid;
508 if (!drm_edid_is_valid(raw_edid)) {
509 DRM_DEBUG_KMS("edid data is invalid.\n");
d3b62dbf
ID
510 return -EINVAL;
511 }
4ddc773b 512 ctx->raw_edid = drm_edid_duplicate(raw_edid);
d3b62dbf
ID
513 if (!ctx->raw_edid) {
514 DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
515 return -ENOMEM;
516 }
d3b62dbf
ID
517 } else {
518 /*
519 * with connection = 0, free raw_edid
520 * only if raw edid data isn't same as fake data.
521 */
522 if (ctx->raw_edid && ctx->raw_edid !=
523 (struct edid *)fake_edid_info) {
524 kfree(ctx->raw_edid);
525 ctx->raw_edid = NULL;
526 }
527 }
b73d1230
ID
528
529 ctx->connected = vidi->connection;
080be03d 530 drm_helper_hpd_irq_event(ctx->drm_dev);
b73d1230
ID
531
532 return 0;
533}
534
56550d94 535static int vidi_probe(struct platform_device *pdev)
b73d1230
ID
536{
537 struct device *dev = &pdev->dev;
538 struct vidi_context *ctx;
b73d1230
ID
539 int ret;
540
d873ab99 541 ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
b73d1230
ID
542 if (!ctx)
543 return -ENOMEM;
544
545 ctx->default_win = 0;
546
547 INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
548
bb7704d6 549 vidi_manager.ctx = ctx;
080be03d 550 vidi_display.ctx = ctx;
b73d1230
ID
551
552 mutex_init(&ctx->lock);
553
bb7704d6 554 platform_set_drvdata(pdev, &vidi_manager);
b73d1230 555
d873ab99 556 ret = device_create_file(dev, &dev_attr_connection);
b73d1230
ID
557 if (ret < 0)
558 DRM_INFO("failed to create connection sysfs.\n");
559
080be03d
SP
560 exynos_drm_manager_register(&vidi_manager);
561 exynos_drm_display_register(&vidi_display);
b73d1230
ID
562
563 return 0;
564}
565
56550d94 566static int vidi_remove(struct platform_device *pdev)
b73d1230
ID
567{
568 struct vidi_context *ctx = platform_get_drvdata(pdev);
569
080be03d
SP
570 exynos_drm_display_unregister(&vidi_display);
571 exynos_drm_manager_unregister(&vidi_manager);
b73d1230 572
d3b62dbf
ID
573 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
574 kfree(ctx->raw_edid);
575 ctx->raw_edid = NULL;
576 }
577
b73d1230
ID
578 return 0;
579}
580
b73d1230
ID
581struct platform_driver vidi_driver = {
582 .probe = vidi_probe,
56550d94 583 .remove = vidi_remove,
b73d1230
ID
584 .driver = {
585 .name = "exynos-drm-vidi",
586 .owner = THIS_MODULE,
b73d1230
ID
587 },
588};