aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2012-03-20 21:55:26 -0400
committerDave Airlie <airlied@redhat.com>2012-03-21 06:15:49 -0400
commitb73d12303ecfc91123363d8900e127da44bf42a6 (patch)
treeacf71b4c4a932c44cacaf7b69106b872db50dccd
parentda0df92b57311aa1b26a2a90599ed16e1e968b90 (diff)
drm/exynos: added virtual display driver.
this driver would be used for wireless display. virtual display driver has independent crtc, encoder and connector and to use this driver, user application should send edid data to this driver from wireless display. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
-rw-r--r--drivers/gpu/drm/exynos/Kconfig6
-rw-r--r--drivers/gpu/drm/exynos/Makefile1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_connector.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c18
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h7
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c676
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.h36
-rw-r--r--include/drm/exynos_drm.h18
9 files changed, 765 insertions, 2 deletions
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 9a9850afe2f0..3343ac437fe5 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -21,3 +21,9 @@ config DRM_EXYNOS_HDMI
21 depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV 21 depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
22 help 22 help
23 Choose this option if you want to use Exynos HDMI for DRM. 23 Choose this option if you want to use Exynos HDMI for DRM.
24
25config DRM_EXYNOS_VIDI
26 bool "Exynos DRM Virtual Display"
27 depends on DRM_EXYNOS
28 help
29 Choose this option if you want to use Exynos VIDI for DRM.
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 5331fa33e13a..9e0bff8badf9 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -12,5 +12,6 @@ exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
12exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \ 12exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI) += exynos_hdmi.o exynos_mixer.o \
13 exynos_ddc.o exynos_hdmiphy.o \ 13 exynos_ddc.o exynos_hdmiphy.o \
14 exynos_drm_hdmi.o 14 exynos_drm_hdmi.o
15exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI) += exynos_drm_vidi.o
15 16
16obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o 17obj-$(CONFIG_DRM_EXYNOS) += exynosdrm.o
diff --git a/drivers/gpu/drm/exynos/exynos_drm_connector.c b/drivers/gpu/drm/exynos/exynos_drm_connector.c
index a5d65912f4d5..ee4ff74bc165 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_connector.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_connector.c
@@ -315,6 +315,10 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
315 connector->interlace_allowed = true; 315 connector->interlace_allowed = true;
316 connector->polled = DRM_CONNECTOR_POLL_HPD; 316 connector->polled = DRM_CONNECTOR_POLL_HPD;
317 break; 317 break;
318 case EXYNOS_DISPLAY_TYPE_VIDI:
319 type = DRM_MODE_CONNECTOR_VIRTUAL;
320 connector->polled = DRM_CONNECTOR_POLL_HPD;
321 break;
318 default: 322 default:
319 type = DRM_MODE_CONNECTOR_Unknown; 323 type = DRM_MODE_CONNECTOR_Unknown;
320 break; 324 break;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 1d78e039643b..3453bdd28a47 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -38,6 +38,7 @@
38#include "exynos_drm_fb.h" 38#include "exynos_drm_fb.h"
39#include "exynos_drm_gem.h" 39#include "exynos_drm_gem.h"
40#include "exynos_drm_plane.h" 40#include "exynos_drm_plane.h"
41#include "exynos_drm_vidi.h"
41 42
42#define DRIVER_NAME "exynos" 43#define DRIVER_NAME "exynos"
43#define DRIVER_DESC "Samsung SoC DRM" 44#define DRIVER_DESC "Samsung SoC DRM"
@@ -208,6 +209,8 @@ static struct drm_ioctl_desc exynos_ioctls[] = {
208 exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH), 209 exynos_drm_gem_mmap_ioctl, DRM_UNLOCKED | DRM_AUTH),
209 DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl, 210 DRM_IOCTL_DEF_DRV(EXYNOS_PLANE_SET_ZPOS, exynos_plane_set_zpos_ioctl,
210 DRM_UNLOCKED | DRM_AUTH), 211 DRM_UNLOCKED | DRM_AUTH),
212 DRM_IOCTL_DEF_DRV(EXYNOS_VIDI_CONNECTION,
213 vidi_connection_ioctl, DRM_UNLOCKED | DRM_AUTH),
211}; 214};
212 215
213static const struct file_operations exynos_drm_driver_fops = { 216static const struct file_operations exynos_drm_driver_fops = {
@@ -298,6 +301,12 @@ static int __init exynos_drm_init(void)
298 goto out_common_hdmi; 301 goto out_common_hdmi;
299#endif 302#endif
300 303
304#ifdef CONFIG_DRM_EXYNOS_VIDI
305 ret = platform_driver_register(&vidi_driver);
306 if (ret < 0)
307 goto out_vidi;
308#endif
309
301 ret = platform_driver_register(&exynos_drm_platform_driver); 310 ret = platform_driver_register(&exynos_drm_platform_driver);
302 if (ret < 0) 311 if (ret < 0)
303 goto out; 312 goto out;
@@ -305,6 +314,11 @@ static int __init exynos_drm_init(void)
305 return 0; 314 return 0;
306 315
307out: 316out:
317#ifdef CONFIG_DRM_EXYNOS_VIDI
318out_vidi:
319 platform_driver_unregister(&vidi_driver);
320#endif
321
308#ifdef CONFIG_DRM_EXYNOS_HDMI 322#ifdef CONFIG_DRM_EXYNOS_HDMI
309 platform_driver_unregister(&exynos_drm_common_hdmi_driver); 323 platform_driver_unregister(&exynos_drm_common_hdmi_driver);
310out_common_hdmi: 324out_common_hdmi:
@@ -333,6 +347,10 @@ static void __exit exynos_drm_exit(void)
333 platform_driver_unregister(&hdmi_driver); 347 platform_driver_unregister(&hdmi_driver);
334#endif 348#endif
335 349
350#ifdef CONFIG_DRM_EXYNOS_VIDI
351 platform_driver_unregister(&vidi_driver);
352#endif
353
336#ifdef CONFIG_DRM_EXYNOS_FIMD 354#ifdef CONFIG_DRM_EXYNOS_FIMD
337 platform_driver_unregister(&fimd_driver); 355 platform_driver_unregister(&fimd_driver);
338#endif 356#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index b26c2f4425d1..fbd0a232c93d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -32,9 +32,9 @@
32#include <linux/module.h> 32#include <linux/module.h>
33#include "drm.h" 33#include "drm.h"
34 34
35#define MAX_CRTC 2 35#define MAX_CRTC 3
36#define MAX_PLANE 5 36#define MAX_PLANE 5
37#define MAX_FB_BUFFER 3 37#define MAX_FB_BUFFER 4
38#define DEFAULT_ZPOS -1 38#define DEFAULT_ZPOS -1
39 39
40struct drm_device; 40struct drm_device;
@@ -50,6 +50,8 @@ enum exynos_drm_output_type {
50 EXYNOS_DISPLAY_TYPE_LCD, 50 EXYNOS_DISPLAY_TYPE_LCD,
51 /* HDMI Interface. */ 51 /* HDMI Interface. */
52 EXYNOS_DISPLAY_TYPE_HDMI, 52 EXYNOS_DISPLAY_TYPE_HDMI,
53 /* Virtual Display Interface. */
54 EXYNOS_DISPLAY_TYPE_VIDI,
53}; 55};
54 56
55/* 57/*
@@ -284,4 +286,5 @@ extern struct platform_driver fimd_driver;
284extern struct platform_driver hdmi_driver; 286extern struct platform_driver hdmi_driver;
285extern struct platform_driver mixer_driver; 287extern struct platform_driver mixer_driver;
286extern struct platform_driver exynos_drm_common_hdmi_driver; 288extern struct platform_driver exynos_drm_common_hdmi_driver;
289extern struct platform_driver vidi_driver;
287#endif 290#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 22786765d405..6e9ac7bd1dcf 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -218,6 +218,7 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
218 switch (display_ops->type) { 218 switch (display_ops->type) {
219 case EXYNOS_DISPLAY_TYPE_LCD: 219 case EXYNOS_DISPLAY_TYPE_LCD:
220 case EXYNOS_DISPLAY_TYPE_HDMI: 220 case EXYNOS_DISPLAY_TYPE_HDMI:
221 case EXYNOS_DISPLAY_TYPE_VIDI:
221 clone_mask |= (1 << (cnt++)); 222 clone_mask |= (1 << (cnt++));
222 break; 223 break;
223 default: 224 default:
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
new file mode 100644
index 000000000000..8e1339f9fe1f
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -0,0 +1,676 @@
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 "drmP.h"
14
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/platform_device.h>
18
19#include <drm/exynos_drm.h>
20
21#include "drm_edid.h"
22#include "drm_crtc_helper.h"
23
24#include "exynos_drm_drv.h"
25#include "exynos_drm_crtc.h"
26#include "exynos_drm_encoder.h"
27
28/* vidi has totally three virtual windows. */
29#define WINDOWS_NR 3
30
31#define get_vidi_context(dev) platform_get_drvdata(to_platform_device(dev))
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;
42 void __iomem *vaddr;
43 unsigned int buf_offsize;
44 unsigned int line_size; /* bytes */
45 bool enabled;
46};
47
48struct vidi_context {
49 struct exynos_drm_subdrv subdrv;
50 struct drm_crtc *crtc;
51 struct vidi_win_data win_data[WINDOWS_NR];
52 struct edid *raw_edid;
53 unsigned int clkdiv;
54 unsigned int default_win;
55 unsigned long irq_flags;
56 unsigned int connected;
57 bool vblank_on;
58 bool suspended;
59 struct work_struct work;
60 struct mutex lock;
61};
62
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
88static void vidi_fake_vblank_handler(struct work_struct *work);
89
90static bool vidi_display_is_connected(struct device *dev)
91{
92 struct vidi_context *ctx = get_vidi_context(dev);
93
94 DRM_DEBUG_KMS("%s\n", __FILE__);
95
96 /*
97 * connection request would come from user side
98 * to do hotplug through specific ioctl.
99 */
100 return ctx->connected ? true : false;
101}
102
103static int vidi_get_edid(struct device *dev, struct drm_connector *connector,
104 u8 *edid, int len)
105{
106 struct vidi_context *ctx = get_vidi_context(dev);
107 struct edid *raw_edid;
108
109 DRM_DEBUG_KMS("%s\n", __FILE__);
110
111 /*
112 * the edid data comes from user side and it would be set
113 * to ctx->raw_edid through specific ioctl.
114 */
115 if (!ctx->raw_edid) {
116 DRM_DEBUG_KMS("raw_edid is null.\n");
117 return -EFAULT;
118 }
119
120 raw_edid = kzalloc(len, GFP_KERNEL);
121 if (!raw_edid) {
122 DRM_DEBUG_KMS("failed to allocate raw_edid.\n");
123 return -ENOMEM;
124 }
125
126 memcpy(raw_edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
127 * EDID_LENGTH, len));
128
129 /* attach the edid data to connector. */
130 connector->display_info.raw_edid = (char *)raw_edid;
131
132 memcpy(edid, ctx->raw_edid, min((1 + ctx->raw_edid->extensions)
133 * EDID_LENGTH, len));
134
135 return 0;
136}
137
138static void *vidi_get_panel(struct device *dev)
139{
140 DRM_DEBUG_KMS("%s\n", __FILE__);
141
142 /* TODO. */
143
144 return NULL;
145}
146
147static int vidi_check_timing(struct device *dev, void *timing)
148{
149 DRM_DEBUG_KMS("%s\n", __FILE__);
150
151 /* TODO. */
152
153 return 0;
154}
155
156static int vidi_display_power_on(struct device *dev, int mode)
157{
158 DRM_DEBUG_KMS("%s\n", __FILE__);
159
160 /* TODO */
161
162 return 0;
163}
164
165static struct exynos_drm_display_ops vidi_display_ops = {
166 .type = EXYNOS_DISPLAY_TYPE_VIDI,
167 .is_connected = vidi_display_is_connected,
168 .get_edid = vidi_get_edid,
169 .get_panel = vidi_get_panel,
170 .check_timing = vidi_check_timing,
171 .power_on = vidi_display_power_on,
172};
173
174static void vidi_dpms(struct device *subdrv_dev, int mode)
175{
176 struct vidi_context *ctx = get_vidi_context(subdrv_dev);
177
178 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
179
180 mutex_lock(&ctx->lock);
181
182 switch (mode) {
183 case DRM_MODE_DPMS_ON:
184 /* TODO. */
185 break;
186 case DRM_MODE_DPMS_STANDBY:
187 case DRM_MODE_DPMS_SUSPEND:
188 case DRM_MODE_DPMS_OFF:
189 /* TODO. */
190 break;
191 default:
192 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
193 break;
194 }
195
196 mutex_unlock(&ctx->lock);
197}
198
199static void vidi_apply(struct device *subdrv_dev)
200{
201 struct vidi_context *ctx = get_vidi_context(subdrv_dev);
202 struct exynos_drm_manager *mgr = &ctx->subdrv.manager;
203 struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
204 struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
205 struct vidi_win_data *win_data;
206 int i;
207
208 DRM_DEBUG_KMS("%s\n", __FILE__);
209
210 for (i = 0; i < WINDOWS_NR; i++) {
211 win_data = &ctx->win_data[i];
212 if (win_data->enabled && (ovl_ops && ovl_ops->commit))
213 ovl_ops->commit(subdrv_dev, i);
214 }
215
216 if (mgr_ops && mgr_ops->commit)
217 mgr_ops->commit(subdrv_dev);
218}
219
220static void vidi_commit(struct device *dev)
221{
222 struct vidi_context *ctx = get_vidi_context(dev);
223
224 DRM_DEBUG_KMS("%s\n", __FILE__);
225
226 if (ctx->suspended)
227 return;
228}
229
230static int vidi_enable_vblank(struct device *dev)
231{
232 struct vidi_context *ctx = get_vidi_context(dev);
233
234 DRM_DEBUG_KMS("%s\n", __FILE__);
235
236 if (ctx->suspended)
237 return -EPERM;
238
239 if (!test_and_set_bit(0, &ctx->irq_flags))
240 ctx->vblank_on = true;
241
242 return 0;
243}
244
245static void vidi_disable_vblank(struct device *dev)
246{
247 struct vidi_context *ctx = get_vidi_context(dev);
248
249 DRM_DEBUG_KMS("%s\n", __FILE__);
250
251 if (ctx->suspended)
252 return;
253
254 if (test_and_clear_bit(0, &ctx->irq_flags))
255 ctx->vblank_on = false;
256}
257
258static struct exynos_drm_manager_ops vidi_manager_ops = {
259 .dpms = vidi_dpms,
260 .apply = vidi_apply,
261 .commit = vidi_commit,
262 .enable_vblank = vidi_enable_vblank,
263 .disable_vblank = vidi_disable_vblank,
264};
265
266static void vidi_win_mode_set(struct device *dev,
267 struct exynos_drm_overlay *overlay)
268{
269 struct vidi_context *ctx = get_vidi_context(dev);
270 struct vidi_win_data *win_data;
271 int win;
272 unsigned long offset;
273
274 DRM_DEBUG_KMS("%s\n", __FILE__);
275
276 if (!overlay) {
277 dev_err(dev, "overlay is NULL\n");
278 return;
279 }
280
281 win = overlay->zpos;
282 if (win == DEFAULT_ZPOS)
283 win = ctx->default_win;
284
285 if (win < 0 || win > WINDOWS_NR)
286 return;
287
288 offset = overlay->fb_x * (overlay->bpp >> 3);
289 offset += overlay->fb_y * overlay->pitch;
290
291 DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
292
293 win_data = &ctx->win_data[win];
294
295 win_data->offset_x = overlay->crtc_x;
296 win_data->offset_y = overlay->crtc_y;
297 win_data->ovl_width = overlay->crtc_width;
298 win_data->ovl_height = overlay->crtc_height;
299 win_data->fb_width = overlay->fb_width;
300 win_data->fb_height = overlay->fb_height;
301 win_data->dma_addr = overlay->dma_addr[0] + offset;
302 win_data->vaddr = overlay->vaddr[0] + offset;
303 win_data->bpp = overlay->bpp;
304 win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
305 (overlay->bpp >> 3);
306 win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
307
308 /*
309 * some parts of win_data should be transferred to user side
310 * through specific ioctl.
311 */
312
313 DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
314 win_data->offset_x, win_data->offset_y);
315 DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
316 win_data->ovl_width, win_data->ovl_height);
317 DRM_DEBUG_KMS("paddr = 0x%lx, vaddr = 0x%lx\n",
318 (unsigned long)win_data->dma_addr,
319 (unsigned long)win_data->vaddr);
320 DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
321 overlay->fb_width, overlay->crtc_width);
322}
323
324static void vidi_win_commit(struct device *dev, int zpos)
325{
326 struct vidi_context *ctx = get_vidi_context(dev);
327 struct vidi_win_data *win_data;
328 int win = zpos;
329
330 DRM_DEBUG_KMS("%s\n", __FILE__);
331
332 if (ctx->suspended)
333 return;
334
335 if (win == DEFAULT_ZPOS)
336 win = ctx->default_win;
337
338 if (win < 0 || win > WINDOWS_NR)
339 return;
340
341 win_data = &ctx->win_data[win];
342
343 win_data->enabled = true;
344
345 DRM_DEBUG_KMS("dma_addr = 0x%x\n", win_data->dma_addr);
346
347 if (ctx->vblank_on)
348 schedule_work(&ctx->work);
349}
350
351static void vidi_win_disable(struct device *dev, int zpos)
352{
353 struct vidi_context *ctx = get_vidi_context(dev);
354 struct vidi_win_data *win_data;
355 int win = zpos;
356
357 DRM_DEBUG_KMS("%s\n", __FILE__);
358
359 if (win == DEFAULT_ZPOS)
360 win = ctx->default_win;
361
362 if (win < 0 || win > WINDOWS_NR)
363 return;
364
365 win_data = &ctx->win_data[win];
366 win_data->enabled = false;
367
368 /* TODO. */
369}
370
371static struct exynos_drm_overlay_ops vidi_overlay_ops = {
372 .mode_set = vidi_win_mode_set,
373 .commit = vidi_win_commit,
374 .disable = vidi_win_disable,
375};
376
377static void vidi_finish_pageflip(struct drm_device *drm_dev, int crtc)
378{
379 struct exynos_drm_private *dev_priv = drm_dev->dev_private;
380 struct drm_pending_vblank_event *e, *t;
381 struct timeval now;
382 unsigned long flags;
383 bool is_checked = false;
384
385 spin_lock_irqsave(&drm_dev->event_lock, flags);
386
387 list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
388 base.link) {
389 /* if event's pipe isn't same as crtc then ignore it. */
390 if (crtc != e->pipe)
391 continue;
392
393 is_checked = true;
394
395 do_gettimeofday(&now);
396 e->event.sequence = 0;
397 e->event.tv_sec = now.tv_sec;
398 e->event.tv_usec = now.tv_usec;
399
400 list_move_tail(&e->base.link, &e->base.file_priv->event_list);
401 wake_up_interruptible(&e->base.file_priv->event_wait);
402 }
403
404 if (is_checked) {
405 /*
406 * call drm_vblank_put only in case that drm_vblank_get was
407 * called.
408 */
409 if (atomic_read(&drm_dev->vblank_refcount[crtc]) > 0)
410 drm_vblank_put(drm_dev, crtc);
411
412 /*
413 * don't off vblank if vblank_disable_allowed is 1,
414 * because vblank would be off by timer handler.
415 */
416 if (!drm_dev->vblank_disable_allowed)
417 drm_vblank_off(drm_dev, crtc);
418 }
419
420 spin_unlock_irqrestore(&drm_dev->event_lock, flags);
421}
422
423static void vidi_fake_vblank_handler(struct work_struct *work)
424{
425 struct vidi_context *ctx = container_of(work, struct vidi_context,
426 work);
427 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
428 struct exynos_drm_manager *manager = &subdrv->manager;
429
430 if (manager->pipe < 0)
431 return;
432
433 /* refresh rate is about 50Hz. */
434 usleep_range(16000, 20000);
435
436 drm_handle_vblank(subdrv->drm_dev, manager->pipe);
437 vidi_finish_pageflip(subdrv->drm_dev, manager->pipe);
438}
439
440static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
441{
442 DRM_DEBUG_KMS("%s\n", __FILE__);
443
444 /*
445 * enable drm irq mode.
446 * - with irq_enabled = 1, we can use the vblank feature.
447 *
448 * P.S. note that we wouldn't use drm irq handler but
449 * just specific driver own one instead because
450 * drm framework supports only one irq handler.
451 */
452 drm_dev->irq_enabled = 1;
453
454 /*
455 * with vblank_disable_allowed = 1, vblank interrupt will be disabled
456 * by drm timer once a current process gives up ownership of
457 * vblank event.(after drm_vblank_put function is called)
458 */
459 drm_dev->vblank_disable_allowed = 1;
460
461 return 0;
462}
463
464static void vidi_subdrv_remove(struct drm_device *drm_dev)
465{
466 DRM_DEBUG_KMS("%s\n", __FILE__);
467
468 /* TODO. */
469}
470
471static int vidi_power_on(struct vidi_context *ctx, bool enable)
472{
473 struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
474 struct device *dev = subdrv->manager.dev;
475
476 DRM_DEBUG_KMS("%s\n", __FILE__);
477
478 if (enable != false && enable != true)
479 return -EINVAL;
480
481 if (enable) {
482 ctx->suspended = false;
483
484 /* if vblank was enabled status, enable it again. */
485 if (test_and_clear_bit(0, &ctx->irq_flags))
486 vidi_enable_vblank(dev);
487
488 vidi_apply(dev);
489 } else {
490 ctx->suspended = true;
491 }
492
493 return 0;
494}
495
496static int vidi_show_connection(struct device *dev,
497 struct device_attribute *attr, char *buf)
498{
499 int rc;
500 struct vidi_context *ctx = get_vidi_context(dev);
501
502 mutex_lock(&ctx->lock);
503
504 rc = sprintf(buf, "%d\n", ctx->connected);
505
506 mutex_unlock(&ctx->lock);
507
508 return rc;
509}
510
511static int vidi_store_connection(struct device *dev,
512 struct device_attribute *attr,
513 const char *buf, size_t len)
514{
515 struct vidi_context *ctx = get_vidi_context(dev);
516 int ret;
517
518 DRM_DEBUG_KMS("%s\n", __FILE__);
519
520 ret = kstrtoint(buf, 0, &ctx->connected);
521 if (ret)
522 return ret;
523
524 if (ctx->connected > 1)
525 return -EINVAL;
526
527 DRM_DEBUG_KMS("requested connection.\n");
528
529 drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
530
531 return len;
532}
533
534static DEVICE_ATTR(connection, 0644, vidi_show_connection,
535 vidi_store_connection);
536
537int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
538 struct drm_file *file_priv)
539{
540 struct vidi_context *ctx = NULL;
541 struct drm_encoder *encoder;
542 struct exynos_drm_manager *manager;
543 struct exynos_drm_display_ops *display_ops;
544 struct drm_exynos_vidi_connection *vidi = data;
545
546 DRM_DEBUG_KMS("%s\n", __FILE__);
547
548 if (!vidi) {
549 DRM_DEBUG_KMS("user data for vidi is null.\n");
550 return -EINVAL;
551 }
552
553 if (!vidi->edid) {
554 DRM_DEBUG_KMS("edid data is null.\n");
555 return -EINVAL;
556 }
557
558 if (vidi->connection > 1) {
559 DRM_DEBUG_KMS("connection should be 0 or 1.\n");
560 return -EINVAL;
561 }
562
563 list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
564 head) {
565 manager = exynos_drm_get_manager(encoder);
566 display_ops = manager->display_ops;
567
568 if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
569 ctx = get_vidi_context(manager->dev);
570 break;
571 }
572 }
573
574 if (!ctx) {
575 DRM_DEBUG_KMS("not found virtual device type encoder.\n");
576 return -EINVAL;
577 }
578
579 if (ctx->connected == vidi->connection) {
580 DRM_DEBUG_KMS("same connection request.\n");
581 return -EINVAL;
582 }
583
584 if (vidi->connection)
585 ctx->raw_edid = (struct edid *)vidi->edid;
586
587 ctx->connected = vidi->connection;
588 drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
589
590 return 0;
591}
592
593static int __devinit vidi_probe(struct platform_device *pdev)
594{
595 struct device *dev = &pdev->dev;
596 struct vidi_context *ctx;
597 struct exynos_drm_subdrv *subdrv;
598 int ret;
599
600 DRM_DEBUG_KMS("%s\n", __FILE__);
601
602 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
603 if (!ctx)
604 return -ENOMEM;
605
606 ctx->default_win = 0;
607
608 INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
609
610 /* for test */
611 ctx->raw_edid = (struct edid *)fake_edid_info;
612
613 subdrv = &ctx->subdrv;
614 subdrv->probe = vidi_subdrv_probe;
615 subdrv->remove = vidi_subdrv_remove;
616 subdrv->manager.pipe = -1;
617 subdrv->manager.ops = &vidi_manager_ops;
618 subdrv->manager.overlay_ops = &vidi_overlay_ops;
619 subdrv->manager.display_ops = &vidi_display_ops;
620 subdrv->manager.dev = dev;
621
622 mutex_init(&ctx->lock);
623
624 platform_set_drvdata(pdev, ctx);
625
626 ret = device_create_file(&pdev->dev, &dev_attr_connection);
627 if (ret < 0)
628 DRM_INFO("failed to create connection sysfs.\n");
629
630 exynos_drm_subdrv_register(subdrv);
631
632 return 0;
633}
634
635static int __devexit vidi_remove(struct platform_device *pdev)
636{
637 struct vidi_context *ctx = platform_get_drvdata(pdev);
638
639 DRM_DEBUG_KMS("%s\n", __FILE__);
640
641 exynos_drm_subdrv_unregister(&ctx->subdrv);
642
643 kfree(ctx);
644
645 return 0;
646}
647
648#ifdef CONFIG_PM_SLEEP
649static int vidi_suspend(struct device *dev)
650{
651 struct vidi_context *ctx = get_vidi_context(dev);
652
653 return vidi_power_on(ctx, false);
654}
655
656static int vidi_resume(struct device *dev)
657{
658 struct vidi_context *ctx = get_vidi_context(dev);
659
660 return vidi_power_on(ctx, true);
661}
662#endif
663
664static const struct dev_pm_ops vidi_pm_ops = {
665 SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
666};
667
668struct platform_driver vidi_driver = {
669 .probe = vidi_probe,
670 .remove = __devexit_p(vidi_remove),
671 .driver = {
672 .name = "exynos-drm-vidi",
673 .owner = THIS_MODULE,
674 .pm = &vidi_pm_ops,
675 },
676};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.h b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
new file mode 100644
index 000000000000..a4babe4e65d7
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.h
@@ -0,0 +1,36 @@
1/* exynos_drm_vidi.h
2 *
3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 * Author: Inki Dae <inki.dae@samsung.com>
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the next
14 * paragraph) shall be included in all copies or substantial portions of the
15 * Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26#ifndef _EXYNOS_DRM_VIDI_H_
27#define _EXYNOS_DRM_VIDI_H_
28
29#ifdef CONFIG_DRM_EXYNOS_VIDI
30int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
31 struct drm_file *file_priv);
32#else
33#define vidi_connection_ioctl NULL
34#endif
35
36#endif
diff --git a/include/drm/exynos_drm.h b/include/drm/exynos_drm.h
index 81c9cb77476e..3963116083ae 100644
--- a/include/drm/exynos_drm.h
+++ b/include/drm/exynos_drm.h
@@ -74,6 +74,20 @@ struct drm_exynos_gem_mmap {
74 uint64_t mapped; 74 uint64_t mapped;
75}; 75};
76 76
77/**
78 * A structure for user connection request of virtual display.
79 *
80 * @connection: indicate whether doing connetion or not by user.
81 * @extensions: if this value is 1 then the vidi driver would need additional
82 * 128bytes edid data.
83 * @edid: the edid data pointer from user side.
84 */
85struct drm_exynos_vidi_connection {
86 unsigned int connection;
87 unsigned int extensions;
88 uint64_t *edid;
89};
90
77struct drm_exynos_plane_set_zpos { 91struct drm_exynos_plane_set_zpos {
78 __u32 plane_id; 92 __u32 plane_id;
79 __s32 zpos; 93 __s32 zpos;
@@ -90,6 +104,7 @@ enum e_drm_exynos_gem_mem_type {
90#define DRM_EXYNOS_GEM_MMAP 0x02 104#define DRM_EXYNOS_GEM_MMAP 0x02
91/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */ 105/* Reserved 0x03 ~ 0x05 for exynos specific gem ioctl */
92#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06 106#define DRM_EXYNOS_PLANE_SET_ZPOS 0x06
107#define DRM_EXYNOS_VIDI_CONNECTION 0x07
93 108
94#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \ 109#define DRM_IOCTL_EXYNOS_GEM_CREATE DRM_IOWR(DRM_COMMAND_BASE + \
95 DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create) 110 DRM_EXYNOS_GEM_CREATE, struct drm_exynos_gem_create)
@@ -103,6 +118,9 @@ enum e_drm_exynos_gem_mem_type {
103#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \ 118#define DRM_IOCTL_EXYNOS_PLANE_SET_ZPOS DRM_IOWR(DRM_COMMAND_BASE + \
104 DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos) 119 DRM_EXYNOS_PLANE_SET_ZPOS, struct drm_exynos_plane_set_zpos)
105 120
121#define DRM_IOCTL_EXYNOS_VIDI_CONNECTION DRM_IOWR(DRM_COMMAND_BASE + \
122 DRM_EXYNOS_VIDI_CONNECTION, struct drm_exynos_vidi_connection)
123
106#ifdef __KERNEL__ 124#ifdef __KERNEL__
107 125
108/** 126/**