gfx: display: add Android early suspend support
authorJani Nikula <jani.nikula@intel.com>
Fri, 9 Dec 2011 13:14:21 +0000 (15:14 +0200)
committerMarkus Lehtonen <markus.lehtonen@linux.intel.com>
Tue, 3 Jul 2012 09:28:49 +0000 (12:28 +0300)
Use early suspend to switch display off, and late resume to switch display
on. Use runtime PM to automatically handle enabling and disabling hardware.

Signed-off-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
drivers/staging/mrst/drv/psb_drv.h
drivers/staging/mrst/drv/psb_powermgmt.c

index e4c304b..ab0ba97 100644 (file)
 #include "ttm/ttm_lock.h"
 #include "psb_irq.h"
 
+#ifdef CONFIG_EARLYSUSPEND
+#include <linux/earlysuspend.h>
+#endif
+
 /*IMG headers*/
 #include "private_data.h"
 #include "pvr_drm.h"
@@ -682,6 +686,10 @@ struct drm_psb_private {
        struct mdfld_dsi_dbi_output * dbi_output2;
 /* MDFLD_DSI private date end */
 
+#ifdef CONFIG_EARLYSUSPEND
+       struct early_suspend early_suspend;
+#endif
+
        /*
         *Register state
         */
index 31f8082..b60fcf0 100644 (file)
@@ -346,6 +346,60 @@ out:
        return;
 }
 #endif
+
+#ifdef CONFIG_EARLYSUSPEND
+/*
+ * REVISIT: The early suspend and late resume handlers should not call
+ * pm_runtime_put() and pm_runtime_get_sync() directly, but rather the DPMS
+ * handlers should do it.
+ */
+static void gfx_early_suspend(struct early_suspend *es)
+{
+       struct drm_psb_private *dev_priv =
+               container_of(es, struct drm_psb_private, early_suspend);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_encoder *encoder;
+
+       dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct drm_encoder_helper_funcs *ehf = encoder->helper_private;
+
+               if (drm_helper_encoder_in_use(encoder) && ehf && ehf->dpms)
+                       ehf->dpms(encoder, DRM_MODE_DPMS_OFF);
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+
+       pm_runtime_put(&dev->pdev->dev);
+}
+
+static void gfx_late_resume(struct early_suspend *es)
+{
+       struct drm_psb_private *dev_priv =
+               container_of(es, struct drm_psb_private, early_suspend);
+       struct drm_device *dev = dev_priv->dev;
+       struct drm_encoder *encoder;
+
+       dev_dbg(&dev->pdev->dev, "%s\n", __func__);
+
+       pm_runtime_get_sync(&dev->pdev->dev);
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               struct drm_encoder_helper_funcs *ehf = encoder->helper_private;
+
+               if (drm_helper_encoder_in_use(encoder) && ehf && ehf->dpms) {
+                       struct drm_crtc *crtc = encoder->crtc;
+
+                       ehf->mode_set(encoder, &crtc->mode, &crtc->hwmode);
+                       ehf->dpms(encoder, DRM_MODE_DPMS_ON);
+               }
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+}
+#endif
+
 /*
  * ospm_power_init
  *
@@ -379,6 +433,13 @@ void ospm_power_init(struct drm_device *dev)
 
        spin_lock_init(&dev_priv->ospm_lock);
 
+#ifdef CONFIG_EARLYSUSPEND
+       dev_priv->early_suspend.suspend = gfx_early_suspend;
+       dev_priv->early_suspend.resume = gfx_late_resume;
+       dev_priv->early_suspend.level = EARLY_SUSPEND_LEVEL_STOP_DRAWING;
+       register_early_suspend(&dev_priv->early_suspend);
+#endif
+
        /* Runtime PM for PCI drivers. */
        pm_runtime_put_noidle(&dev->pdev->dev);
 }