Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
exynos_drm_hdmi.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2011 Samsung Electronics Co.Ltd
3  * Authors:
4  * Inki Dae <[email protected]>
5  * Seung-Woo Kim <[email protected]>
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 <drm/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 
45 
47 };
48 
50 {
51  if (ctx)
52  hdmi_ctx = ctx;
53 }
54 
56 {
57  if (ctx)
58  mixer_ctx = ctx;
59 }
60 
62 {
63  DRM_DEBUG_KMS("%s\n", __FILE__);
64 
65  if (ops)
66  hdmi_ops = ops;
67 }
68 
70 {
71  DRM_DEBUG_KMS("%s\n", __FILE__);
72 
73  if (ops)
74  mixer_ops = ops;
75 }
76 
77 static bool drm_hdmi_is_connected(struct device *dev)
78 {
79  struct drm_hdmi_context *ctx = to_context(dev);
80 
81  DRM_DEBUG_KMS("%s\n", __FILE__);
82 
83  if (hdmi_ops && hdmi_ops->is_connected)
84  return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
85 
86  return false;
87 }
88 
89 static int drm_hdmi_get_edid(struct device *dev,
90  struct drm_connector *connector, u8 *edid, int len)
91 {
92  struct drm_hdmi_context *ctx = to_context(dev);
93 
94  DRM_DEBUG_KMS("%s\n", __FILE__);
95 
96  if (hdmi_ops && hdmi_ops->get_edid)
97  return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid,
98  len);
99 
100  return 0;
101 }
102 
103 static int drm_hdmi_check_timing(struct device *dev, void *timing)
104 {
105  struct drm_hdmi_context *ctx = to_context(dev);
106 
107  DRM_DEBUG_KMS("%s\n", __FILE__);
108 
109  if (hdmi_ops && hdmi_ops->check_timing)
110  return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
111 
112  return 0;
113 }
114 
115 static int drm_hdmi_power_on(struct device *dev, int mode)
116 {
117  struct drm_hdmi_context *ctx = to_context(dev);
118 
119  DRM_DEBUG_KMS("%s\n", __FILE__);
120 
121  if (hdmi_ops && hdmi_ops->power_on)
122  return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
123 
124  return 0;
125 }
126 
127 static struct exynos_drm_display_ops drm_hdmi_display_ops = {
128  .type = EXYNOS_DISPLAY_TYPE_HDMI,
129  .is_connected = drm_hdmi_is_connected,
130  .get_edid = drm_hdmi_get_edid,
131  .check_timing = drm_hdmi_check_timing,
132  .power_on = drm_hdmi_power_on,
133 };
134 
135 static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
136 {
137  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
138  struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
139  struct exynos_drm_manager *manager = subdrv->manager;
140 
141  DRM_DEBUG_KMS("%s\n", __FILE__);
142 
143  if (mixer_ops && mixer_ops->enable_vblank)
144  return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
145  manager->pipe);
146 
147  return 0;
148 }
149 
150 static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
151 {
152  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
153 
154  DRM_DEBUG_KMS("%s\n", __FILE__);
155 
156  if (mixer_ops && mixer_ops->disable_vblank)
157  return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
158 }
159 
160 static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
161  struct drm_connector *connector,
162  const struct drm_display_mode *mode,
163  struct drm_display_mode *adjusted_mode)
164 {
165  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
166 
167  DRM_DEBUG_KMS("%s\n", __FILE__);
168 
169  if (hdmi_ops && hdmi_ops->mode_fixup)
170  hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
171  adjusted_mode);
172 }
173 
174 static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
175 {
176  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
177 
178  DRM_DEBUG_KMS("%s\n", __FILE__);
179 
180  if (hdmi_ops && hdmi_ops->mode_set)
181  hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
182 }
183 
184 static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
185  unsigned int *width, unsigned int *height)
186 {
187  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
188 
189  DRM_DEBUG_KMS("%s\n", __FILE__);
190 
191  if (hdmi_ops && hdmi_ops->get_max_resol)
192  hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
193 }
194 
195 static void drm_hdmi_commit(struct device *subdrv_dev)
196 {
197  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
198 
199  DRM_DEBUG_KMS("%s\n", __FILE__);
200 
201  if (hdmi_ops && hdmi_ops->commit)
202  hdmi_ops->commit(ctx->hdmi_ctx->ctx);
203 }
204 
205 static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
206 {
207  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
208 
209  DRM_DEBUG_KMS("%s\n", __FILE__);
210 
211  if (mixer_ops && mixer_ops->dpms)
212  mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
213 
214  if (hdmi_ops && hdmi_ops->dpms)
215  hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
216 }
217 
218 static void drm_hdmi_apply(struct device *subdrv_dev)
219 {
220  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
221  int i;
222 
223  DRM_DEBUG_KMS("%s\n", __FILE__);
224 
225  for (i = 0; i < MIXER_WIN_NR; i++) {
226  if (!ctx->enabled[i])
227  continue;
228  if (mixer_ops && mixer_ops->win_commit)
229  mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
230  }
231 
232  if (hdmi_ops && hdmi_ops->commit)
233  hdmi_ops->commit(ctx->hdmi_ctx->ctx);
234 }
235 
236 static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
237  .dpms = drm_hdmi_dpms,
238  .apply = drm_hdmi_apply,
239  .enable_vblank = drm_hdmi_enable_vblank,
240  .disable_vblank = drm_hdmi_disable_vblank,
241  .mode_fixup = drm_hdmi_mode_fixup,
242  .mode_set = drm_hdmi_mode_set,
243  .get_max_resol = drm_hdmi_get_max_resol,
244  .commit = drm_hdmi_commit,
245 };
246 
247 static void drm_mixer_mode_set(struct device *subdrv_dev,
248  struct exynos_drm_overlay *overlay)
249 {
250  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
251 
252  DRM_DEBUG_KMS("%s\n", __FILE__);
253 
254  if (mixer_ops && mixer_ops->win_mode_set)
255  mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
256 }
257 
258 static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
259 {
260  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
261  int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
262 
263  DRM_DEBUG_KMS("%s\n", __FILE__);
264 
265  if (win < 0 || win > MIXER_WIN_NR) {
266  DRM_ERROR("mixer window[%d] is wrong\n", win);
267  return;
268  }
269 
270  if (mixer_ops && mixer_ops->win_commit)
271  mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
272 
273  ctx->enabled[win] = true;
274 }
275 
276 static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
277 {
278  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
279  int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
280 
281  DRM_DEBUG_KMS("%s\n", __FILE__);
282 
283  if (win < 0 || win > MIXER_WIN_NR) {
284  DRM_ERROR("mixer window[%d] is wrong\n", win);
285  return;
286  }
287 
288  if (mixer_ops && mixer_ops->win_disable)
289  mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
290 
291  ctx->enabled[win] = false;
292 }
293 
294 static void drm_mixer_wait_for_vblank(struct device *subdrv_dev)
295 {
296  struct drm_hdmi_context *ctx = to_context(subdrv_dev);
297 
298  DRM_DEBUG_KMS("%s\n", __FILE__);
299 
300  if (mixer_ops && mixer_ops->wait_for_vblank)
301  mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
302 }
303 
304 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
305  .mode_set = drm_mixer_mode_set,
306  .commit = drm_mixer_commit,
307  .disable = drm_mixer_disable,
308  .wait_for_vblank = drm_mixer_wait_for_vblank,
309 };
310 
311 static struct exynos_drm_manager hdmi_manager = {
312  .pipe = -1,
313  .ops = &drm_hdmi_manager_ops,
314  .overlay_ops = &drm_hdmi_overlay_ops,
315  .display_ops = &drm_hdmi_display_ops,
316 };
317 
318 static int hdmi_subdrv_probe(struct drm_device *drm_dev,
319  struct device *dev)
320 {
321  struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
322  struct drm_hdmi_context *ctx;
323 
324  DRM_DEBUG_KMS("%s\n", __FILE__);
325 
326  if (!hdmi_ctx) {
327  DRM_ERROR("hdmi context not initialized.\n");
328  return -EFAULT;
329  }
330 
331  if (!mixer_ctx) {
332  DRM_ERROR("mixer context not initialized.\n");
333  return -EFAULT;
334  }
335 
336  ctx = get_ctx_from_subdrv(subdrv);
337 
338  if (!ctx) {
339  DRM_ERROR("no drm hdmi context.\n");
340  return -EFAULT;
341  }
342 
343  ctx->hdmi_ctx = hdmi_ctx;
344  ctx->mixer_ctx = mixer_ctx;
345 
346  ctx->hdmi_ctx->drm_dev = drm_dev;
347  ctx->mixer_ctx->drm_dev = drm_dev;
348 
349  return 0;
350 }
351 
352 static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
353 {
354  struct device *dev = &pdev->dev;
355  struct exynos_drm_subdrv *subdrv;
356  struct drm_hdmi_context *ctx;
357 
358  DRM_DEBUG_KMS("%s\n", __FILE__);
359 
360  ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
361  if (!ctx) {
362  DRM_LOG_KMS("failed to alloc common hdmi context.\n");
363  return -ENOMEM;
364  }
365 
366  subdrv = &ctx->subdrv;
367 
368  subdrv->dev = dev;
369  subdrv->manager = &hdmi_manager;
370  subdrv->probe = hdmi_subdrv_probe;
371 
372  platform_set_drvdata(pdev, subdrv);
373 
375 
376  return 0;
377 }
378 
379 static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
380 {
381  struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
382 
383  DRM_DEBUG_KMS("%s\n", __FILE__);
384 
386 
387  return 0;
388 }
389 
391  .probe = exynos_drm_hdmi_probe,
392  .remove = __devexit_p(exynos_drm_hdmi_remove),
393  .driver = {
394  .name = "exynos-drm-hdmi",
395  .owner = THIS_MODULE,
396  },
397 };