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 /* these callback points shoud be set by specific drivers. */
33 static struct exynos_hdmi_display_ops
*hdmi_display_ops
;
34 static struct exynos_hdmi_manager_ops
*hdmi_manager_ops
;
35 static struct exynos_hdmi_overlay_ops
*hdmi_overlay_ops
;
37 struct drm_hdmi_context
{
38 struct exynos_drm_subdrv subdrv
;
39 struct exynos_drm_hdmi_context
*hdmi_ctx
;
40 struct exynos_drm_hdmi_context
*mixer_ctx
;
41 struct work_struct work
;
44 void exynos_drm_display_ops_register(struct exynos_hdmi_display_ops
47 DRM_DEBUG_KMS("%s\n", __FILE__
);
50 hdmi_display_ops
= display_ops
;
52 EXPORT_SYMBOL(exynos_drm_display_ops_register
);
54 void exynos_drm_manager_ops_register(struct exynos_hdmi_manager_ops
57 DRM_DEBUG_KMS("%s\n", __FILE__
);
60 hdmi_manager_ops
= manager_ops
;
62 EXPORT_SYMBOL(exynos_drm_manager_ops_register
);
64 void exynos_drm_overlay_ops_register(struct exynos_hdmi_overlay_ops
67 DRM_DEBUG_KMS("%s\n", __FILE__
);
70 hdmi_overlay_ops
= overlay_ops
;
72 EXPORT_SYMBOL(exynos_drm_overlay_ops_register
);
74 static bool drm_hdmi_is_connected(struct device
*dev
)
76 struct drm_hdmi_context
*ctx
= to_context(dev
);
78 DRM_DEBUG_KMS("%s\n", __FILE__
);
80 if (hdmi_display_ops
&& hdmi_display_ops
->is_connected
)
81 return hdmi_display_ops
->is_connected(ctx
->hdmi_ctx
->ctx
);
86 static int drm_hdmi_get_edid(struct device
*dev
,
87 struct drm_connector
*connector
, u8
*edid
, int len
)
89 struct drm_hdmi_context
*ctx
= to_context(dev
);
91 DRM_DEBUG_KMS("%s\n", __FILE__
);
93 if (hdmi_display_ops
&& hdmi_display_ops
->get_edid
)
94 return hdmi_display_ops
->get_edid(ctx
->hdmi_ctx
->ctx
,
95 connector
, edid
, len
);
100 static int drm_hdmi_check_timing(struct device
*dev
, void *timing
)
102 struct drm_hdmi_context
*ctx
= to_context(dev
);
104 DRM_DEBUG_KMS("%s\n", __FILE__
);
106 if (hdmi_display_ops
&& hdmi_display_ops
->check_timing
)
107 return hdmi_display_ops
->check_timing(ctx
->hdmi_ctx
->ctx
,
113 static int drm_hdmi_power_on(struct device
*dev
, int mode
)
115 struct drm_hdmi_context
*ctx
= to_context(dev
);
117 DRM_DEBUG_KMS("%s\n", __FILE__
);
119 if (hdmi_display_ops
&& hdmi_display_ops
->power_on
)
120 return hdmi_display_ops
->power_on(ctx
->hdmi_ctx
->ctx
, mode
);
125 static struct exynos_drm_display_ops drm_hdmi_display_ops
= {
126 .type
= EXYNOS_DISPLAY_TYPE_HDMI
,
127 .is_connected
= drm_hdmi_is_connected
,
128 .get_edid
= drm_hdmi_get_edid
,
129 .check_timing
= drm_hdmi_check_timing
,
130 .power_on
= drm_hdmi_power_on
,
133 static int drm_hdmi_enable_vblank(struct device
*subdrv_dev
)
135 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
136 struct exynos_drm_subdrv
*subdrv
= &ctx
->subdrv
;
137 struct exynos_drm_manager
*manager
= &subdrv
->manager
;
139 DRM_DEBUG_KMS("%s\n", __FILE__
);
141 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->enable_vblank
)
142 return hdmi_overlay_ops
->enable_vblank(ctx
->mixer_ctx
->ctx
,
148 static void drm_hdmi_disable_vblank(struct device
*subdrv_dev
)
150 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
152 DRM_DEBUG_KMS("%s\n", __FILE__
);
154 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->disable_vblank
)
155 return hdmi_overlay_ops
->disable_vblank(ctx
->mixer_ctx
->ctx
);
158 static void drm_hdmi_mode_set(struct device
*subdrv_dev
, void *mode
)
160 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
162 DRM_DEBUG_KMS("%s\n", __FILE__
);
164 if (hdmi_manager_ops
&& hdmi_manager_ops
->mode_set
)
165 hdmi_manager_ops
->mode_set(ctx
->hdmi_ctx
->ctx
, mode
);
168 static void drm_hdmi_commit(struct device
*subdrv_dev
)
170 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
172 DRM_DEBUG_KMS("%s\n", __FILE__
);
174 if (hdmi_manager_ops
&& hdmi_manager_ops
->commit
)
175 hdmi_manager_ops
->commit(ctx
->hdmi_ctx
->ctx
);
178 static void drm_hdmi_dpms(struct device
*subdrv_dev
, int mode
)
180 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
182 DRM_DEBUG_KMS("%s\n", __FILE__
);
185 case DRM_MODE_DPMS_ON
:
187 case DRM_MODE_DPMS_STANDBY
:
188 case DRM_MODE_DPMS_SUSPEND
:
189 case DRM_MODE_DPMS_OFF
:
190 if (hdmi_manager_ops
&& hdmi_manager_ops
->disable
)
191 hdmi_manager_ops
->disable(ctx
->hdmi_ctx
->ctx
);
194 DRM_DEBUG_KMS("unkown dps mode: %d\n", mode
);
199 static struct exynos_drm_manager_ops drm_hdmi_manager_ops
= {
200 .dpms
= drm_hdmi_dpms
,
201 .enable_vblank
= drm_hdmi_enable_vblank
,
202 .disable_vblank
= drm_hdmi_disable_vblank
,
203 .mode_set
= drm_hdmi_mode_set
,
204 .commit
= drm_hdmi_commit
,
207 static void drm_mixer_mode_set(struct device
*subdrv_dev
,
208 struct exynos_drm_overlay
*overlay
)
210 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
212 DRM_DEBUG_KMS("%s\n", __FILE__
);
214 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_mode_set
)
215 hdmi_overlay_ops
->win_mode_set(ctx
->mixer_ctx
->ctx
, overlay
);
218 static void drm_mixer_commit(struct device
*subdrv_dev
, int zpos
)
220 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
222 DRM_DEBUG_KMS("%s\n", __FILE__
);
224 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_commit
)
225 hdmi_overlay_ops
->win_commit(ctx
->mixer_ctx
->ctx
, zpos
);
228 static void drm_mixer_disable(struct device
*subdrv_dev
, int zpos
)
230 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
232 DRM_DEBUG_KMS("%s\n", __FILE__
);
234 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_disable
)
235 hdmi_overlay_ops
->win_disable(ctx
->mixer_ctx
->ctx
, zpos
);
238 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops
= {
239 .mode_set
= drm_mixer_mode_set
,
240 .commit
= drm_mixer_commit
,
241 .disable
= drm_mixer_disable
,
245 static int hdmi_subdrv_probe(struct drm_device
*drm_dev
,
248 struct exynos_drm_subdrv
*subdrv
= to_subdrv(dev
);
249 struct drm_hdmi_context
*ctx
;
250 struct platform_device
*pdev
= to_platform_device(dev
);
251 struct exynos_drm_common_hdmi_pd
*pd
;
254 DRM_DEBUG_KMS("%s\n", __FILE__
);
256 pd
= pdev
->dev
.platform_data
;
259 DRM_DEBUG_KMS("platform data is null.\n");
264 DRM_DEBUG_KMS("hdmi device is null.\n");
268 if (!pd
->mixer_dev
) {
269 DRM_DEBUG_KMS("mixer device is null.\n");
273 ret
= platform_driver_register(&hdmi_driver
);
275 DRM_DEBUG_KMS("failed to register hdmi driver.\n");
279 ret
= platform_driver_register(&mixer_driver
);
281 DRM_DEBUG_KMS("failed to register mixer driver.\n");
285 ctx
= get_ctx_from_subdrv(subdrv
);
287 ctx
->hdmi_ctx
= (struct exynos_drm_hdmi_context
*)
288 to_context(pd
->hdmi_dev
);
289 if (!ctx
->hdmi_ctx
) {
290 DRM_DEBUG_KMS("hdmi context is null.\n");
295 ctx
->hdmi_ctx
->drm_dev
= drm_dev
;
297 ctx
->mixer_ctx
= (struct exynos_drm_hdmi_context
*)
298 to_context(pd
->mixer_dev
);
299 if (!ctx
->mixer_ctx
) {
300 DRM_DEBUG_KMS("mixer context is null.\n");
305 ctx
->mixer_ctx
->drm_dev
= drm_dev
;
310 platform_driver_unregister(&mixer_driver
);
312 platform_driver_unregister(&hdmi_driver
);
316 static void hdmi_subdrv_remove(struct drm_device
*drm_dev
)
318 DRM_DEBUG_KMS("%s\n", __FILE__
);
320 platform_driver_unregister(&hdmi_driver
);
321 platform_driver_unregister(&mixer_driver
);
324 static void exynos_drm_hdmi_late_probe(struct work_struct
*work
)
326 struct drm_hdmi_context
*ctx
= container_of(work
,
327 struct drm_hdmi_context
, work
);
330 * this function calls subdrv->probe() so this must be called
331 * after probe context.
333 * PS. subdrv->probe() will call platform_driver_register() to probe
334 * hdmi and mixer driver.
336 exynos_drm_subdrv_register(&ctx
->subdrv
);
339 static int __devinit
exynos_drm_hdmi_probe(struct platform_device
*pdev
)
341 struct device
*dev
= &pdev
->dev
;
342 struct exynos_drm_subdrv
*subdrv
;
343 struct drm_hdmi_context
*ctx
;
345 DRM_DEBUG_KMS("%s\n", __FILE__
);
347 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
349 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
353 subdrv
= &ctx
->subdrv
;
355 subdrv
->probe
= hdmi_subdrv_probe
;
356 subdrv
->remove
= hdmi_subdrv_remove
;
357 subdrv
->manager
.pipe
= -1;
358 subdrv
->manager
.ops
= &drm_hdmi_manager_ops
;
359 subdrv
->manager
.overlay_ops
= &drm_hdmi_overlay_ops
;
360 subdrv
->manager
.display_ops
= &drm_hdmi_display_ops
;
361 subdrv
->manager
.dev
= dev
;
363 platform_set_drvdata(pdev
, subdrv
);
365 INIT_WORK(&ctx
->work
, exynos_drm_hdmi_late_probe
);
367 schedule_work(&ctx
->work
);
372 static int hdmi_runtime_suspend(struct device
*dev
)
374 DRM_DEBUG_KMS("%s\n", __FILE__
);
379 static int hdmi_runtime_resume(struct device
*dev
)
381 DRM_DEBUG_KMS("%s\n", __FILE__
);
386 static const struct dev_pm_ops hdmi_pm_ops
= {
387 .runtime_suspend
= hdmi_runtime_suspend
,
388 .runtime_resume
= hdmi_runtime_resume
,
391 static int __devexit
exynos_drm_hdmi_remove(struct platform_device
*pdev
)
393 struct drm_hdmi_context
*ctx
= platform_get_drvdata(pdev
);
395 DRM_DEBUG_KMS("%s\n", __FILE__
);
397 exynos_drm_subdrv_unregister(&ctx
->subdrv
);
403 static struct platform_driver exynos_drm_common_hdmi_driver
= {
404 .probe
= exynos_drm_hdmi_probe
,
405 .remove
= __devexit_p(exynos_drm_hdmi_remove
),
407 .name
= "exynos-drm-hdmi",
408 .owner
= THIS_MODULE
,
413 static int __init
exynos_drm_hdmi_init(void)
417 DRM_DEBUG_KMS("%s\n", __FILE__
);
419 ret
= platform_driver_register(&exynos_drm_common_hdmi_driver
);
421 DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
428 static void __exit
exynos_drm_hdmi_exit(void)
430 platform_driver_unregister(&exynos_drm_common_hdmi_driver
);
433 module_init(exynos_drm_hdmi_init
);
434 module_exit(exynos_drm_hdmi_exit
);
436 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
437 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
438 MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
439 MODULE_LICENSE("GPL");