blob: ff194be5ebf0ec27d50bda63d8b439d9a2a7f4df [file] [log] [blame]
Inki Daeb73d1232012-03-21 10:55:26 +09001/* 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 */
David Howells760285e2012-10-02 18:01:07 +010013#include <drm/drmP.h>
Inki Daeb73d1232012-03-21 10:55:26 +090014
15#include <linux/kernel.h>
Inki Daeb73d1232012-03-21 10:55:26 +090016#include <linux/platform_device.h>
Inki Dae1d50aa92014-11-24 14:55:41 +090017#include <linux/component.h>
Inki Daeb73d1232012-03-21 10:55:26 +090018
19#include <drm/exynos_drm.h>
20
David Howells760285e2012-10-02 18:01:07 +010021#include <drm/drm_edid.h>
22#include <drm/drm_crtc_helper.h>
Inki Daeb73d1232012-03-21 10:55:26 +090023
24#include "exynos_drm_drv.h"
25#include "exynos_drm_crtc.h"
26#include "exynos_drm_encoder.h"
Mark Browne30655d2013-08-13 00:46:40 +010027#include "exynos_drm_vidi.h"
Inki Daeb73d1232012-03-21 10:55:26 +090028
29/* vidi has totally three virtual windows. */
30#define WINDOWS_NR 3
31
Sean Paulce6cb552014-01-30 16:38:07 -050032#define ctx_from_connector(c) container_of(c, struct vidi_context, \
33 connector)
Inki Daeb73d1232012-03-21 10:55:26 +090034
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;
Inki Daeb73d1232012-03-21 10:55:26 +090044 unsigned int buf_offsize;
45 unsigned int line_size; /* bytes */
46 bool enabled;
47};
48
49struct vidi_context {
Andrzej Hajdaf01833c2014-11-17 09:54:16 +010050 struct exynos_drm_manager manager;
Andrzej Hajda73404262014-11-17 09:54:22 +010051 struct exynos_drm_display display;
Inki Dae1d50aa92014-11-24 14:55:41 +090052 struct platform_device *pdev;
Sean Paul080be03d2014-02-19 21:02:55 +090053 struct drm_device *drm_dev;
Inki Daeb73d1232012-03-21 10:55:26 +090054 struct drm_crtc *crtc;
Sean Paulce6cb552014-01-30 16:38:07 -050055 struct drm_encoder *encoder;
56 struct drm_connector connector;
Inki Daeb73d1232012-03-21 10:55:26 +090057 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;
Inki Dae291257c2012-09-19 11:02:43 +090065 bool direct_vblank;
Inki Daeb73d1232012-03-21 10:55:26 +090066 struct work_struct work;
67 struct mutex lock;
Sean Paul080be03d2014-02-19 21:02:55 +090068 int pipe;
Inki Daeb73d1232012-03-21 10:55:26 +090069};
70
Andrzej Hajdae1819aa2014-11-17 09:54:17 +010071static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
72{
73 return container_of(m, struct vidi_context, manager);
74}
75
Andrzej Hajda2f26bd72014-11-17 09:54:23 +010076static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
77{
78 return container_of(d, struct vidi_context, display);
79}
80
Inki Daeb73d1232012-03-21 10:55:26 +090081static 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
Sean Paulbb7704d2014-01-30 16:19:06 -0500106static void vidi_apply(struct exynos_drm_manager *mgr)
Inki Daeb73d1232012-03-21 10:55:26 +0900107{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100108 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900109 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
Inki Daeb73d1232012-03-21 10:55:26 +0900110 struct vidi_win_data *win_data;
111 int i;
112
Inki Daeb73d1232012-03-21 10:55:26 +0900113 for (i = 0; i < WINDOWS_NR; i++) {
114 win_data = &ctx->win_data[i];
Sean Paul1c6244c2014-01-30 16:19:02 -0500115 if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
Sean Paulbb7704d2014-01-30 16:19:06 -0500116 mgr_ops->win_commit(mgr, i);
Inki Daeb73d1232012-03-21 10:55:26 +0900117 }
118
119 if (mgr_ops && mgr_ops->commit)
Sean Paulbb7704d2014-01-30 16:19:06 -0500120 mgr_ops->commit(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900121}
122
Sean Paulbb7704d2014-01-30 16:19:06 -0500123static void vidi_commit(struct exynos_drm_manager *mgr)
Inki Daeb73d1232012-03-21 10:55:26 +0900124{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100125 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900126
Inki Daeb73d1232012-03-21 10:55:26 +0900127 if (ctx->suspended)
128 return;
129}
130
Sean Paulbb7704d2014-01-30 16:19:06 -0500131static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
Inki Daeb73d1232012-03-21 10:55:26 +0900132{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100133 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900134
Inki Daeb73d1232012-03-21 10:55:26 +0900135 if (ctx->suspended)
136 return -EPERM;
137
138 if (!test_and_set_bit(0, &ctx->irq_flags))
139 ctx->vblank_on = true;
140
Inki Dae291257c2012-09-19 11:02:43 +0900141 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
Sean Paul1c6244c2014-01-30 16:19:02 -0500146 * that function will be called by manager_ops->win_commit callback
Inki Dae291257c2012-09-19 11:02:43 +0900147 */
148 schedule_work(&ctx->work);
149
Inki Daeb73d1232012-03-21 10:55:26 +0900150 return 0;
151}
152
Sean Paulbb7704d2014-01-30 16:19:06 -0500153static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
Inki Daeb73d1232012-03-21 10:55:26 +0900154{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100155 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900156
Inki Daeb73d1232012-03-21 10:55:26 +0900157 if (ctx->suspended)
158 return;
159
160 if (test_and_clear_bit(0, &ctx->irq_flags))
161 ctx->vblank_on = false;
162}
163
Sean Paulbb7704d2014-01-30 16:19:06 -0500164static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200165 struct exynos_drm_plane *plane)
Inki Daeb73d1232012-03-21 10:55:26 +0900166{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100167 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900168 struct vidi_win_data *win_data;
169 int win;
170 unsigned long offset;
171
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200172 if (!plane) {
173 DRM_ERROR("plane is NULL\n");
Inki Daeb73d1232012-03-21 10:55:26 +0900174 return;
175 }
176
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200177 win = plane->zpos;
Inki Daeb73d1232012-03-21 10:55:26 +0900178 if (win == DEFAULT_ZPOS)
179 win = ctx->default_win;
180
Inki Daea7f98d62013-05-28 16:01:21 +0900181 if (win < 0 || win >= WINDOWS_NR)
Inki Daeb73d1232012-03-21 10:55:26 +0900182 return;
183
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200184 offset = plane->fb_x * (plane->bpp >> 3);
185 offset += plane->fb_y * plane->pitch;
Inki Daeb73d1232012-03-21 10:55:26 +0900186
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200187 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
Inki Daeb73d1232012-03-21 10:55:26 +0900188
189 win_data = &ctx->win_data[win];
190
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200191 win_data->offset_x = plane->crtc_x;
192 win_data->offset_y = plane->crtc_y;
193 win_data->ovl_width = plane->crtc_width;
194 win_data->ovl_height = plane->crtc_height;
195 win_data->fb_width = plane->fb_width;
196 win_data->fb_height = plane->fb_height;
197 win_data->dma_addr = plane->dma_addr[0] + offset;
198 win_data->bpp = plane->bpp;
199 win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
200 (plane->bpp >> 3);
201 win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
Inki Daeb73d1232012-03-21 10:55:26 +0900202
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);
YoungJun Choddd8e952012-12-10 15:44:58 +0900212 DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
Inki Daeb73d1232012-03-21 10:55:26 +0900213 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
Gustavo Padovan8837dee2014-11-03 18:13:27 -0200214 plane->fb_width, plane->crtc_width);
Inki Daeb73d1232012-03-21 10:55:26 +0900215}
216
Sean Paulbb7704d2014-01-30 16:19:06 -0500217static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
Inki Daeb73d1232012-03-21 10:55:26 +0900218{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100219 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900220 struct vidi_win_data *win_data;
221 int win = zpos;
222
Inki Daeb73d1232012-03-21 10:55:26 +0900223 if (ctx->suspended)
224 return;
225
226 if (win == DEFAULT_ZPOS)
227 win = ctx->default_win;
228
Inki Daea7f98d62013-05-28 16:01:21 +0900229 if (win < 0 || win >= WINDOWS_NR)
Inki Daeb73d1232012-03-21 10:55:26 +0900230 return;
231
232 win_data = &ctx->win_data[win];
233
234 win_data->enabled = true;
235
Jingoo Hanb8eade22014-04-22 14:45:32 +0900236 DRM_DEBUG_KMS("dma_addr = %pad\n", &win_data->dma_addr);
Inki Daeb73d1232012-03-21 10:55:26 +0900237
238 if (ctx->vblank_on)
239 schedule_work(&ctx->work);
240}
241
Sean Paulbb7704d2014-01-30 16:19:06 -0500242static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
Inki Daeb73d1232012-03-21 10:55:26 +0900243{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100244 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daeb73d1232012-03-21 10:55:26 +0900245 struct vidi_win_data *win_data;
246 int win = zpos;
247
Inki Daeb73d1232012-03-21 10:55:26 +0900248 if (win == DEFAULT_ZPOS)
249 win = ctx->default_win;
250
Inki Daea7f98d62013-05-28 16:01:21 +0900251 if (win < 0 || win >= WINDOWS_NR)
Inki Daeb73d1232012-03-21 10:55:26 +0900252 return;
253
254 win_data = &ctx->win_data[win];
255 win_data->enabled = false;
256
257 /* TODO. */
258}
259
Sean Paulaf65c802014-01-30 16:19:27 -0500260static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
261{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100262 struct vidi_context *ctx = manager_to_vidi(mgr);
Sean Paulaf65c802014-01-30 16:19:27 -0500263
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
284static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
285{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100286 struct vidi_context *ctx = manager_to_vidi(mgr);
Sean Paulaf65c802014-01-30 16:19:27 -0500287
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
Sean Paul080be03d2014-02-19 21:02:55 +0900309static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
Inki Daef37cd5e2014-05-09 14:25:20 +0900310 struct drm_device *drm_dev)
Sean Paul080be03d2014-02-19 21:02:55 +0900311{
Andrzej Hajdae1819aa2014-11-17 09:54:17 +0100312 struct vidi_context *ctx = manager_to_vidi(mgr);
Inki Daef37cd5e2014-05-09 14:25:20 +0900313 struct exynos_drm_private *priv = drm_dev->dev_private;
Sean Paul080be03d2014-02-19 21:02:55 +0900314
Inki Daef37cd5e2014-05-09 14:25:20 +0900315 mgr->drm_dev = ctx->drm_dev = drm_dev;
316 mgr->pipe = ctx->pipe = priv->pipe++;
Sean Paul080be03d2014-02-19 21:02:55 +0900317
Sean Paul080be03d2014-02-19 21:02:55 +0900318 return 0;
319}
320
Sean Paul1c6244c2014-01-30 16:19:02 -0500321static struct exynos_drm_manager_ops vidi_manager_ops = {
322 .dpms = vidi_dpms,
Sean Paul1c6244c2014-01-30 16:19:02 -0500323 .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,
Inki Daeb73d1232012-03-21 10:55:26 +0900329};
330
Inki Daeb73d1232012-03-21 10:55:26 +0900331static void vidi_fake_vblank_handler(struct work_struct *work)
332{
333 struct vidi_context *ctx = container_of(work, struct vidi_context,
334 work);
Inki Daeb73d1232012-03-21 10:55:26 +0900335
Sean Paul080be03d2014-02-19 21:02:55 +0900336 if (ctx->pipe < 0)
Inki Daeb73d1232012-03-21 10:55:26 +0900337 return;
338
339 /* refresh rate is about 50Hz. */
340 usleep_range(16000, 20000);
341
Inki Dae291257c2012-09-19 11:02:43 +0900342 mutex_lock(&ctx->lock);
343
344 if (ctx->direct_vblank) {
Sean Paul080be03d2014-02-19 21:02:55 +0900345 drm_handle_vblank(ctx->drm_dev, ctx->pipe);
Inki Dae291257c2012-09-19 11:02:43 +0900346 ctx->direct_vblank = false;
347 mutex_unlock(&ctx->lock);
348 return;
349 }
350
351 mutex_unlock(&ctx->lock);
352
Sean Paul080be03d2014-02-19 21:02:55 +0900353 exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
Inki Daeb73d1232012-03-21 10:55:26 +0900354}
355
Inki Daeb73d1232012-03-21 10:55:26 +0900356static int vidi_show_connection(struct device *dev,
357 struct device_attribute *attr, char *buf)
358{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100359 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900360 int rc;
Inki Daeb73d1232012-03-21 10:55:26 +0900361
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
371static int vidi_store_connection(struct device *dev,
372 struct device_attribute *attr,
373 const char *buf, size_t len)
374{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100375 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900376 int ret;
377
Inki Daeb73d1232012-03-21 10:55:26 +0900378 ret = kstrtoint(buf, 0, &ctx->connected);
379 if (ret)
380 return ret;
381
382 if (ctx->connected > 1)
383 return -EINVAL;
384
Inki Daed07d39d2012-06-27 16:00:56 +0900385 /* use fake edid data for test. */
386 if (!ctx->raw_edid)
387 ctx->raw_edid = (struct edid *)fake_edid_info;
388
Inki Daed7b84782012-06-27 16:16:26 +0900389 /* 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
Inki Daeb73d1232012-03-21 10:55:26 +0900395 DRM_DEBUG_KMS("requested connection.\n");
396
Sean Paul080be03d2014-02-19 21:02:55 +0900397 drm_helper_hpd_irq_event(ctx->drm_dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900398
399 return len;
400}
401
402static DEVICE_ATTR(connection, 0644, vidi_show_connection,
403 vidi_store_connection);
404
405int 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;
Sean Paul080be03d2014-02-19 21:02:55 +0900410 struct exynos_drm_display *display;
Inki Daeb73d1232012-03-21 10:55:26 +0900411 struct drm_exynos_vidi_connection *vidi = data;
412
Inki Daeb73d1232012-03-21 10:55:26 +0900413 if (!vidi) {
414 DRM_DEBUG_KMS("user data for vidi is null.\n");
415 return -EINVAL;
416 }
417
Inki Daeb73d1232012-03-21 10:55:26 +0900418 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) {
Sean Paul080be03d2014-02-19 21:02:55 +0900425 display = exynos_drm_get_display(encoder);
Inki Daeb73d1232012-03-21 10:55:26 +0900426
Sean Paul080be03d2014-02-19 21:02:55 +0900427 if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
Andrzej Hajda2f26bd72014-11-17 09:54:23 +0100428 ctx = display_to_vidi(display);
Inki Daeb73d1232012-03-21 10:55:26 +0900429 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
Inki Daed3b62db2012-06-27 16:36:12 +0900443 if (vidi->connection) {
Seung-Woo Kime7808df2013-01-10 19:35:06 +0900444 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");
Inki Daed3b62db2012-06-27 16:36:12 +0900447 return -EINVAL;
448 }
Jani Nikula4ddc7732013-09-27 15:08:29 +0300449 ctx->raw_edid = drm_edid_duplicate(raw_edid);
Inki Daed3b62db2012-06-27 16:36:12 +0900450 if (!ctx->raw_edid) {
451 DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
452 return -ENOMEM;
453 }
Inki Daed3b62db2012-06-27 16:36:12 +0900454 } 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 }
Inki Daeb73d1232012-03-21 10:55:26 +0900465
466 ctx->connected = vidi->connection;
Sean Paul080be03d2014-02-19 21:02:55 +0900467 drm_helper_hpd_irq_event(ctx->drm_dev);
Inki Daeb73d1232012-03-21 10:55:26 +0900468
469 return 0;
470}
471
Sean Paulce6cb552014-01-30 16:38:07 -0500472static 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
485static void vidi_connector_destroy(struct drm_connector *connector)
486{
487}
488
489static 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
496static 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
Sean Paulce6cb552014-01-30 16:38:07 -0500523static 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
530static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
531 .get_modes = vidi_get_modes,
Sean Paulce6cb552014-01-30 16:38:07 -0500532 .best_encoder = vidi_best_encoder,
533};
534
535static int vidi_create_connector(struct exynos_drm_display *display,
536 struct drm_encoder *encoder)
537{
Andrzej Hajda2f26bd72014-11-17 09:54:23 +0100538 struct vidi_context *ctx = display_to_vidi(display);
Sean Paulce6cb552014-01-30 16:38:07 -0500539 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);
Thomas Wood34ea3d32014-05-29 16:57:41 +0100553 drm_connector_register(connector);
Sean Paulce6cb552014-01-30 16:38:07 -0500554 drm_mode_connector_attach_encoder(connector, encoder);
555
556 return 0;
557}
558
559
560static struct exynos_drm_display_ops vidi_display_ops = {
561 .create_connector = vidi_create_connector,
562};
563
Inki Dae1d50aa92014-11-24 14:55:41 +0900564static int vidi_bind(struct device *dev, struct device *master, void *data)
Inki Daef37cd5e2014-05-09 14:25:20 +0900565{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100566 struct vidi_context *ctx = dev_get_drvdata(dev);
Inki Dae1d50aa92014-11-24 14:55:41 +0900567 struct drm_device *drm_dev = data;
Inki Daef37cd5e2014-05-09 14:25:20 +0900568 struct drm_crtc *crtc = ctx->crtc;
569 int ret;
570
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100571 vidi_mgr_initialize(&ctx->manager, drm_dev);
Inki Daef37cd5e2014-05-09 14:25:20 +0900572
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100573 ret = exynos_drm_crtc_create(&ctx->manager);
Inki Daef37cd5e2014-05-09 14:25:20 +0900574 if (ret) {
575 DRM_ERROR("failed to create crtc.\n");
576 return ret;
577 }
578
Andrzej Hajda73404262014-11-17 09:54:22 +0100579 ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
Inki Daef37cd5e2014-05-09 14:25:20 +0900580 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
Inki Dae1d50aa92014-11-24 14:55:41 +0900589
590static void vidi_unbind(struct device *dev, struct device *master, void *data)
591{
592}
593
594static const struct component_ops vidi_component_ops = {
595 .bind = vidi_bind,
596 .unbind = vidi_unbind,
597};
598
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800599static int vidi_probe(struct platform_device *pdev)
Inki Daeb73d1232012-03-21 10:55:26 +0900600{
Inki Daeb73d1232012-03-21 10:55:26 +0900601 struct vidi_context *ctx;
Inki Daeb73d1232012-03-21 10:55:26 +0900602 int ret;
603
Inki Daef37cd5e2014-05-09 14:25:20 +0900604 ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
Inki Daeb73d1232012-03-21 10:55:26 +0900605 if (!ctx)
606 return -ENOMEM;
607
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100608 ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
609 ctx->manager.ops = &vidi_manager_ops;
Andrzej Hajda73404262014-11-17 09:54:22 +0100610 ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
611 ctx->display.ops = &vidi_display_ops;
Inki Daeb73d1232012-03-21 10:55:26 +0900612 ctx->default_win = 0;
Inki Dae1d50aa92014-11-24 14:55:41 +0900613 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;
Inki Daeb73d1232012-03-21 10:55:26 +0900624
625 INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
626
Inki Daeb73d1232012-03-21 10:55:26 +0900627 mutex_init(&ctx->lock);
628
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100629 platform_set_drvdata(pdev, ctx);
Inki Daeb73d1232012-03-21 10:55:26 +0900630
Inki Daef37cd5e2014-05-09 14:25:20 +0900631 ret = device_create_file(&pdev->dev, &dev_attr_connection);
632 if (ret < 0) {
Inki Dae1d50aa92014-11-24 14:55:41 +0900633 DRM_ERROR("failed to create connection sysfs.\n");
634 goto err_del_conn_component;
Inki Daef37cd5e2014-05-09 14:25:20 +0900635 }
Inki Daeb73d1232012-03-21 10:55:26 +0900636
Inki Dae1d50aa92014-11-24 14:55:41 +0900637 ret = component_add(&pdev->dev, &vidi_component_ops);
638 if (ret)
639 goto err_remove_file;
640
641 return ret;
642
643err_remove_file:
644 device_remove_file(&pdev->dev, &dev_attr_connection);
645err_del_conn_component:
646 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CONNECTOR);
647err_del_crtc_component:
648 exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
649
650 return ret;
Inki Daeb73d1232012-03-21 10:55:26 +0900651}
652
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800653static int vidi_remove(struct platform_device *pdev)
Inki Daeb73d1232012-03-21 10:55:26 +0900654{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100655 struct vidi_context *ctx = platform_get_drvdata(pdev);
Inki Daeb73d1232012-03-21 10:55:26 +0900656
Inki Daed3b62db2012-06-27 16:36:12 +0900657 if (ctx->raw_edid != (struct edid *)fake_edid_info) {
658 kfree(ctx->raw_edid);
659 ctx->raw_edid = NULL;
Inki Daef37cd5e2014-05-09 14:25:20 +0900660
661 return -EINVAL;
Inki Daed3b62db2012-06-27 16:36:12 +0900662 }
663
Inki Dae1d50aa92014-11-24 14:55:41 +0900664 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
Inki Daeb73d1232012-03-21 10:55:26 +0900668 return 0;
669}
670
Inki Daeb73d1232012-03-21 10:55:26 +0900671struct platform_driver vidi_driver = {
672 .probe = vidi_probe,
Greg Kroah-Hartman56550d92012-12-21 15:09:25 -0800673 .remove = vidi_remove,
Inki Daeb73d1232012-03-21 10:55:26 +0900674 .driver = {
675 .name = "exynos-drm-vidi",
676 .owner = THIS_MODULE,
Inki Daeb73d1232012-03-21 10:55:26 +0900677 },
678};
Inki Daef37cd5e2014-05-09 14:25:20 +0900679
680int 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
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100698static 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
Inki Daef37cd5e2014-05-09 14:25:20 +0900705void exynos_drm_remove_vidi(void)
706{
Andrzej Hajdaf01833c2014-11-17 09:54:16 +0100707 int ret = driver_for_each_device(&vidi_driver.driver, NULL, NULL,
708 exynos_drm_remove_vidi_device);
709 /* silence compiler warning */
710 (void)ret;
Inki Daef37cd5e2014-05-09 14:25:20 +0900711
712 platform_driver_unregister(&vidi_driver);
Inki Daef37cd5e2014-05-09 14:25:20 +0900713}