Add S2R functionality for HDMI and Mixer
[cascardo/linux.git] / drivers / gpu / drm / exynos / exynos_drm_hdmi.c
1 /*
2  * Copyright (C) 2011 Samsung Electronics Co.Ltd
3  * Authors:
4  *      Inki Dae <inki.dae@samsung.com>
5  *      Seung-Woo Kim <sw0312.kim@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
14 #include "drmP.h"
15
16 #include <linux/kernel.h>
17 #include <linux/wait.h>
18 #include <linux/module.h>
19 #include <linux/platform_device.h>
20 #include <linux/pm_runtime.h>
21
22 #include <drm/exynos_drm.h>
23
24 #include "exynos_drm_drv.h"
25 #include "exynos_drm_hdmi.h"
26
27 #define to_context(dev)         platform_get_drvdata(to_platform_device(dev))
28 #define to_subdrv(dev)          to_context(dev)
29 #define get_ctx_from_subdrv(subdrv)     container_of(subdrv,\
30                                         struct drm_hdmi_context, subdrv);
31
32 /* Common hdmi subdrv needs to access the hdmi and mixer though context.
33 * These should be initialied by the repective drivers */
34 static struct exynos_drm_hdmi_context *hdmi_ctx;
35 static struct exynos_drm_hdmi_context *mixer_ctx;
36
37 /* these callback points shoud be set by specific drivers. */
38 static struct exynos_hdmi_ops *hdmi_ops;
39 static struct exynos_mixer_ops *mixer_ops;
40
41 struct drm_hdmi_context {
42         struct exynos_drm_subdrv        subdrv;
43         struct exynos_drm_hdmi_context  *hdmi_ctx;
44         struct exynos_drm_hdmi_context  *mixer_ctx;
45         bool    enabled[MIXER_WIN_NR];
46 };
47
48 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
49 {
50         DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
51         hdmi_ctx = ctx;
52 }
53
54 void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
55 {
56         DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
57         mixer_ctx = ctx;
58 }
59
60 void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
61 {
62         DRM_DEBUG_KMS("%s\n", __FILE__);
63
64         if (ops)
65                 hdmi_ops = ops;
66 }
67
68 void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
69 {
70         DRM_DEBUG_KMS("%s\n", __FILE__);
71
72         if (ops)
73                 mixer_ops = ops;
74 }
75
76 static bool drm_hdmi_is_connected(struct device *dev)
77 {
78         struct drm_hdmi_context *ctx = to_context(dev);
79
80         DRM_DEBUG_KMS("%s\n", __FILE__);
81
82         if (hdmi_ops && hdmi_ops->is_connected)
83                 return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
84
85         return false;
86 }
87
88 static int drm_hdmi_get_edid(struct device *dev,
89                 struct drm_connector *connector, u8 *edid, int len)
90 {
91         struct drm_hdmi_context *ctx = to_context(dev);
92
93         DRM_DEBUG_KMS("%s\n", __FILE__);
94
95         if (hdmi_ops && hdmi_ops->get_edid)
96                 return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid,
97                                           len);
98
99         return 0;
100 }
101
102 static int drm_hdmi_check_timing(struct device *dev, void *timing)
103 {
104         struct drm_hdmi_context *ctx = to_context(dev);
105
106         DRM_DEBUG_KMS("%s\n", __FILE__);
107
108         if (hdmi_ops && hdmi_ops->check_timing)
109                 return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
110
111         return 0;
112 }
113
114 static int drm_hdmi_power_on(struct device *dev, int mode)
115 {
116         struct drm_hdmi_context *ctx = to_context(dev);
117
118         DRM_DEBUG_KMS("%s\n", __FILE__);
119
120         if (mixer_ops && mixer_ops->power_on) {
121                 if (mixer_ops->power_on(ctx->mixer_ctx->ctx, mode))
122                         return -EINVAL;
123         }
124
125         if (hdmi_ops && hdmi_ops->power_on)
126                 return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
127
128         return 0;
129 }
130
131 static struct exynos_drm_display_ops drm_hdmi_display_ops = {
132         .type = EXYNOS_DISPLAY_TYPE_HDMI,
133         .is_connected = drm_hdmi_is_connected,
134         .get_edid = drm_hdmi_get_edid,
135         .check_timing = drm_hdmi_check_timing,
136         .power_on = drm_hdmi_power_on,
137 };
138
139 static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
140 {
141         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
142         struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
143         struct exynos_drm_manager *manager = subdrv->manager;
144
145         DRM_DEBUG_KMS("%s\n", __FILE__);
146
147         if (mixer_ops && mixer_ops->enable_vblank)
148                 return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
149                                                 manager->pipe);
150
151         return 0;
152 }
153
154 static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
155 {
156         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
157
158         DRM_DEBUG_KMS("%s\n", __FILE__);
159
160         if (mixer_ops && mixer_ops->disable_vblank)
161                 return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
162 }
163
164 static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
165                                 struct drm_connector *connector,
166                                 struct drm_display_mode *mode,
167                                 struct drm_display_mode *adjusted_mode)
168 {
169         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
170
171         DRM_DEBUG_KMS("%s\n", __FILE__);
172
173         if (hdmi_ops && hdmi_ops->mode_fixup)
174                 hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
175                                      adjusted_mode);
176 }
177
178 static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
179 {
180         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
181
182         DRM_DEBUG_KMS("%s\n", __FILE__);
183
184         if (hdmi_ops && hdmi_ops->mode_set)
185                 hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
186 }
187
188 static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
189                                 unsigned int *width, unsigned int *height)
190 {
191         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
192
193         DRM_DEBUG_KMS("%s\n", __FILE__);
194
195         if (hdmi_ops && hdmi_ops->get_max_resol)
196                 hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
197 }
198
199 static void drm_hdmi_commit(struct device *subdrv_dev)
200 {
201         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
202
203         DRM_DEBUG_KMS("%s\n", __FILE__);
204
205         if (hdmi_ops && hdmi_ops->commit)
206                 hdmi_ops->commit(ctx->hdmi_ctx->ctx);
207 }
208
209 static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
210 {
211         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
212
213         DRM_DEBUG_KMS("%s\n", __FILE__);
214
215         if (mixer_ops && mixer_ops->dpms)
216                 mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
217
218         if (hdmi_ops && hdmi_ops->dpms)
219                 hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
220 }
221
222 static void drm_hdmi_apply(struct device *subdrv_dev)
223 {
224         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
225         int i;
226
227         DRM_DEBUG_KMS("%s\n", __FILE__);
228
229         for (i = 0; i < MIXER_WIN_NR; i++) {
230                 if (!ctx->enabled[i])
231                         continue;
232                 if (mixer_ops && mixer_ops->win_commit)
233                         mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
234         }
235
236         if (hdmi_ops && hdmi_ops->commit)
237                 hdmi_ops->commit(ctx->hdmi_ctx->ctx);
238 }
239
240 static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
241         .dpms = drm_hdmi_dpms,
242         .apply = drm_hdmi_apply,
243         .enable_vblank = drm_hdmi_enable_vblank,
244         .disable_vblank = drm_hdmi_disable_vblank,
245         .mode_fixup = drm_hdmi_mode_fixup,
246         .mode_set = drm_hdmi_mode_set,
247         .get_max_resol = drm_hdmi_get_max_resol,
248         .commit = drm_hdmi_commit,
249 };
250
251 static void drm_mixer_mode_set(struct device *subdrv_dev,
252                 struct exynos_drm_overlay *overlay)
253 {
254         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
255
256         DRM_DEBUG_KMS("%s\n", __FILE__);
257
258         if (mixer_ops && mixer_ops->win_mode_set)
259                 mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
260 }
261
262 static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
263 {
264         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
265         int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
266
267         DRM_DEBUG_KMS("%s\n", __FILE__);
268
269         if (win < 0 || win > MIXER_WIN_NR) {
270                 DRM_ERROR("mixer window[%d] is wrong\n", win);
271                 return;
272         }
273
274         if (mixer_ops && mixer_ops->win_commit)
275                 mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
276
277         ctx->enabled[win] = true;
278 }
279
280 static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
281 {
282         struct drm_hdmi_context *ctx = to_context(subdrv_dev);
283         int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
284
285         DRM_DEBUG_KMS("%s\n", __FILE__);
286
287         if (win < 0 || win > MIXER_WIN_NR) {
288                 DRM_ERROR("mixer window[%d] is wrong\n", win);
289                 return;
290         }
291
292         if (mixer_ops && mixer_ops->win_disable)
293                 mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
294
295         ctx->enabled[win] = false;
296 }
297
298 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
299         .mode_set = drm_mixer_mode_set,
300         .commit = drm_mixer_commit,
301         .disable = drm_mixer_disable,
302 };
303
304 static struct exynos_drm_manager hdmi_manager = {
305         .pipe           = -1,
306         .ops            = &drm_hdmi_manager_ops,
307         .overlay_ops    = &drm_hdmi_overlay_ops,
308         .display_ops    = &drm_hdmi_display_ops,
309 };
310
311 static int hdmi_subdrv_probe(struct drm_device *drm_dev,
312                 struct device *dev)
313 {
314         struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
315         struct drm_hdmi_context *ctx;
316
317         DRM_DEBUG_KMS("%s\n", __FILE__);
318
319         if (!hdmi_ctx) {
320                 DRM_DEBUG_KMS("hdmi context is null.\n");
321                 return -EFAULT;
322         }
323
324         if (!mixer_ctx) {
325                 DRM_DEBUG_KMS("mixer context is null.\n");
326                 return -EFAULT;
327         }
328
329         ctx = get_ctx_from_subdrv(subdrv);
330
331         ctx->hdmi_ctx = hdmi_ctx;
332         ctx->mixer_ctx = mixer_ctx;
333
334         ctx->hdmi_ctx->drm_dev = drm_dev;
335
336         ctx->mixer_ctx->drm_dev = drm_dev;
337
338         return 0;
339 }
340
341 static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
342 {
343         struct device *dev = &pdev->dev;
344         struct exynos_drm_subdrv *subdrv;
345         struct drm_hdmi_context *ctx;
346
347         DRM_DEBUG_KMS("%s\n", __FILE__);
348
349         ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
350         if (!ctx) {
351                 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
352                 return -ENOMEM;
353         }
354
355         subdrv = &ctx->subdrv;
356
357         subdrv->dev = dev;
358         subdrv->manager = &hdmi_manager;
359         subdrv->probe = hdmi_subdrv_probe;
360
361         platform_set_drvdata(pdev, subdrv);
362
363         exynos_drm_subdrv_register(subdrv);
364
365         return 0;
366 }
367
368 static int hdmi_runtime_suspend(struct device *dev)
369 {
370         DRM_DEBUG_KMS("%s\n", __FILE__);
371
372         return 0;
373 }
374
375 static int hdmi_runtime_resume(struct device *dev)
376 {
377         DRM_DEBUG_KMS("%s\n", __FILE__);
378
379         return 0;
380 }
381
382 static const struct dev_pm_ops hdmi_pm_ops = {
383         .runtime_suspend = hdmi_runtime_suspend,
384         .runtime_resume  = hdmi_runtime_resume,
385 };
386
387 static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
388 {
389         struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
390
391         DRM_DEBUG_KMS("%s\n", __FILE__);
392
393         exynos_drm_subdrv_unregister(&ctx->subdrv);
394         kfree(ctx);
395
396         return 0;
397 }
398
399 struct platform_driver exynos_drm_common_hdmi_driver = {
400         .probe          = exynos_drm_hdmi_probe,
401         .remove         = __devexit_p(exynos_drm_hdmi_remove),
402         .driver         = {
403                 .name   = "exynos-drm-hdmi",
404                 .owner  = THIS_MODULE,
405                 .pm = &hdmi_pm_ops,
406         },
407 };