aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/exynos
diff options
context:
space:
mode:
authorJoonyoung Shim <jy0922.shim@samsung.com>2011-12-09 02:52:11 -0500
committerInki Dae <inki.dae@samsung.com>2011-12-21 01:14:17 -0500
commitcb91f6a078097cdfe23bc1bd997e4310b06b87a3 (patch)
tree0bc8e1caa838782fe8b8fb7bc5389c100ff3a841 /drivers/gpu/drm/exynos
parentec05da959acc5da8d51207060d9af672ae837321 (diff)
drm/exynos: add runtime pm feature for fimd
This adds runtime PM feature for fimd. The runtime PM functions control clocks for fimd and prevent to access the register of fimd for vblank when clock is turned off by suspend of runtime PM. Signed-off-by: Joonyoung Shim <jy0922.shim@samsung.com> 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')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c78
1 files changed, 77 insertions, 1 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index 771800cc5f79..0b76bc058bca 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -17,6 +17,7 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/platform_device.h> 18#include <linux/platform_device.h>
19#include <linux/clk.h> 19#include <linux/clk.h>
20#include <linux/pm_runtime.h>
20 21
21#include <drm/exynos_drm.h> 22#include <drm/exynos_drm.h>
22#include <plat/regs-fb-v4.h> 23#include <plat/regs-fb-v4.h>
@@ -85,6 +86,7 @@ struct fimd_context {
85 unsigned long irq_flags; 86 unsigned long irq_flags;
86 u32 vidcon0; 87 u32 vidcon0;
87 u32 vidcon1; 88 u32 vidcon1;
89 bool suspended;
88 90
89 struct fb_videomode *timing; 91 struct fb_videomode *timing;
90}; 92};
@@ -137,7 +139,19 @@ static void fimd_dpms(struct device *subdrv_dev, int mode)
137{ 139{
138 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); 140 DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
139 141
140 /* TODO */ 142 switch (mode) {
143 case DRM_MODE_DPMS_ON:
144 pm_runtime_get_sync(subdrv_dev);
145 break;
146 case DRM_MODE_DPMS_STANDBY:
147 case DRM_MODE_DPMS_SUSPEND:
148 case DRM_MODE_DPMS_OFF:
149 pm_runtime_put_sync(subdrv_dev);
150 break;
151 default:
152 DRM_DEBUG_KMS("unspecified mode %d\n", mode);
153 break;
154 }
141} 155}
142 156
143static void fimd_apply(struct device *subdrv_dev) 157static void fimd_apply(struct device *subdrv_dev)
@@ -210,6 +224,9 @@ static int fimd_enable_vblank(struct device *dev)
210 224
211 DRM_DEBUG_KMS("%s\n", __FILE__); 225 DRM_DEBUG_KMS("%s\n", __FILE__);
212 226
227 if (ctx->suspended)
228 return -EPERM;
229
213 if (!test_and_set_bit(0, &ctx->irq_flags)) { 230 if (!test_and_set_bit(0, &ctx->irq_flags)) {
214 val = readl(ctx->regs + VIDINTCON0); 231 val = readl(ctx->regs + VIDINTCON0);
215 232
@@ -234,6 +251,9 @@ static void fimd_disable_vblank(struct device *dev)
234 251
235 DRM_DEBUG_KMS("%s\n", __FILE__); 252 DRM_DEBUG_KMS("%s\n", __FILE__);
236 253
254 if (ctx->suspended)
255 return;
256
237 if (test_and_clear_bit(0, &ctx->irq_flags)) { 257 if (test_and_clear_bit(0, &ctx->irq_flags)) {
238 val = readl(ctx->regs + VIDINTCON0); 258 val = readl(ctx->regs + VIDINTCON0);
239 259
@@ -760,6 +780,10 @@ static int __devinit fimd_probe(struct platform_device *pdev)
760 goto err_req_irq; 780 goto err_req_irq;
761 } 781 }
762 782
783 pm_runtime_set_active(dev);
784 pm_runtime_enable(dev);
785 pm_runtime_get_sync(dev);
786
763 for (win = 0; win < WINDOWS_NR; win++) 787 for (win = 0; win < WINDOWS_NR; win++)
764 fimd_clear_win(ctx, win); 788 fimd_clear_win(ctx, win);
765 789
@@ -812,14 +836,25 @@ err_clk_get:
812 836
813static int __devexit fimd_remove(struct platform_device *pdev) 837static int __devexit fimd_remove(struct platform_device *pdev)
814{ 838{
839 struct device *dev = &pdev->dev;
815 struct fimd_context *ctx = platform_get_drvdata(pdev); 840 struct fimd_context *ctx = platform_get_drvdata(pdev);
816 841
817 DRM_DEBUG_KMS("%s\n", __FILE__); 842 DRM_DEBUG_KMS("%s\n", __FILE__);
818 843
819 exynos_drm_subdrv_unregister(&ctx->subdrv); 844 exynos_drm_subdrv_unregister(&ctx->subdrv);
820 845
846 if (ctx->suspended)
847 goto out;
848
821 clk_disable(ctx->lcd_clk); 849 clk_disable(ctx->lcd_clk);
822 clk_disable(ctx->bus_clk); 850 clk_disable(ctx->bus_clk);
851
852 pm_runtime_set_suspended(dev);
853 pm_runtime_put_sync(dev);
854
855out:
856 pm_runtime_disable(dev);
857
823 clk_put(ctx->lcd_clk); 858 clk_put(ctx->lcd_clk);
824 clk_put(ctx->bus_clk); 859 clk_put(ctx->bus_clk);
825 860
@@ -833,12 +868,53 @@ static int __devexit fimd_remove(struct platform_device *pdev)
833 return 0; 868 return 0;
834} 869}
835 870
871#ifdef CONFIG_PM_RUNTIME
872static int fimd_runtime_suspend(struct device *dev)
873{
874 struct fimd_context *ctx = get_fimd_context(dev);
875
876 DRM_DEBUG_KMS("%s\n", __FILE__);
877
878 clk_disable(ctx->lcd_clk);
879 clk_disable(ctx->bus_clk);
880
881 ctx->suspended = true;
882 return 0;
883}
884
885static int fimd_runtime_resume(struct device *dev)
886{
887 struct fimd_context *ctx = get_fimd_context(dev);
888 int ret;
889
890 DRM_DEBUG_KMS("%s\n", __FILE__);
891
892 ret = clk_enable(ctx->bus_clk);
893 if (ret < 0)
894 return ret;
895
896 ret = clk_enable(ctx->lcd_clk);
897 if (ret < 0) {
898 clk_disable(ctx->bus_clk);
899 return ret;
900 }
901
902 ctx->suspended = false;
903 return 0;
904}
905#endif
906
907static const struct dev_pm_ops fimd_pm_ops = {
908 SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
909};
910
836static struct platform_driver fimd_driver = { 911static struct platform_driver fimd_driver = {
837 .probe = fimd_probe, 912 .probe = fimd_probe,
838 .remove = __devexit_p(fimd_remove), 913 .remove = __devexit_p(fimd_remove),
839 .driver = { 914 .driver = {
840 .name = "exynos4-fb", 915 .name = "exynos4-fb",
841 .owner = THIS_MODULE, 916 .owner = THIS_MODULE,
917 .pm = &fimd_pm_ops,
842 }, 918 },
843}; 919};
844 920