diff options
author | Sean Paul <seanpaul@chromium.org> | 2014-01-30 16:19:27 -0500 |
---|---|---|
committer | Inki Dae <daeinki@gmail.com> | 2014-03-23 11:36:36 -0400 |
commit | af65c804877078a58cb02cc0f2ce4198401402fc (patch) | |
tree | 1894a3b77ee5098bafe60f69694ca5d122a1be36 | |
parent | a43b933bcbbd6c7e2660b672a311345cea9524c1 (diff) |
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>
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_drv.c | 97 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_fimd.c | 86 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_vidi.c | 119 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_hdmi.c | 88 | ||||
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_mixer.c | 68 |
5 files changed, 170 insertions, 288 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c index 8619a537e6ff..8789d64109ca 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_drv.c +++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c | |||
@@ -11,6 +11,7 @@ | |||
11 | * option) any later version. | 11 | * option) any later version. |
12 | */ | 12 | */ |
13 | 13 | ||
14 | #include <linux/pm_runtime.h> | ||
14 | #include <drm/drmP.h> | 15 | #include <drm/drmP.h> |
15 | #include <drm/drm_crtc_helper.h> | 16 | #include <drm/drm_crtc_helper.h> |
16 | 17 | ||
@@ -53,6 +54,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags) | |||
53 | return -ENOMEM; | 54 | return -ENOMEM; |
54 | 55 | ||
55 | INIT_LIST_HEAD(&private->pageflip_event_list); | 56 | INIT_LIST_HEAD(&private->pageflip_event_list); |
57 | dev_set_drvdata(dev->dev, dev); | ||
56 | dev->dev_private = (void *)private; | 58 | dev->dev_private = (void *)private; |
57 | 59 | ||
58 | /* | 60 | /* |
@@ -163,6 +165,41 @@ static const struct file_operations exynos_drm_gem_fops = { | |||
163 | .mmap = exynos_drm_gem_mmap_buffer, | 165 | .mmap = exynos_drm_gem_mmap_buffer, |
164 | }; | 166 | }; |
165 | 167 | ||
168 | static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state) | ||
169 | { | ||
170 | struct drm_connector *connector; | ||
171 | |||
172 | drm_modeset_lock_all(dev); | ||
173 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
174 | int old_dpms = connector->dpms; | ||
175 | |||
176 | if (connector->funcs->dpms) | ||
177 | connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF); | ||
178 | |||
179 | /* Set the old mode back to the connector for resume */ | ||
180 | connector->dpms = old_dpms; | ||
181 | } | ||
182 | drm_modeset_unlock_all(dev); | ||
183 | |||
184 | return 0; | ||
185 | } | ||
186 | |||
187 | static int exynos_drm_resume(struct drm_device *dev) | ||
188 | { | ||
189 | struct drm_connector *connector; | ||
190 | |||
191 | drm_modeset_lock_all(dev); | ||
192 | list_for_each_entry(connector, &dev->mode_config.connector_list, head) { | ||
193 | if (connector->funcs->dpms) | ||
194 | connector->funcs->dpms(connector, connector->dpms); | ||
195 | } | ||
196 | |||
197 | drm_helper_resume_force_mode(dev); | ||
198 | drm_modeset_unlock_all(dev); | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | |||
166 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) | 203 | static int exynos_drm_open(struct drm_device *dev, struct drm_file *file) |
167 | { | 204 | { |
168 | struct drm_exynos_file_private *file_priv; | 205 | struct drm_exynos_file_private *file_priv; |
@@ -300,6 +337,8 @@ static struct drm_driver exynos_drm_driver = { | |||
300 | DRIVER_GEM | DRIVER_PRIME, | 337 | DRIVER_GEM | DRIVER_PRIME, |
301 | .load = exynos_drm_load, | 338 | .load = exynos_drm_load, |
302 | .unload = exynos_drm_unload, | 339 | .unload = exynos_drm_unload, |
340 | .suspend = exynos_drm_suspend, | ||
341 | .resume = exynos_drm_resume, | ||
303 | .open = exynos_drm_open, | 342 | .open = exynos_drm_open, |
304 | .preclose = exynos_drm_preclose, | 343 | .preclose = exynos_drm_preclose, |
305 | .lastclose = exynos_drm_lastclose, | 344 | .lastclose = exynos_drm_lastclose, |
@@ -334,6 +373,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev) | |||
334 | if (ret) | 373 | if (ret) |
335 | return ret; | 374 | return ret; |
336 | 375 | ||
376 | pm_runtime_enable(&pdev->dev); | ||
377 | pm_runtime_get_sync(&pdev->dev); | ||
378 | |||
337 | return drm_platform_init(&exynos_drm_driver, pdev); | 379 | return drm_platform_init(&exynos_drm_driver, pdev); |
338 | } | 380 | } |
339 | 381 | ||
@@ -344,12 +386,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev) | |||
344 | return 0; | 386 | return 0; |
345 | } | 387 | } |
346 | 388 | ||
389 | #ifdef CONFIG_PM_SLEEP | ||
390 | static int exynos_drm_sys_suspend(struct device *dev) | ||
391 | { | ||
392 | struct drm_device *drm_dev = dev_get_drvdata(dev); | ||
393 | pm_message_t message; | ||
394 | |||
395 | if (pm_runtime_suspended(dev)) | ||
396 | return 0; | ||
397 | |||
398 | message.event = PM_EVENT_SUSPEND; | ||
399 | return exynos_drm_suspend(drm_dev, message); | ||
400 | } | ||
401 | |||
402 | static int exynos_drm_sys_resume(struct device *dev) | ||
403 | { | ||
404 | struct drm_device *drm_dev = dev_get_drvdata(dev); | ||
405 | |||
406 | if (pm_runtime_suspended(dev)) | ||
407 | return 0; | ||
408 | |||
409 | return exynos_drm_resume(drm_dev); | ||
410 | } | ||
411 | #endif | ||
412 | |||
413 | #ifdef CONFIG_PM_RUNTIME | ||
414 | static int exynos_drm_runtime_suspend(struct device *dev) | ||
415 | { | ||
416 | struct drm_device *drm_dev = dev_get_drvdata(dev); | ||
417 | pm_message_t message; | ||
418 | |||
419 | if (pm_runtime_suspended(dev)) | ||
420 | return 0; | ||
421 | |||
422 | message.event = PM_EVENT_SUSPEND; | ||
423 | return exynos_drm_suspend(drm_dev, message); | ||
424 | } | ||
425 | |||
426 | static int exynos_drm_runtime_resume(struct device *dev) | ||
427 | { | ||
428 | struct drm_device *drm_dev = dev_get_drvdata(dev); | ||
429 | |||
430 | if (!pm_runtime_suspended(dev)) | ||
431 | return 0; | ||
432 | |||
433 | return exynos_drm_resume(drm_dev); | ||
434 | } | ||
435 | #endif | ||
436 | |||
437 | static const struct dev_pm_ops exynos_drm_pm_ops = { | ||
438 | SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume) | ||
439 | SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend, | ||
440 | exynos_drm_runtime_resume, NULL) | ||
441 | }; | ||
442 | |||
347 | static struct platform_driver exynos_drm_platform_driver = { | 443 | static struct platform_driver exynos_drm_platform_driver = { |
348 | .probe = exynos_drm_platform_probe, | 444 | .probe = exynos_drm_platform_probe, |
349 | .remove = exynos_drm_platform_remove, | 445 | .remove = exynos_drm_platform_remove, |
350 | .driver = { | 446 | .driver = { |
351 | .owner = THIS_MODULE, | 447 | .owner = THIS_MODULE, |
352 | .name = "exynos-drm", | 448 | .name = "exynos-drm", |
449 | .pm = &exynos_drm_pm_ops, | ||
353 | }, | 450 | }, |
354 | }; | 451 | }; |
355 | 452 | ||
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c index 1efdcac4510d..f78fbf4682b4 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c +++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c | |||
@@ -732,6 +732,8 @@ static int fimd_poweron(struct exynos_drm_manager *mgr) | |||
732 | 732 | ||
733 | ctx->suspended = false; | 733 | ctx->suspended = false; |
734 | 734 | ||
735 | pm_runtime_get_sync(ctx->dev); | ||
736 | |||
735 | ret = clk_prepare_enable(ctx->bus_clk); | 737 | ret = clk_prepare_enable(ctx->bus_clk); |
736 | if (ret < 0) { | 738 | if (ret < 0) { |
737 | DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); | 739 | DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret); |
@@ -785,32 +787,24 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr) | |||
785 | clk_disable_unprepare(ctx->lcd_clk); | 787 | clk_disable_unprepare(ctx->lcd_clk); |
786 | clk_disable_unprepare(ctx->bus_clk); | 788 | clk_disable_unprepare(ctx->bus_clk); |
787 | 789 | ||
790 | pm_runtime_put_sync(ctx->dev); | ||
791 | |||
788 | ctx->suspended = true; | 792 | ctx->suspended = true; |
789 | return 0; | 793 | return 0; |
790 | } | 794 | } |
791 | 795 | ||
792 | static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) | 796 | static void fimd_dpms(struct exynos_drm_manager *mgr, int mode) |
793 | { | 797 | { |
794 | struct fimd_context *ctx = mgr->ctx; | 798 | DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode); |
795 | |||
796 | DRM_DEBUG_KMS("%d\n", mode); | ||
797 | 799 | ||
798 | switch (mode) { | 800 | switch (mode) { |
799 | case DRM_MODE_DPMS_ON: | 801 | case DRM_MODE_DPMS_ON: |
800 | /* | 802 | fimd_poweron(mgr); |
801 | * enable fimd hardware only if suspended status. | ||
802 | * | ||
803 | * P.S. fimd_dpms function would be called at booting time so | ||
804 | * clk_enable could be called double time. | ||
805 | */ | ||
806 | if (ctx->suspended) | ||
807 | pm_runtime_get_sync(ctx->dev); | ||
808 | break; | 803 | break; |
809 | case DRM_MODE_DPMS_STANDBY: | 804 | case DRM_MODE_DPMS_STANDBY: |
810 | case DRM_MODE_DPMS_SUSPEND: | 805 | case DRM_MODE_DPMS_SUSPEND: |
811 | case DRM_MODE_DPMS_OFF: | 806 | case DRM_MODE_DPMS_OFF: |
812 | if (!ctx->suspended) | 807 | fimd_poweroff(mgr); |
813 | pm_runtime_put_sync(ctx->dev); | ||
814 | break; | 808 | break; |
815 | default: | 809 | default: |
816 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); | 810 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); |
@@ -929,7 +923,6 @@ static int fimd_probe(struct platform_device *pdev) | |||
929 | exynos_drm_manager_register(&fimd_manager); | 923 | exynos_drm_manager_register(&fimd_manager); |
930 | 924 | ||
931 | pm_runtime_enable(dev); | 925 | pm_runtime_enable(dev); |
932 | pm_runtime_get_sync(dev); | ||
933 | 926 | ||
934 | for (win = 0; win < WINDOWS_NR; win++) | 927 | for (win = 0; win < WINDOWS_NR; win++) |
935 | fimd_clear_win(ctx, win); | 928 | fimd_clear_win(ctx, win); |
@@ -939,84 +932,23 @@ static int fimd_probe(struct platform_device *pdev) | |||
939 | 932 | ||
940 | static int fimd_remove(struct platform_device *pdev) | 933 | static int fimd_remove(struct platform_device *pdev) |
941 | { | 934 | { |
942 | struct device *dev = &pdev->dev; | ||
943 | struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); | 935 | struct exynos_drm_manager *mgr = platform_get_drvdata(pdev); |
944 | struct fimd_context *ctx = mgr->ctx; | ||
945 | 936 | ||
946 | exynos_drm_manager_unregister(&fimd_manager); | 937 | exynos_drm_manager_unregister(&fimd_manager); |
947 | 938 | ||
948 | if (ctx->suspended) | 939 | fimd_dpms(mgr, DRM_MODE_DPMS_OFF); |
949 | goto out; | ||
950 | |||
951 | pm_runtime_set_suspended(dev); | ||
952 | pm_runtime_put_sync(dev); | ||
953 | 940 | ||
954 | out: | 941 | pm_runtime_disable(&pdev->dev); |
955 | pm_runtime_disable(dev); | ||
956 | |||
957 | return 0; | ||
958 | } | ||
959 | |||
960 | #ifdef CONFIG_PM_SLEEP | ||
961 | static int fimd_suspend(struct device *dev) | ||
962 | { | ||
963 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
964 | |||
965 | /* | ||
966 | * do not use pm_runtime_suspend(). if pm_runtime_suspend() is | ||
967 | * called here, an error would be returned by that interface | ||
968 | * because the usage_count of pm runtime is more than 1. | ||
969 | */ | ||
970 | if (!pm_runtime_suspended(dev)) | ||
971 | return fimd_poweroff(mgr); | ||
972 | 942 | ||
973 | return 0; | 943 | return 0; |
974 | } | 944 | } |
975 | 945 | ||
976 | static int fimd_resume(struct device *dev) | ||
977 | { | ||
978 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
979 | |||
980 | /* | ||
981 | * if entered to sleep when lcd panel was on, the usage_count | ||
982 | * of pm runtime would still be 1 so in this case, fimd driver | ||
983 | * should be on directly not drawing on pm runtime interface. | ||
984 | */ | ||
985 | if (pm_runtime_suspended(dev)) | ||
986 | return 0; | ||
987 | |||
988 | return fimd_poweron(mgr); | ||
989 | } | ||
990 | #endif | ||
991 | |||
992 | #ifdef CONFIG_PM_RUNTIME | ||
993 | static int fimd_runtime_suspend(struct device *dev) | ||
994 | { | ||
995 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
996 | |||
997 | return fimd_poweroff(mgr); | ||
998 | } | ||
999 | |||
1000 | static int fimd_runtime_resume(struct device *dev) | ||
1001 | { | ||
1002 | struct exynos_drm_manager *mgr = get_fimd_manager(dev); | ||
1003 | |||
1004 | return fimd_poweron(mgr); | ||
1005 | } | ||
1006 | #endif | ||
1007 | |||
1008 | static const struct dev_pm_ops fimd_pm_ops = { | ||
1009 | SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume) | ||
1010 | SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL) | ||
1011 | }; | ||
1012 | |||
1013 | struct platform_driver fimd_driver = { | 946 | struct platform_driver fimd_driver = { |
1014 | .probe = fimd_probe, | 947 | .probe = fimd_probe, |
1015 | .remove = fimd_remove, | 948 | .remove = fimd_remove, |
1016 | .driver = { | 949 | .driver = { |
1017 | .name = "exynos4-fb", | 950 | .name = "exynos4-fb", |
1018 | .owner = THIS_MODULE, | 951 | .owner = THIS_MODULE, |
1019 | .pm = &fimd_pm_ops, | ||
1020 | .of_match_table = fimd_driver_dt_match, | 952 | .of_match_table = fimd_driver_dt_match, |
1021 | }, | 953 | }, |
1022 | }; | 954 | }; |
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c index f6f4438a40d9..5d0b5cdeaacf 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c +++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c | |||
@@ -140,31 +140,6 @@ static struct exynos_drm_display vidi_display = { | |||
140 | .ops = &vidi_display_ops, | 140 | .ops = &vidi_display_ops, |
141 | }; | 141 | }; |
142 | 142 | ||
143 | static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) | ||
144 | { | ||
145 | struct vidi_context *ctx = mgr->ctx; | ||
146 | |||
147 | DRM_DEBUG_KMS("%d\n", mode); | ||
148 | |||
149 | mutex_lock(&ctx->lock); | ||
150 | |||
151 | switch (mode) { | ||
152 | case DRM_MODE_DPMS_ON: | ||
153 | /* TODO. */ | ||
154 | break; | ||
155 | case DRM_MODE_DPMS_STANDBY: | ||
156 | case DRM_MODE_DPMS_SUSPEND: | ||
157 | case DRM_MODE_DPMS_OFF: | ||
158 | /* TODO. */ | ||
159 | break; | ||
160 | default: | ||
161 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); | ||
162 | break; | ||
163 | } | ||
164 | |||
165 | mutex_unlock(&ctx->lock); | ||
166 | } | ||
167 | |||
168 | static void vidi_apply(struct exynos_drm_manager *mgr) | 143 | static void vidi_apply(struct exynos_drm_manager *mgr) |
169 | { | 144 | { |
170 | struct vidi_context *ctx = mgr->ctx; | 145 | struct vidi_context *ctx = mgr->ctx; |
@@ -319,6 +294,55 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos) | |||
319 | /* TODO. */ | 294 | /* TODO. */ |
320 | } | 295 | } |
321 | 296 | ||
297 | static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) | ||
298 | { | ||
299 | struct vidi_context *ctx = mgr->ctx; | ||
300 | |||
301 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
302 | |||
303 | if (enable != false && enable != true) | ||
304 | return -EINVAL; | ||
305 | |||
306 | if (enable) { | ||
307 | ctx->suspended = false; | ||
308 | |||
309 | /* if vblank was enabled status, enable it again. */ | ||
310 | if (test_and_clear_bit(0, &ctx->irq_flags)) | ||
311 | vidi_enable_vblank(mgr); | ||
312 | |||
313 | vidi_apply(mgr); | ||
314 | } else { | ||
315 | ctx->suspended = true; | ||
316 | } | ||
317 | |||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static void vidi_dpms(struct exynos_drm_manager *mgr, int mode) | ||
322 | { | ||
323 | struct vidi_context *ctx = mgr->ctx; | ||
324 | |||
325 | DRM_DEBUG_KMS("%d\n", mode); | ||
326 | |||
327 | mutex_lock(&ctx->lock); | ||
328 | |||
329 | switch (mode) { | ||
330 | case DRM_MODE_DPMS_ON: | ||
331 | vidi_power_on(mgr, true); | ||
332 | break; | ||
333 | case DRM_MODE_DPMS_STANDBY: | ||
334 | case DRM_MODE_DPMS_SUSPEND: | ||
335 | case DRM_MODE_DPMS_OFF: | ||
336 | vidi_power_on(mgr, false); | ||
337 | break; | ||
338 | default: | ||
339 | DRM_DEBUG_KMS("unspecified mode %d\n", mode); | ||
340 | break; | ||
341 | } | ||
342 | |||
343 | mutex_unlock(&ctx->lock); | ||
344 | } | ||
345 | |||
322 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, | 346 | static int vidi_mgr_initialize(struct exynos_drm_manager *mgr, |
323 | struct drm_device *drm_dev, int pipe) | 347 | struct drm_device *drm_dev, int pipe) |
324 | { | 348 | { |
@@ -390,30 +414,6 @@ static void vidi_fake_vblank_handler(struct work_struct *work) | |||
390 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); | 414 | exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe); |
391 | } | 415 | } |
392 | 416 | ||
393 | static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable) | ||
394 | { | ||
395 | struct vidi_context *ctx = mgr->ctx; | ||
396 | |||
397 | DRM_DEBUG_KMS("%s\n", __FILE__); | ||
398 | |||
399 | if (enable != false && enable != true) | ||
400 | return -EINVAL; | ||
401 | |||
402 | if (enable) { | ||
403 | ctx->suspended = false; | ||
404 | |||
405 | /* if vblank was enabled status, enable it again. */ | ||
406 | if (test_and_clear_bit(0, &ctx->irq_flags)) | ||
407 | vidi_enable_vblank(mgr); | ||
408 | |||
409 | vidi_apply(mgr); | ||
410 | } else { | ||
411 | ctx->suspended = true; | ||
412 | } | ||
413 | |||
414 | return 0; | ||
415 | } | ||
416 | |||
417 | static int vidi_show_connection(struct device *dev, | 417 | static int vidi_show_connection(struct device *dev, |
418 | struct device_attribute *attr, char *buf) | 418 | struct device_attribute *attr, char *buf) |
419 | { | 419 | { |
@@ -578,32 +578,11 @@ static int vidi_remove(struct platform_device *pdev) | |||
578 | return 0; | 578 | return 0; |
579 | } | 579 | } |
580 | 580 | ||
581 | #ifdef CONFIG_PM_SLEEP | ||
582 | static int vidi_suspend(struct device *dev) | ||
583 | { | ||
584 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | ||
585 | |||
586 | return vidi_power_on(mgr, false); | ||
587 | } | ||
588 | |||
589 | static int vidi_resume(struct device *dev) | ||
590 | { | ||
591 | struct exynos_drm_manager *mgr = get_vidi_mgr(dev); | ||
592 | |||
593 | return vidi_power_on(mgr, true); | ||
594 | } | ||
595 | #endif | ||
596 | |||
597 | static const struct dev_pm_ops vidi_pm_ops = { | ||
598 | SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume) | ||
599 | }; | ||
600 | |||
601 | struct platform_driver vidi_driver = { | 581 | struct platform_driver vidi_driver = { |
602 | .probe = vidi_probe, | 582 | .probe = vidi_probe, |
603 | .remove = vidi_remove, | 583 | .remove = vidi_remove, |
604 | .driver = { | 584 | .driver = { |
605 | .name = "exynos-drm-vidi", | 585 | .name = "exynos-drm-vidi", |
606 | .owner = THIS_MODULE, | 586 | .owner = THIS_MODULE, |
607 | .pm = &vidi_pm_ops, | ||
608 | }, | 587 | }, |
609 | }; | 588 | }; |
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c index b31a51da50f6..1a06a54a901f 100644 --- a/drivers/gpu/drm/exynos/exynos_hdmi.c +++ b/drivers/gpu/drm/exynos/exynos_hdmi.c | |||
@@ -1789,6 +1789,8 @@ static void hdmi_poweron(struct exynos_drm_display *display) | |||
1789 | 1789 | ||
1790 | mutex_unlock(&hdata->hdmi_mutex); | 1790 | mutex_unlock(&hdata->hdmi_mutex); |
1791 | 1791 | ||
1792 | pm_runtime_get_sync(hdata->dev); | ||
1793 | |||
1792 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) | 1794 | if (regulator_bulk_enable(res->regul_count, res->regul_bulk)) |
1793 | DRM_DEBUG_KMS("failed to enable regulator bulk\n"); | 1795 | DRM_DEBUG_KMS("failed to enable regulator bulk\n"); |
1794 | 1796 | ||
@@ -1822,8 +1824,9 @@ static void hdmi_poweroff(struct exynos_drm_display *display) | |||
1822 | clk_disable_unprepare(res->hdmiphy); | 1824 | clk_disable_unprepare(res->hdmiphy); |
1823 | regulator_bulk_disable(res->regul_count, res->regul_bulk); | 1825 | regulator_bulk_disable(res->regul_count, res->regul_bulk); |
1824 | 1826 | ||
1825 | mutex_lock(&hdata->hdmi_mutex); | 1827 | pm_runtime_put_sync(hdata->dev); |
1826 | 1828 | ||
1829 | mutex_lock(&hdata->hdmi_mutex); | ||
1827 | hdata->powered = false; | 1830 | hdata->powered = false; |
1828 | 1831 | ||
1829 | out: | 1832 | out: |
@@ -1832,20 +1835,16 @@ out: | |||
1832 | 1835 | ||
1833 | static void hdmi_dpms(struct exynos_drm_display *display, int mode) | 1836 | static void hdmi_dpms(struct exynos_drm_display *display, int mode) |
1834 | { | 1837 | { |
1835 | struct hdmi_context *hdata = display->ctx; | ||
1836 | |||
1837 | DRM_DEBUG_KMS("mode %d\n", mode); | 1838 | DRM_DEBUG_KMS("mode %d\n", mode); |
1838 | 1839 | ||
1839 | switch (mode) { | 1840 | switch (mode) { |
1840 | case DRM_MODE_DPMS_ON: | 1841 | case DRM_MODE_DPMS_ON: |
1841 | if (pm_runtime_suspended(hdata->dev)) | 1842 | hdmi_poweron(display); |
1842 | pm_runtime_get_sync(hdata->dev); | ||
1843 | break; | 1843 | break; |
1844 | case DRM_MODE_DPMS_STANDBY: | 1844 | case DRM_MODE_DPMS_STANDBY: |
1845 | case DRM_MODE_DPMS_SUSPEND: | 1845 | case DRM_MODE_DPMS_SUSPEND: |
1846 | case DRM_MODE_DPMS_OFF: | 1846 | case DRM_MODE_DPMS_OFF: |
1847 | if (!pm_runtime_suspended(hdata->dev)) | 1847 | hdmi_poweroff(display); |
1848 | pm_runtime_put_sync(hdata->dev); | ||
1849 | break; | 1848 | break; |
1850 | default: | 1849 | default: |
1851 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | 1850 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); |
@@ -2085,11 +2084,11 @@ static int hdmi_probe(struct platform_device *pdev) | |||
2085 | goto err_hdmiphy; | 2084 | goto err_hdmiphy; |
2086 | } | 2085 | } |
2087 | 2086 | ||
2087 | pm_runtime_enable(dev); | ||
2088 | |||
2088 | hdmi_display.ctx = hdata; | 2089 | hdmi_display.ctx = hdata; |
2089 | exynos_drm_display_register(&hdmi_display); | 2090 | exynos_drm_display_register(&hdmi_display); |
2090 | 2091 | ||
2091 | pm_runtime_enable(dev); | ||
2092 | |||
2093 | return 0; | 2092 | return 0; |
2094 | 2093 | ||
2095 | err_hdmiphy: | 2094 | err_hdmiphy: |
@@ -2105,88 +2104,19 @@ static int hdmi_remove(struct platform_device *pdev) | |||
2105 | struct exynos_drm_display *display = get_hdmi_display(dev); | 2104 | struct exynos_drm_display *display = get_hdmi_display(dev); |
2106 | struct hdmi_context *hdata = display->ctx; | 2105 | struct hdmi_context *hdata = display->ctx; |
2107 | 2106 | ||
2108 | pm_runtime_disable(dev); | ||
2109 | |||
2110 | put_device(&hdata->hdmiphy_port->dev); | 2107 | put_device(&hdata->hdmiphy_port->dev); |
2111 | put_device(&hdata->ddc_port->dev); | 2108 | put_device(&hdata->ddc_port->dev); |
2109 | pm_runtime_disable(&pdev->dev); | ||
2112 | 2110 | ||
2113 | return 0; | 2111 | return 0; |
2114 | } | 2112 | } |
2115 | 2113 | ||
2116 | #ifdef CONFIG_PM_SLEEP | ||
2117 | static int hdmi_suspend(struct device *dev) | ||
2118 | { | ||
2119 | struct exynos_drm_display *display = get_hdmi_display(dev); | ||
2120 | struct hdmi_context *hdata = display->ctx; | ||
2121 | |||
2122 | disable_irq(hdata->irq); | ||
2123 | |||
2124 | hdata->hpd = false; | ||
2125 | if (hdata->drm_dev) | ||
2126 | drm_helper_hpd_irq_event(hdata->drm_dev); | ||
2127 | |||
2128 | if (pm_runtime_suspended(dev)) { | ||
2129 | DRM_DEBUG_KMS("Already suspended\n"); | ||
2130 | return 0; | ||
2131 | } | ||
2132 | |||
2133 | hdmi_poweroff(display); | ||
2134 | |||
2135 | return 0; | ||
2136 | } | ||
2137 | |||
2138 | static int hdmi_resume(struct device *dev) | ||
2139 | { | ||
2140 | struct exynos_drm_display *display = get_hdmi_display(dev); | ||
2141 | struct hdmi_context *hdata = display->ctx; | ||
2142 | |||
2143 | hdata->hpd = gpio_get_value(hdata->hpd_gpio); | ||
2144 | |||
2145 | enable_irq(hdata->irq); | ||
2146 | |||
2147 | if (!pm_runtime_suspended(dev)) { | ||
2148 | DRM_DEBUG_KMS("Already resumed\n"); | ||
2149 | return 0; | ||
2150 | } | ||
2151 | |||
2152 | hdmi_poweron(display); | ||
2153 | |||
2154 | return 0; | ||
2155 | } | ||
2156 | #endif | ||
2157 | |||
2158 | #ifdef CONFIG_PM_RUNTIME | ||
2159 | static int hdmi_runtime_suspend(struct device *dev) | ||
2160 | { | ||
2161 | struct exynos_drm_display *display = get_hdmi_display(dev); | ||
2162 | |||
2163 | hdmi_poweroff(display); | ||
2164 | |||
2165 | return 0; | ||
2166 | } | ||
2167 | |||
2168 | static int hdmi_runtime_resume(struct device *dev) | ||
2169 | { | ||
2170 | struct exynos_drm_display *display = get_hdmi_display(dev); | ||
2171 | |||
2172 | hdmi_poweron(display); | ||
2173 | |||
2174 | return 0; | ||
2175 | } | ||
2176 | #endif | ||
2177 | |||
2178 | static const struct dev_pm_ops hdmi_pm_ops = { | ||
2179 | SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume) | ||
2180 | SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL) | ||
2181 | }; | ||
2182 | |||
2183 | struct platform_driver hdmi_driver = { | 2114 | struct platform_driver hdmi_driver = { |
2184 | .probe = hdmi_probe, | 2115 | .probe = hdmi_probe, |
2185 | .remove = hdmi_remove, | 2116 | .remove = hdmi_remove, |
2186 | .driver = { | 2117 | .driver = { |
2187 | .name = "exynos-hdmi", | 2118 | .name = "exynos-hdmi", |
2188 | .owner = THIS_MODULE, | 2119 | .owner = THIS_MODULE, |
2189 | .pm = &hdmi_pm_ops, | ||
2190 | .of_match_table = hdmi_match_types, | 2120 | .of_match_table = hdmi_match_types, |
2191 | }, | 2121 | }, |
2192 | }; | 2122 | }; |
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index d5228577cabb..ce288818d2c0 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c | |||
@@ -1061,6 +1061,8 @@ static void mixer_poweron(struct exynos_drm_manager *mgr) | |||
1061 | ctx->powered = true; | 1061 | ctx->powered = true; |
1062 | mutex_unlock(&ctx->mixer_mutex); | 1062 | mutex_unlock(&ctx->mixer_mutex); |
1063 | 1063 | ||
1064 | pm_runtime_get_sync(ctx->dev); | ||
1065 | |||
1064 | clk_prepare_enable(res->mixer); | 1066 | clk_prepare_enable(res->mixer); |
1065 | if (ctx->vp_enabled) { | 1067 | if (ctx->vp_enabled) { |
1066 | clk_prepare_enable(res->vp); | 1068 | clk_prepare_enable(res->vp); |
@@ -1093,6 +1095,8 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr) | |||
1093 | clk_disable_unprepare(res->sclk_mixer); | 1095 | clk_disable_unprepare(res->sclk_mixer); |
1094 | } | 1096 | } |
1095 | 1097 | ||
1098 | pm_runtime_put_sync(ctx->dev); | ||
1099 | |||
1096 | mutex_lock(&ctx->mixer_mutex); | 1100 | mutex_lock(&ctx->mixer_mutex); |
1097 | ctx->powered = false; | 1101 | ctx->powered = false; |
1098 | 1102 | ||
@@ -1102,18 +1106,14 @@ out: | |||
1102 | 1106 | ||
1103 | static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) | 1107 | static void mixer_dpms(struct exynos_drm_manager *mgr, int mode) |
1104 | { | 1108 | { |
1105 | struct mixer_context *mixer_ctx = mgr->ctx; | ||
1106 | |||
1107 | switch (mode) { | 1109 | switch (mode) { |
1108 | case DRM_MODE_DPMS_ON: | 1110 | case DRM_MODE_DPMS_ON: |
1109 | if (pm_runtime_suspended(mixer_ctx->dev)) | 1111 | mixer_poweron(mgr); |
1110 | pm_runtime_get_sync(mixer_ctx->dev); | ||
1111 | break; | 1112 | break; |
1112 | case DRM_MODE_DPMS_STANDBY: | 1113 | case DRM_MODE_DPMS_STANDBY: |
1113 | case DRM_MODE_DPMS_SUSPEND: | 1114 | case DRM_MODE_DPMS_SUSPEND: |
1114 | case DRM_MODE_DPMS_OFF: | 1115 | case DRM_MODE_DPMS_OFF: |
1115 | if (!pm_runtime_suspended(mixer_ctx->dev)) | 1116 | mixer_poweroff(mgr); |
1116 | pm_runtime_put_sync(mixer_ctx->dev); | ||
1117 | break; | 1117 | break; |
1118 | default: | 1118 | default: |
1119 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); | 1119 | DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode); |
@@ -1250,66 +1250,10 @@ static int mixer_remove(struct platform_device *pdev) | |||
1250 | return 0; | 1250 | return 0; |
1251 | } | 1251 | } |
1252 | 1252 | ||
1253 | #ifdef CONFIG_PM_SLEEP | ||
1254 | static int mixer_suspend(struct device *dev) | ||
1255 | { | ||
1256 | struct exynos_drm_manager *mgr = get_mixer_manager(dev); | ||
1257 | |||
1258 | if (pm_runtime_suspended(dev)) { | ||
1259 | DRM_DEBUG_KMS("Already suspended\n"); | ||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | mixer_poweroff(mgr); | ||
1264 | |||
1265 | return 0; | ||
1266 | } | ||
1267 | |||
1268 | static int mixer_resume(struct device *dev) | ||
1269 | { | ||
1270 | struct exynos_drm_manager *mgr = get_mixer_manager(dev); | ||
1271 | |||
1272 | if (!pm_runtime_suspended(dev)) { | ||
1273 | DRM_DEBUG_KMS("Already resumed\n"); | ||
1274 | return 0; | ||
1275 | } | ||
1276 | |||
1277 | mixer_poweron(mgr); | ||
1278 | |||
1279 | return 0; | ||
1280 | } | ||
1281 | #endif | ||
1282 | |||
1283 | #ifdef CONFIG_PM_RUNTIME | ||
1284 | static int mixer_runtime_suspend(struct device *dev) | ||
1285 | { | ||
1286 | struct exynos_drm_manager *mgr = get_mixer_manager(dev); | ||
1287 | |||
1288 | mixer_poweroff(mgr); | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | static int mixer_runtime_resume(struct device *dev) | ||
1294 | { | ||
1295 | struct exynos_drm_manager *mgr = get_mixer_manager(dev); | ||
1296 | |||
1297 | mixer_poweron(mgr); | ||
1298 | |||
1299 | return 0; | ||
1300 | } | ||
1301 | #endif | ||
1302 | |||
1303 | static const struct dev_pm_ops mixer_pm_ops = { | ||
1304 | SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume) | ||
1305 | SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL) | ||
1306 | }; | ||
1307 | |||
1308 | struct platform_driver mixer_driver = { | 1253 | struct platform_driver mixer_driver = { |
1309 | .driver = { | 1254 | .driver = { |
1310 | .name = "exynos-mixer", | 1255 | .name = "exynos-mixer", |
1311 | .owner = THIS_MODULE, | 1256 | .owner = THIS_MODULE, |
1312 | .pm = &mixer_pm_ops, | ||
1313 | .of_match_table = mixer_match_types, | 1257 | .of_match_table = mixer_match_types, |
1314 | }, | 1258 | }, |
1315 | .probe = mixer_probe, | 1259 | .probe = mixer_probe, |