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_fixup(struct device
*subdrv_dev
,
159 struct drm_connector
*connector
,
160 struct drm_display_mode
*mode
,
161 struct drm_display_mode
*adjusted_mode
)
163 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
165 DRM_DEBUG_KMS("%s\n", __FILE__
);
167 if (hdmi_manager_ops
&& hdmi_manager_ops
->mode_fixup
)
168 hdmi_manager_ops
->mode_fixup(ctx
->hdmi_ctx
->ctx
, connector
,
169 mode
, adjusted_mode
);
172 static void drm_hdmi_mode_set(struct device
*subdrv_dev
, void *mode
)
174 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
176 DRM_DEBUG_KMS("%s\n", __FILE__
);
178 if (hdmi_manager_ops
&& hdmi_manager_ops
->mode_set
)
179 hdmi_manager_ops
->mode_set(ctx
->hdmi_ctx
->ctx
, mode
);
182 static void drm_hdmi_get_max_resol(struct device
*subdrv_dev
,
183 unsigned int *width
, unsigned int *height
)
185 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
187 DRM_DEBUG_KMS("%s\n", __FILE__
);
189 if (hdmi_manager_ops
&& hdmi_manager_ops
->get_max_resol
)
190 hdmi_manager_ops
->get_max_resol(ctx
->hdmi_ctx
->ctx
, width
,
194 static void drm_hdmi_commit(struct device
*subdrv_dev
)
196 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
198 DRM_DEBUG_KMS("%s\n", __FILE__
);
200 if (hdmi_manager_ops
&& hdmi_manager_ops
->commit
)
201 hdmi_manager_ops
->commit(ctx
->hdmi_ctx
->ctx
);
204 static void drm_hdmi_dpms(struct device
*subdrv_dev
, int mode
)
206 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
208 DRM_DEBUG_KMS("%s\n", __FILE__
);
211 case DRM_MODE_DPMS_ON
:
213 case DRM_MODE_DPMS_STANDBY
:
214 case DRM_MODE_DPMS_SUSPEND
:
215 case DRM_MODE_DPMS_OFF
:
216 if (hdmi_manager_ops
&& hdmi_manager_ops
->disable
)
217 hdmi_manager_ops
->disable(ctx
->hdmi_ctx
->ctx
);
220 DRM_DEBUG_KMS("unkown dps mode: %d\n", mode
);
225 static struct exynos_drm_manager_ops drm_hdmi_manager_ops
= {
226 .dpms
= drm_hdmi_dpms
,
227 .enable_vblank
= drm_hdmi_enable_vblank
,
228 .disable_vblank
= drm_hdmi_disable_vblank
,
229 .mode_fixup
= drm_hdmi_mode_fixup
,
230 .mode_set
= drm_hdmi_mode_set
,
231 .get_max_resol
= drm_hdmi_get_max_resol
,
232 .commit
= drm_hdmi_commit
,
235 static void drm_mixer_mode_set(struct device
*subdrv_dev
,
236 struct exynos_drm_overlay
*overlay
)
238 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
240 DRM_DEBUG_KMS("%s\n", __FILE__
);
242 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_mode_set
)
243 hdmi_overlay_ops
->win_mode_set(ctx
->mixer_ctx
->ctx
, overlay
);
246 static void drm_mixer_commit(struct device
*subdrv_dev
, int zpos
)
248 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
250 DRM_DEBUG_KMS("%s\n", __FILE__
);
252 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_commit
)
253 hdmi_overlay_ops
->win_commit(ctx
->mixer_ctx
->ctx
, zpos
);
256 static void drm_mixer_disable(struct device
*subdrv_dev
, int zpos
)
258 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
260 DRM_DEBUG_KMS("%s\n", __FILE__
);
262 if (hdmi_overlay_ops
&& hdmi_overlay_ops
->win_disable
)
263 hdmi_overlay_ops
->win_disable(ctx
->mixer_ctx
->ctx
, zpos
);
266 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops
= {
267 .mode_set
= drm_mixer_mode_set
,
268 .commit
= drm_mixer_commit
,
269 .disable
= drm_mixer_disable
,
273 static int hdmi_subdrv_probe(struct drm_device
*drm_dev
,
276 struct exynos_drm_subdrv
*subdrv
= to_subdrv(dev
);
277 struct drm_hdmi_context
*ctx
;
278 struct platform_device
*pdev
= to_platform_device(dev
);
279 struct exynos_drm_common_hdmi_pd
*pd
;
282 DRM_DEBUG_KMS("%s\n", __FILE__
);
284 pd
= pdev
->dev
.platform_data
;
287 DRM_DEBUG_KMS("platform data is null.\n");
292 DRM_DEBUG_KMS("hdmi device is null.\n");
296 if (!pd
->mixer_dev
) {
297 DRM_DEBUG_KMS("mixer device is null.\n");
301 ret
= platform_driver_register(&hdmi_driver
);
303 DRM_DEBUG_KMS("failed to register hdmi driver.\n");
307 ret
= platform_driver_register(&mixer_driver
);
309 DRM_DEBUG_KMS("failed to register mixer driver.\n");
313 ctx
= get_ctx_from_subdrv(subdrv
);
315 ctx
->hdmi_ctx
= (struct exynos_drm_hdmi_context
*)
316 to_context(pd
->hdmi_dev
);
317 if (!ctx
->hdmi_ctx
) {
318 DRM_DEBUG_KMS("hdmi context is null.\n");
323 ctx
->hdmi_ctx
->drm_dev
= drm_dev
;
325 ctx
->mixer_ctx
= (struct exynos_drm_hdmi_context
*)
326 to_context(pd
->mixer_dev
);
327 if (!ctx
->mixer_ctx
) {
328 DRM_DEBUG_KMS("mixer context is null.\n");
333 ctx
->mixer_ctx
->drm_dev
= drm_dev
;
338 platform_driver_unregister(&mixer_driver
);
340 platform_driver_unregister(&hdmi_driver
);
344 static void hdmi_subdrv_remove(struct drm_device
*drm_dev
)
346 DRM_DEBUG_KMS("%s\n", __FILE__
);
348 platform_driver_unregister(&hdmi_driver
);
349 platform_driver_unregister(&mixer_driver
);
352 static void exynos_drm_hdmi_late_probe(struct work_struct
*work
)
354 struct drm_hdmi_context
*ctx
= container_of(work
,
355 struct drm_hdmi_context
, work
);
358 * this function calls subdrv->probe() so this must be called
359 * after probe context.
361 * PS. subdrv->probe() will call platform_driver_register() to probe
362 * hdmi and mixer driver.
364 exynos_drm_subdrv_register(&ctx
->subdrv
);
367 static int __devinit
exynos_drm_hdmi_probe(struct platform_device
*pdev
)
369 struct device
*dev
= &pdev
->dev
;
370 struct exynos_drm_subdrv
*subdrv
;
371 struct drm_hdmi_context
*ctx
;
373 DRM_DEBUG_KMS("%s\n", __FILE__
);
375 ctx
= kzalloc(sizeof(*ctx
), GFP_KERNEL
);
377 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
381 subdrv
= &ctx
->subdrv
;
383 subdrv
->probe
= hdmi_subdrv_probe
;
384 subdrv
->remove
= hdmi_subdrv_remove
;
385 subdrv
->manager
.pipe
= -1;
386 subdrv
->manager
.ops
= &drm_hdmi_manager_ops
;
387 subdrv
->manager
.overlay_ops
= &drm_hdmi_overlay_ops
;
388 subdrv
->manager
.display_ops
= &drm_hdmi_display_ops
;
389 subdrv
->manager
.dev
= dev
;
391 platform_set_drvdata(pdev
, subdrv
);
393 INIT_WORK(&ctx
->work
, exynos_drm_hdmi_late_probe
);
395 schedule_work(&ctx
->work
);
400 static int hdmi_runtime_suspend(struct device
*dev
)
402 DRM_DEBUG_KMS("%s\n", __FILE__
);
407 static int hdmi_runtime_resume(struct device
*dev
)
409 DRM_DEBUG_KMS("%s\n", __FILE__
);
414 static const struct dev_pm_ops hdmi_pm_ops
= {
415 .runtime_suspend
= hdmi_runtime_suspend
,
416 .runtime_resume
= hdmi_runtime_resume
,
419 static int __devexit
exynos_drm_hdmi_remove(struct platform_device
*pdev
)
421 struct drm_hdmi_context
*ctx
= platform_get_drvdata(pdev
);
423 DRM_DEBUG_KMS("%s\n", __FILE__
);
425 exynos_drm_subdrv_unregister(&ctx
->subdrv
);
431 static struct platform_driver exynos_drm_common_hdmi_driver
= {
432 .probe
= exynos_drm_hdmi_probe
,
433 .remove
= __devexit_p(exynos_drm_hdmi_remove
),
435 .name
= "exynos-drm-hdmi",
436 .owner
= THIS_MODULE
,
441 static int __init
exynos_drm_hdmi_init(void)
445 DRM_DEBUG_KMS("%s\n", __FILE__
);
447 ret
= platform_driver_register(&exynos_drm_common_hdmi_driver
);
449 DRM_DEBUG_KMS("failed to register hdmi common driver.\n");
456 static void __exit
exynos_drm_hdmi_exit(void)
458 platform_driver_unregister(&exynos_drm_common_hdmi_driver
);
461 module_init(exynos_drm_hdmi_init
);
462 module_exit(exynos_drm_hdmi_exit
);
464 MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
465 MODULE_AUTHOR("Seung-Woo Kim, <sw0312.kim@samsung.com>");
466 MODULE_DESCRIPTION("Samsung SoC DRM HDMI Driver");
467 MODULE_LICENSE("GPL");