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 /* platform device pointer for common drm hdmi device. */
33 static struct platform_device
*exynos_drm_hdmi_pdev
;
35 /* Common hdmi subdrv needs to access the hdmi and mixer though context.
36 * These should be initialied by the repective drivers */
37 static struct exynos_drm_hdmi_context
*hdmi_ctx
;
38 static struct exynos_drm_hdmi_context
*mixer_ctx
;
40 /* these callback points shoud be set by specific drivers. */
41 static struct exynos_hdmi_ops
*hdmi_ops
;
42 static struct exynos_mixer_ops
*mixer_ops
;
44 struct drm_hdmi_context
{
45 struct exynos_drm_subdrv subdrv
;
46 struct exynos_drm_hdmi_context
*hdmi_ctx
;
47 struct exynos_drm_hdmi_context
*mixer_ctx
;
49 bool enabled
[MIXER_WIN_NR
];
52 int exynos_platform_device_hdmi_register(void)
54 struct platform_device
*pdev
;
56 if (exynos_drm_hdmi_pdev
)
59 pdev
= platform_device_register_simple(
60 "exynos-drm-hdmi", -1, NULL
, 0);
64 exynos_drm_hdmi_pdev
= pdev
;
69 void exynos_platform_device_hdmi_unregister(void)
71 if (exynos_drm_hdmi_pdev
) {
72 platform_device_unregister(exynos_drm_hdmi_pdev
);
73 exynos_drm_hdmi_pdev
= NULL
;
77 void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context
*ctx
)
83 void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context
*ctx
)
89 void exynos_hdmi_ops_register(struct exynos_hdmi_ops
*ops
)
91 DRM_DEBUG_KMS("%s\n", __FILE__
);
97 void exynos_mixer_ops_register(struct exynos_mixer_ops
*ops
)
99 DRM_DEBUG_KMS("%s\n", __FILE__
);
105 static bool drm_hdmi_is_connected(struct device
*dev
)
107 struct drm_hdmi_context
*ctx
= to_context(dev
);
109 DRM_DEBUG_KMS("%s\n", __FILE__
);
111 if (hdmi_ops
&& hdmi_ops
->is_connected
)
112 return hdmi_ops
->is_connected(ctx
->hdmi_ctx
->ctx
);
117 static struct edid
*drm_hdmi_get_edid(struct device
*dev
,
118 struct drm_connector
*connector
)
120 struct drm_hdmi_context
*ctx
= to_context(dev
);
122 DRM_DEBUG_KMS("%s\n", __FILE__
);
124 if (hdmi_ops
&& hdmi_ops
->get_edid
)
125 return hdmi_ops
->get_edid(ctx
->hdmi_ctx
->ctx
, connector
);
130 static int drm_hdmi_check_timing(struct device
*dev
, void *timing
)
132 struct drm_hdmi_context
*ctx
= to_context(dev
);
135 DRM_DEBUG_KMS("%s\n", __FILE__
);
138 * Both, mixer and hdmi should be able to handle the requested mode.
139 * If any of the two fails, return mode as BAD.
142 if (mixer_ops
&& mixer_ops
->check_timing
)
143 ret
= mixer_ops
->check_timing(ctx
->mixer_ctx
->ctx
, timing
);
148 if (hdmi_ops
&& hdmi_ops
->check_timing
)
149 return hdmi_ops
->check_timing(ctx
->hdmi_ctx
->ctx
, timing
);
154 static int drm_hdmi_power_on(struct device
*dev
, int mode
)
156 struct drm_hdmi_context
*ctx
= to_context(dev
);
158 DRM_DEBUG_KMS("%s\n", __FILE__
);
160 if (hdmi_ops
&& hdmi_ops
->power_on
)
161 return hdmi_ops
->power_on(ctx
->hdmi_ctx
->ctx
, mode
);
166 static struct exynos_drm_display_ops drm_hdmi_display_ops
= {
167 .type
= EXYNOS_DISPLAY_TYPE_HDMI
,
168 .is_connected
= drm_hdmi_is_connected
,
169 .get_edid
= drm_hdmi_get_edid
,
170 .check_timing
= drm_hdmi_check_timing
,
171 .power_on
= drm_hdmi_power_on
,
174 static int drm_hdmi_enable_vblank(struct device
*subdrv_dev
)
176 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
177 struct exynos_drm_subdrv
*subdrv
= &ctx
->subdrv
;
178 struct exynos_drm_manager
*manager
= subdrv
->manager
;
180 DRM_DEBUG_KMS("%s\n", __FILE__
);
182 if (mixer_ops
&& mixer_ops
->enable_vblank
)
183 return mixer_ops
->enable_vblank(ctx
->mixer_ctx
->ctx
,
189 static void drm_hdmi_disable_vblank(struct device
*subdrv_dev
)
191 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
193 DRM_DEBUG_KMS("%s\n", __FILE__
);
195 if (mixer_ops
&& mixer_ops
->disable_vblank
)
196 return mixer_ops
->disable_vblank(ctx
->mixer_ctx
->ctx
);
199 static void drm_hdmi_wait_for_vblank(struct device
*subdrv_dev
)
201 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
203 DRM_DEBUG_KMS("%s\n", __FILE__
);
205 if (mixer_ops
&& mixer_ops
->wait_for_vblank
)
206 mixer_ops
->wait_for_vblank(ctx
->mixer_ctx
->ctx
);
209 static void drm_hdmi_mode_fixup(struct device
*subdrv_dev
,
210 struct drm_connector
*connector
,
211 const struct drm_display_mode
*mode
,
212 struct drm_display_mode
*adjusted_mode
)
214 struct drm_display_mode
*m
;
217 DRM_DEBUG_KMS("%s\n", __FILE__
);
219 drm_mode_set_crtcinfo(adjusted_mode
, 0);
221 mode_ok
= drm_hdmi_check_timing(subdrv_dev
, adjusted_mode
);
223 /* just return if user desired mode exists. */
228 * otherwise, find the most suitable mode among modes and change it
231 list_for_each_entry(m
, &connector
->modes
, head
) {
232 mode_ok
= drm_hdmi_check_timing(subdrv_dev
, m
);
235 struct drm_mode_object base
;
236 struct list_head head
;
238 DRM_INFO("desired mode doesn't exist so\n");
239 DRM_INFO("use the most suitable mode among modes.\n");
241 DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
242 m
->hdisplay
, m
->vdisplay
, m
->vrefresh
);
244 /* preserve display mode header while copying. */
245 head
= adjusted_mode
->head
;
246 base
= adjusted_mode
->base
;
247 memcpy(adjusted_mode
, m
, sizeof(*m
));
248 adjusted_mode
->head
= head
;
249 adjusted_mode
->base
= base
;
255 static void drm_hdmi_mode_set(struct device
*subdrv_dev
, void *mode
)
257 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
259 DRM_DEBUG_KMS("%s\n", __FILE__
);
261 if (hdmi_ops
&& hdmi_ops
->mode_set
)
262 hdmi_ops
->mode_set(ctx
->hdmi_ctx
->ctx
, mode
);
265 static void drm_hdmi_get_max_resol(struct device
*subdrv_dev
,
266 unsigned int *width
, unsigned int *height
)
268 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
270 DRM_DEBUG_KMS("%s\n", __FILE__
);
272 if (hdmi_ops
&& hdmi_ops
->get_max_resol
)
273 hdmi_ops
->get_max_resol(ctx
->hdmi_ctx
->ctx
, width
, height
);
276 static void drm_hdmi_commit(struct device
*subdrv_dev
)
278 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
280 DRM_DEBUG_KMS("%s\n", __FILE__
);
282 if (hdmi_ops
&& hdmi_ops
->commit
)
283 hdmi_ops
->commit(ctx
->hdmi_ctx
->ctx
);
286 static void drm_hdmi_dpms(struct device
*subdrv_dev
, int mode
)
288 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
290 DRM_DEBUG_KMS("%s\n", __FILE__
);
292 if (mixer_ops
&& mixer_ops
->dpms
)
293 mixer_ops
->dpms(ctx
->mixer_ctx
->ctx
, mode
);
295 if (hdmi_ops
&& hdmi_ops
->dpms
)
296 hdmi_ops
->dpms(ctx
->hdmi_ctx
->ctx
, mode
);
299 static void drm_hdmi_apply(struct device
*subdrv_dev
)
301 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
304 DRM_DEBUG_KMS("%s\n", __FILE__
);
306 for (i
= 0; i
< MIXER_WIN_NR
; i
++) {
307 if (!ctx
->enabled
[i
])
309 if (mixer_ops
&& mixer_ops
->win_commit
)
310 mixer_ops
->win_commit(ctx
->mixer_ctx
->ctx
, i
);
313 if (hdmi_ops
&& hdmi_ops
->commit
)
314 hdmi_ops
->commit(ctx
->hdmi_ctx
->ctx
);
317 static struct exynos_drm_manager_ops drm_hdmi_manager_ops
= {
318 .dpms
= drm_hdmi_dpms
,
319 .apply
= drm_hdmi_apply
,
320 .enable_vblank
= drm_hdmi_enable_vblank
,
321 .disable_vblank
= drm_hdmi_disable_vblank
,
322 .wait_for_vblank
= drm_hdmi_wait_for_vblank
,
323 .mode_fixup
= drm_hdmi_mode_fixup
,
324 .mode_set
= drm_hdmi_mode_set
,
325 .get_max_resol
= drm_hdmi_get_max_resol
,
326 .commit
= drm_hdmi_commit
,
329 static void drm_mixer_mode_set(struct device
*subdrv_dev
,
330 struct exynos_drm_overlay
*overlay
)
332 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
334 DRM_DEBUG_KMS("%s\n", __FILE__
);
336 if (mixer_ops
&& mixer_ops
->win_mode_set
)
337 mixer_ops
->win_mode_set(ctx
->mixer_ctx
->ctx
, overlay
);
340 static void drm_mixer_commit(struct device
*subdrv_dev
, int zpos
)
342 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
343 int win
= (zpos
== DEFAULT_ZPOS
) ? MIXER_DEFAULT_WIN
: zpos
;
345 DRM_DEBUG_KMS("%s\n", __FILE__
);
347 if (win
< 0 || win
> MIXER_WIN_NR
) {
348 DRM_ERROR("mixer window[%d] is wrong\n", win
);
352 if (mixer_ops
&& mixer_ops
->win_commit
)
353 mixer_ops
->win_commit(ctx
->mixer_ctx
->ctx
, win
);
355 ctx
->enabled
[win
] = true;
358 static void drm_mixer_disable(struct device
*subdrv_dev
, int zpos
)
360 struct drm_hdmi_context
*ctx
= to_context(subdrv_dev
);
361 int win
= (zpos
== DEFAULT_ZPOS
) ? MIXER_DEFAULT_WIN
: zpos
;
363 DRM_DEBUG_KMS("%s\n", __FILE__
);
365 if (win
< 0 || win
> MIXER_WIN_NR
) {
366 DRM_ERROR("mixer window[%d] is wrong\n", win
);
370 if (mixer_ops
&& mixer_ops
->win_disable
)
371 mixer_ops
->win_disable(ctx
->mixer_ctx
->ctx
, win
);
373 ctx
->enabled
[win
] = false;
376 static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops
= {
377 .mode_set
= drm_mixer_mode_set
,
378 .commit
= drm_mixer_commit
,
379 .disable
= drm_mixer_disable
,
382 static struct exynos_drm_manager hdmi_manager
= {
384 .ops
= &drm_hdmi_manager_ops
,
385 .overlay_ops
= &drm_hdmi_overlay_ops
,
386 .display_ops
= &drm_hdmi_display_ops
,
389 static int hdmi_subdrv_probe(struct drm_device
*drm_dev
,
392 struct exynos_drm_subdrv
*subdrv
= to_subdrv(dev
);
393 struct drm_hdmi_context
*ctx
;
395 DRM_DEBUG_KMS("%s\n", __FILE__
);
398 DRM_ERROR("hdmi context not initialized.\n");
403 DRM_ERROR("mixer context not initialized.\n");
407 ctx
= get_ctx_from_subdrv(subdrv
);
410 DRM_ERROR("no drm hdmi context.\n");
414 ctx
->hdmi_ctx
= hdmi_ctx
;
415 ctx
->mixer_ctx
= mixer_ctx
;
417 ctx
->hdmi_ctx
->drm_dev
= drm_dev
;
418 ctx
->mixer_ctx
->drm_dev
= drm_dev
;
420 if (mixer_ops
->iommu_on
)
421 mixer_ops
->iommu_on(ctx
->mixer_ctx
->ctx
, true);
426 static void hdmi_subdrv_remove(struct drm_device
*drm_dev
, struct device
*dev
)
428 struct drm_hdmi_context
*ctx
;
429 struct exynos_drm_subdrv
*subdrv
= to_subdrv(dev
);
431 ctx
= get_ctx_from_subdrv(subdrv
);
433 if (mixer_ops
->iommu_on
)
434 mixer_ops
->iommu_on(ctx
->mixer_ctx
->ctx
, false);
437 static int exynos_drm_hdmi_probe(struct platform_device
*pdev
)
439 struct device
*dev
= &pdev
->dev
;
440 struct exynos_drm_subdrv
*subdrv
;
441 struct drm_hdmi_context
*ctx
;
443 DRM_DEBUG_KMS("%s\n", __FILE__
);
445 ctx
= devm_kzalloc(dev
, sizeof(*ctx
), GFP_KERNEL
);
447 DRM_LOG_KMS("failed to alloc common hdmi context.\n");
451 subdrv
= &ctx
->subdrv
;
454 subdrv
->manager
= &hdmi_manager
;
455 subdrv
->probe
= hdmi_subdrv_probe
;
456 subdrv
->remove
= hdmi_subdrv_remove
;
458 platform_set_drvdata(pdev
, subdrv
);
460 exynos_drm_subdrv_register(subdrv
);
465 static int exynos_drm_hdmi_remove(struct platform_device
*pdev
)
467 struct drm_hdmi_context
*ctx
= platform_get_drvdata(pdev
);
469 DRM_DEBUG_KMS("%s\n", __FILE__
);
471 exynos_drm_subdrv_unregister(&ctx
->subdrv
);
476 struct platform_driver exynos_drm_common_hdmi_driver
= {
477 .probe
= exynos_drm_hdmi_probe
,
478 .remove
= exynos_drm_hdmi_remove
,
480 .name
= "exynos-drm-hdmi",
481 .owner
= THIS_MODULE
,