Skip to content

Commit

Permalink
drm/exynos: add dpms for hdmi
Browse files Browse the repository at this point in the history
The power and clocks turns on always in exynos hdmi and mixer driver,
but we should turn off the power and clocks of exynos hdmi and mixer
when the hdmi cable unplugged or when hdmi unused.

There are two interrupt to detect hotplug of hdmi cable - internal
interrupt and external interrupt. The internal interrupt can use only
when hdmi is dpms on so if hdmi is dpms off, we should use external
interrupt to detect hotplug of hdmi cable. If hdmi is dpms on, we cannot
external interrupt because the gpio pin for external interrupt is used
to hdmi HPD pin for internal interrupt.

Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
  • Loading branch information
Joonyoung Shim authored and Inki Dae committed May 8, 2012
1 parent 66265a2 commit cf8fc4f
Show file tree
Hide file tree
Showing 4 changed files with 341 additions and 306 deletions.
77 changes: 43 additions & 34 deletions drivers/gpu/drm/exynos/exynos_drm_hdmi.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ struct drm_hdmi_context {
struct exynos_drm_subdrv subdrv;
struct exynos_drm_hdmi_context *hdmi_ctx;
struct exynos_drm_hdmi_context *mixer_ctx;

bool enabled[MIXER_WIN_NR];
};

void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
Expand Down Expand Up @@ -189,23 +191,34 @@ static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)

DRM_DEBUG_KMS("%s\n", __FILE__);

switch (mode) {
case DRM_MODE_DPMS_ON:
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
if (hdmi_ops && hdmi_ops->disable)
hdmi_ops->disable(ctx->hdmi_ctx->ctx);
break;
default:
DRM_DEBUG_KMS("unkown dps mode: %d\n", mode);
break;
if (mixer_ops && mixer_ops->dpms)
mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);

if (hdmi_ops && hdmi_ops->dpms)
hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
}

static void drm_hdmi_apply(struct device *subdrv_dev)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int i;

DRM_DEBUG_KMS("%s\n", __FILE__);

for (i = 0; i < MIXER_WIN_NR; i++) {
if (!ctx->enabled[i])
continue;
if (mixer_ops && mixer_ops->win_commit)
mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
}

if (hdmi_ops && hdmi_ops->commit)
hdmi_ops->commit(ctx->hdmi_ctx->ctx);
}

static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
.dpms = drm_hdmi_dpms,
.apply = drm_hdmi_apply,
.enable_vblank = drm_hdmi_enable_vblank,
.disable_vblank = drm_hdmi_disable_vblank,
.mode_fixup = drm_hdmi_mode_fixup,
Expand All @@ -228,21 +241,37 @@ static void drm_mixer_mode_set(struct device *subdrv_dev,
static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;

DRM_DEBUG_KMS("%s\n", __FILE__);

if (win < 0 || win > MIXER_WIN_NR) {
DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}

if (mixer_ops && mixer_ops->win_commit)
mixer_ops->win_commit(ctx->mixer_ctx->ctx, zpos);
mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);

ctx->enabled[win] = true;
}

static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
{
struct drm_hdmi_context *ctx = to_context(subdrv_dev);
int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;

DRM_DEBUG_KMS("%s\n", __FILE__);

if (win < 0 || win > MIXER_WIN_NR) {
DRM_ERROR("mixer window[%d] is wrong\n", win);
return;
}

if (mixer_ops && mixer_ops->win_disable)
mixer_ops->win_disable(ctx->mixer_ctx->ctx, zpos);
mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);

ctx->enabled[win] = false;
}

static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
Expand Down Expand Up @@ -335,25 +364,6 @@ static int __devinit exynos_drm_hdmi_probe(struct platform_device *pdev)
return 0;
}

static int hdmi_runtime_suspend(struct device *dev)
{
DRM_DEBUG_KMS("%s\n", __FILE__);

return 0;
}

static int hdmi_runtime_resume(struct device *dev)
{
DRM_DEBUG_KMS("%s\n", __FILE__);

return 0;
}

static const struct dev_pm_ops hdmi_pm_ops = {
.runtime_suspend = hdmi_runtime_suspend,
.runtime_resume = hdmi_runtime_resume,
};

static int __devexit exynos_drm_hdmi_remove(struct platform_device *pdev)
{
struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
Expand All @@ -372,6 +382,5 @@ struct platform_driver exynos_drm_common_hdmi_driver = {
.driver = {
.name = "exynos-drm-hdmi",
.owner = THIS_MODULE,
.pm = &hdmi_pm_ops,
},
};
6 changes: 5 additions & 1 deletion drivers/gpu/drm/exynos/exynos_drm_hdmi.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
#ifndef _EXYNOS_DRM_HDMI_H_
#define _EXYNOS_DRM_HDMI_H_

#define MIXER_WIN_NR 3
#define MIXER_DEFAULT_WIN 0

/*
* exynos hdmi common context structure.
*
Expand Down Expand Up @@ -54,13 +57,14 @@ struct exynos_hdmi_ops {
void (*get_max_resol)(void *ctx, unsigned int *width,
unsigned int *height);
void (*commit)(void *ctx);
void (*disable)(void *ctx);
void (*dpms)(void *ctx, int mode);
};

struct exynos_mixer_ops {
/* manager */
int (*enable_vblank)(void *ctx, int pipe);
void (*disable_vblank)(void *ctx);
void (*dpms)(void *ctx, int mode);

/* overlay */
void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
Expand Down
Loading

0 comments on commit cf8fc4f

Please sign in to comment.