diff options
author | Sean Paul <seanpaul@chromium.org> | 2014-04-25 16:06:10 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 11:47:35 +0900 |
commit | 15e683b59de75bbf4e83f97585f571b292a48ce8 (patch) | |
tree | 98bac36f073d131cc56ca9730a8fadf4ff28b515 /drivers/gpu/drm/exynos/exynos_drm_drv.c | |
parent | b33d109db1fa4c7213ca0d65287b583483c4ab7d (diff) | |
download | linux-3.10-15e683b59de75bbf4e83f97585f571b292a48ce8.tar.gz linux-3.10-15e683b59de75bbf4e83f97585f571b292a48ce8.tar.bz2 linux-3.10-15e683b59de75bbf4e83f97585f571b292a48ce8.zip |
drm/exynos: Consolidate suspend/resume in drm_drv
This patch removes all of the suspend/resume logic from the individual
drivers and consolidates it in drm_drv. This consolidation reduces the
number of functions which enable/disable the hardware to just one -- the
dpms callback. This ensures that we always power up/down in a consistent
manner.
Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu/drm/exynos/exynos_drm_drv.c')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 7df0e26f1fb..c028f946dea 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c @@ -11,6 +11,7 @@ * option) any later version. */ +#include <linux/pm_runtime.h> #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> @@ -52,6 +53,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) return -ENOMEM; INIT_LIST_HEAD(&private->pageflip_event_list); + dev_set_drvdata(dev->dev, dev); dev->dev_private = (void *)private; /* @@ -156,6 +158,41 @@ static int exynos_drm_unload(struct drm_device *dev) return 0; } +static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) +{ + struct drm_connector *connector; + + drm_modeset_lock_all(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + int old_dpms = connector->dpms; + + if (connector->funcs->dpms) + connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); + + /* Set the old mode back to the connector for resume */ + connector->dpms = old_dpms; + } + drm_modeset_unlock_all(dev); + + return 0; +} + +static int exynos_drm_resume(struct drm_device *dev) +{ + struct drm_connector *connector; + + drm_modeset_lock_all(dev); + list_for_each_entry(connector, &dev->mode_config.connector_list, head) { + if (connector->funcs->dpms) + connector->funcs->dpms(connector, connector->dpms); + } + + drm_helper_resume_force_mode(dev); + drm_modeset_unlock_all(dev); + + return 0; +} + static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) { struct drm_exynos_file_private *file_priv; @@ -255,6 +292,8 @@ static struct drm_driver exynos_drm_driver = { .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME, .load = exynos_drm_load, .unload = exynos_drm_unload, + .suspend = exynos_drm_suspend, + .resume = exynos_drm_resume, .open = exynos_drm_open, .preclose = exynos_drm_preclose, .lastclose = exynos_drm_lastclose, @@ -286,6 +325,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); exynos_drm_driver.num_ioctls = DRM_ARRAY_SIZE(exynos_ioctls); + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + return drm_platform_init(&exynos_drm_driver, pdev); } @@ -296,12 +338,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int exynos_drm_sys_suspend(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + pm_message_t message; + + if (pm_runtime_suspended(dev)) + return 0; + + message.event = PM_EVENT_SUSPEND; + return exynos_drm_suspend(drm_dev, message); +} + +static int exynos_drm_sys_resume(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + + if (pm_runtime_suspended(dev)) + return 0; + + return exynos_drm_resume(drm_dev); +} +#endif + +#ifdef CONFIG_PM_RUNTIME +static int exynos_drm_runtime_suspend(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + pm_message_t message; + + if (pm_runtime_suspended(dev)) + return 0; + + message.event = PM_EVENT_SUSPEND; + return exynos_drm_suspend(drm_dev, message); +} + +static int exynos_drm_runtime_resume(struct device *dev) +{ + struct drm_device *drm_dev = dev_get_drvdata(dev); + + if (!pm_runtime_suspended(dev)) + return 0; + + return exynos_drm_resume(drm_dev); +} +#endif + +static const struct dev_pm_ops exynos_drm_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) + SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend, + exynos_drm_runtime_resume, NULL) +}; + static struct platform_driver exynos_drm_platform_driver = { .probe = exynos_drm_platform_probe, .remove = exynos_drm_platform_remove, .driver = { .owner = THIS_MODULE, .name = "exynos-drm", + .pm = &exynos_drm_pm_ops, }, }; |