2 * Copyright (C) 2011 Samsung Electronics Co.Ltd
4 * Inki Dae <inki.dae@samsung.com>
5 * Seung-Woo Kim <sw0312.kim@samsung.com>
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.
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>
22 #include <drm/exynos_drm.h>
24 #include "exynos_drm_drv.h"
25 #include "exynos_drm_hdmi.h"
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);
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;
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;
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];
48 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
50 DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
54 void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
56 DRM_DEBUG_KMS("%s. %s.\n", __FILE__, __func__);
60 void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
62 DRM_DEBUG_KMS("%s\n", __FILE__);
68 void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
70 DRM_DEBUG_KMS("%s\n", __FILE__);
76 static bool drm_hdmi_is_connected(struct device *dev)
78 struct drm_hdmi_context *ctx = to_context(dev);
80 DRM_DEBUG_KMS("%s\n", __FILE__);
82 if (hdmi_ops && hdmi_ops->is_connected)
83 return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
88 static int drm_hdmi_get_edid(struct device *dev,
89 struct drm_connector *connector, u8 *edid, int len)
91 struct drm_hdmi_context *ctx = to_context(dev);
93 DRM_DEBUG_KMS("%s\n", __FILE__);
95 if (hdmi_ops && hdmi_ops->get_edid)
96 return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector, edid,
102 static int drm_hdmi_check_timing(struct device *dev, void *timing)
104 struct drm_hdmi_context *ctx = to_context(dev);
106 DRM_DEBUG_KMS("%s\n", __FILE__);
108 if (hdmi_ops && hdmi_ops->check_timing)
109 return hdmi_ops->check_timing(ctx->hdmi_ctx->ctx, timing);
114 static int drm_hdmi_power_on(struct device *dev, int mode)
116 struct drm_hdmi_context *ctx = to_context(dev);
118 DRM_DEBUG_KMS("%s\n", __FILE__);
120 if (mixer_ops && mixer_ops->power_on) {
121 if (mixer_ops->power_on(ctx->mixer_ctx->ctx, mode))
125 if (hdmi_ops && hdmi_ops->power_on)
126 return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
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,
139 static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
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;
145 DRM_DEBUG_KMS("%s\n", __FILE__);
147 if (mixer_ops && mixer_ops->enable_vblank)
148 return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
154 static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
156 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
158 DRM_DEBUG_KMS("%s\n", __FILE__);
160 if (mixer_ops && mixer_ops->disable_vblank)
161 return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
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)
169 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
171 DRM_DEBUG_KMS("%s\n", __FILE__);
173 if (hdmi_ops && hdmi_ops->mode_fixup)
174 hdmi_ops->mode_fixup(ctx->hdmi_ctx->ctx, connector, mode,
178 static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
180 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
182 DRM_DEBUG_KMS("%s\n", __FILE__);
184 if (hdmi_ops && hdmi_ops->mode_set)
185 hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
188 static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
189 unsigned int *width, unsigned int *height)
191 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
193 DRM_DEBUG_KMS("%s\n", __FILE__);
195 if (hdmi_ops && hdmi_ops->get_max_resol)
196 hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
199 static void drm_hdmi_commit(struct device *subdrv_dev)
201 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
203 DRM_DEBUG_KMS("%s\n", __FILE__);
205 if (hdmi_ops && hdmi_ops->commit)
206 hdmi_ops->commit(ctx->hdmi_ctx->ctx);
209 static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
211 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
213 DRM_DEBUG_KMS("%s\n", __FILE__);
215 if (mixer_ops && mixer_ops->dpms)
216 mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
218 if (hdmi_ops && hdmi_ops->dpms)
219 hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
222 static void drm_hdmi_apply(struct device *subdrv_dev)
224 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
227 DRM_DEBUG_KMS("%s\n", __FILE__);
229 for (i = 0; i < MIXER_WIN_NR; i++) {
230 if (!ctx->enabled[i])
232 if (mixer_ops && mixer_ops->win_commit)
233 mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
236 if (hdmi_ops && hdmi_ops->commit)
237 hdmi_ops->commit(ctx->hdmi_ctx->ctx);
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,
251 static void drm_mixer_mode_set(struct device *subdrv_dev,
252 struct exynos_drm_overlay *overlay)
254 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
256 DRM_DEBUG_KMS("%s\n", __FILE__);
258 if (mixer_ops && mixer_ops->win_mode_set)
259 mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
262 static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
264 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
265 int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
267 DRM_DEBUG_KMS("%s\n", __FILE__);
269 if (win < 0 || win > MIXER_WIN_NR) {
270 DRM_ERROR("mixer window[%d] is wrong\n", win);
274 if (mixer_ops && mixer_ops->win_commit)
275 mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
277 ctx->enabled[win] = true;
280 static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
282 struct drm_hdmi_context *ctx = to_context(subdrv_dev);
283 int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
285 DRM_DEBUG_KMS("%s\n", __FILE__);
287 if (win < 0 || win > MIXER_WIN_NR) {
288 DRM_ERROR("mixer window[%d] is wrong\n", win);
292 if (mixer_ops && mixer_ops->win_disable)
293 mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
295 ctx->enabled[win] = false;
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,
304 static struct exynos_drm_manager hdmi_manager = {
306 .ops = &drm_hdmi_manager_ops,
307 .overlay_ops = &drm_hdmi_overlay_ops,
308 .display_ops = &drm_hdmi_display_ops,
311 static int hdmi_subdrv_probe(struct drm_device *drm_dev,
314 struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
315 struct drm_hdmi_context *ctx;
317 DRM_DEBUG_KMS("%s\n", __FILE__);
320 DRM_DEBUG_KMS("hdmi context is null.\n");
325 DRM_DEBUG_KMS("mixer context is null.\n");
329 ctx = get_ctx_from_subdrv(subdrv);
331 ctx->hdmi_ctx = hdmi_ctx;
332 ctx->mixer_ctx = mixer_ctx;
334 ctx->hdmi_ctx->drm_dev = drm_dev;
336 ctx->mixer_ctx->drm_dev = drm_dev;
341 static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
343 struct device *dev = &pdev->dev;
344 struct exynos_drm_subdrv *subdrv;
345 struct drm_hdmi_context *ctx;
347 DRM_DEBUG_KMS("%s\n", __FILE__);
349 ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
351 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
355 subdrv = &ctx->subdrv;
358 subdrv->manager = &hdmi_manager;
359 subdrv->probe = hdmi_subdrv_probe;
361 platform_set_drvdata(pdev, subdrv);
363 exynos_drm_subdrv_register(subdrv);
368 static int hdmi_runtime_suspend(struct device *dev)
370 DRM_DEBUG_KMS("%s\n", __FILE__);
375 static int hdmi_runtime_resume(struct device *dev)
377 DRM_DEBUG_KMS("%s\n", __FILE__);
382 static const struct dev_pm_ops hdmi_pm_ops = {
383 .runtime_suspend = hdmi_runtime_suspend,
384 .runtime_resume = hdmi_runtime_resume,
387 static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
389 struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
391 DRM_DEBUG_KMS("%s\n", __FILE__);
393 exynos_drm_subdrv_unregister(&ctx->subdrv);
399 struct platform_driver exynos_drm_common_hdmi_driver = {
400 .probe = exynos_drm_hdmi_probe,
401 .remove = __devexit_p(exynos_drm_hdmi_remove),
403 .name = "exynos-drm-hdmi",
404 .owner = THIS_MODULE,