summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos/exynos_drm_crtc.c
diff options
context:
space:
mode:
authorInki Dae <inki.dae@samsung.com>2011-12-06 03:06:54 +0100
committerInki Dae <inki.dae@samsung.com>2011-12-21 07:14:17 +0100
commitec05da959acc5da8d51207060d9af672ae837321 (patch)
tree72fbc6c3d5b155877741a38441b308564d083427 /drivers/gpu/drm/exynos/exynos_drm_crtc.c
parentdrm/exynos: Use struct drm_mode_fb_cmd2 (diff)
downloadlinux-ec05da959acc5da8d51207060d9af672ae837321.tar.xz
linux-ec05da959acc5da8d51207060d9af672ae837321.zip
drm/exynos: updated crtc and encoder dpms framework.
With DPMS ON and OFF requests, crtc dpms would be in charge of just only device power such as fimd or hdmi and encoder dpms in charge of device setting(mode setting and register updating) and also lcd panel and digital TV power. Signed-off-by: Inki Dae <inki.dae@samsung.com> Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_crtc.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 7777d41d1cda..a435c3390332 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -52,11 +52,13 @@
* drm framework doesn't support multiple irq yet.
* we can refer to the crtc to current hardware interrupt occured through
* this pipe value.
+ * @dpms: store the crtc dpms value
*/
struct exynos_drm_crtc {
struct drm_crtc drm_crtc;
struct exynos_drm_overlay overlay;
unsigned int pipe;
+ unsigned int dpms;
};
static void exynos_drm_crtc_apply(struct drm_crtc *crtc)
@@ -153,26 +155,37 @@ static int exynos_drm_crtc_update(struct drm_crtc *crtc)
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
+ struct drm_device *dev = crtc->dev;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
+ if (exynos_crtc->dpms == mode) {
+ DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
+ return;
+ }
+
+ mutex_lock(&dev->struct_mutex);
+
switch (mode) {
case DRM_MODE_DPMS_ON:
- exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
- exynos_drm_encoder_crtc_commit);
+ exynos_drm_fn_encoder(crtc, &mode,
+ exynos_drm_encoder_crtc_dpms);
+ exynos_crtc->dpms = mode;
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- /* TODO */
- exynos_drm_fn_encoder(crtc, NULL,
- exynos_drm_encoder_crtc_disable);
+ exynos_drm_fn_encoder(crtc, &mode,
+ exynos_drm_encoder_crtc_dpms);
+ exynos_crtc->dpms = mode;
break;
default:
- DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+ DRM_ERROR("unspecified mode %d\n", mode);
break;
}
+
+ mutex_unlock(&dev->struct_mutex);
}
static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
@@ -188,6 +201,28 @@ static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
DRM_DEBUG_KMS("%s\n", __FILE__);
+ /*
+ * when set_crtc is requested from user or at booting time,
+ * crtc->commit would be called without dpms call so if dpms is
+ * no power on then crtc->dpms should be called
+ * with DRM_MODE_DPMS_ON for the hardware power to be on.
+ */
+ if (exynos_crtc->dpms != DRM_MODE_DPMS_ON) {
+ int mode = DRM_MODE_DPMS_ON;
+
+ /*
+ * enable hardware(power on) to all encoders hdmi connected
+ * to current crtc.
+ */
+ exynos_drm_crtc_dpms(crtc, mode);
+ /*
+ * enable dma to all encoders connected to current crtc and
+ * lcd panel.
+ */
+ exynos_drm_fn_encoder(crtc, &mode,
+ exynos_drm_encoder_dpms_from_crtc);
+ }
+
exynos_drm_fn_encoder(crtc, &exynos_crtc->pipe,
exynos_drm_encoder_crtc_commit);
}
@@ -344,6 +379,7 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
}
exynos_crtc->pipe = nr;
+ exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
crtc = &exynos_crtc->drm_crtc;
private->crtc[nr] = crtc;
@@ -357,9 +393,14 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
{
struct exynos_drm_private *private = dev->dev_private;
+ struct exynos_drm_crtc *exynos_crtc =
+ to_exynos_crtc(private->crtc[crtc]);
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
+ return -EPERM;
+
exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
exynos_drm_enable_vblank);
@@ -369,9 +410,14 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
{
struct exynos_drm_private *private = dev->dev_private;
+ struct exynos_drm_crtc *exynos_crtc =
+ to_exynos_crtc(private->crtc[crtc]);
DRM_DEBUG_KMS("%s\n", __FILE__);
+ if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
+ return;
+
exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
exynos_drm_disable_vblank);
}