aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLiviu Dudau <Liviu.Dudau@arm.com>2017-03-22 06:44:57 -0400
committerLiviu Dudau <Liviu.Dudau@arm.com>2017-04-24 05:45:33 -0400
commit85f6421889eca68ceb0a0403c4c00b2eaf3c16e0 (patch)
treed010c422ee0fbe187dc7c42e1326d66ce910e412
parent46f1d42f273836a3b8840637b9ee3d98a528ffd2 (diff)
drm: mali-dp: Enable power management for the device.
Enable runtime and system Power Management. Clocks are now managed from malidp_crtc_{enable,disable} functions. Suspend-to-RAM tested as working on Juno. Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
-rw-r--r--drivers/gpu/drm/arm/malidp_crtc.c14
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.c128
-rw-r--r--drivers/gpu/drm/arm/malidp_drv.h1
-rw-r--r--drivers/gpu/drm/arm/malidp_hw.h5
4 files changed, 125 insertions, 23 deletions
diff --git a/drivers/gpu/drm/arm/malidp_crtc.c b/drivers/gpu/drm/arm/malidp_crtc.c
index f9d665550d3e..fab776c37602 100644
--- a/drivers/gpu/drm/arm/malidp_crtc.c
+++ b/drivers/gpu/drm/arm/malidp_crtc.c
@@ -16,6 +16,7 @@
16#include <drm/drm_crtc.h> 16#include <drm/drm_crtc.h>
17#include <drm/drm_crtc_helper.h> 17#include <drm/drm_crtc_helper.h>
18#include <linux/clk.h> 18#include <linux/clk.h>
19#include <linux/pm_runtime.h>
19#include <video/videomode.h> 20#include <video/videomode.h>
20 21
21#include "malidp_drv.h" 22#include "malidp_drv.h"
@@ -58,9 +59,14 @@ static void malidp_crtc_enable(struct drm_crtc *crtc)
58 struct malidp_drm *malidp = crtc_to_malidp_device(crtc); 59 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
59 struct malidp_hw_device *hwdev = malidp->dev; 60 struct malidp_hw_device *hwdev = malidp->dev;
60 struct videomode vm; 61 struct videomode vm;
62 int err = pm_runtime_get_sync(crtc->dev->dev);
61 63
62 drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm); 64 if (err < 0) {
65 DRM_DEBUG_DRIVER("Failed to enable runtime power management: %d\n", err);
66 return;
67 }
63 68
69 drm_display_mode_to_videomode(&crtc->state->adjusted_mode, &vm);
64 clk_prepare_enable(hwdev->pxlclk); 70 clk_prepare_enable(hwdev->pxlclk);
65 71
66 /* We rely on firmware to set mclk to a sensible level. */ 72 /* We rely on firmware to set mclk to a sensible level. */
@@ -75,10 +81,16 @@ static void malidp_crtc_disable(struct drm_crtc *crtc)
75{ 81{
76 struct malidp_drm *malidp = crtc_to_malidp_device(crtc); 82 struct malidp_drm *malidp = crtc_to_malidp_device(crtc);
77 struct malidp_hw_device *hwdev = malidp->dev; 83 struct malidp_hw_device *hwdev = malidp->dev;
84 int err;
78 85
79 drm_crtc_vblank_off(crtc); 86 drm_crtc_vblank_off(crtc);
80 hwdev->enter_config_mode(hwdev); 87 hwdev->enter_config_mode(hwdev);
81 clk_disable_unprepare(hwdev->pxlclk); 88 clk_disable_unprepare(hwdev->pxlclk);
89
90 err = pm_runtime_put(crtc->dev->dev);
91 if (err < 0) {
92 DRM_DEBUG_DRIVER("Failed to disable runtime power management: %d\n", err);
93 }
82} 94}
83 95
84static int malidp_crtc_atomic_check(struct drm_crtc *crtc, 96static int malidp_crtc_atomic_check(struct drm_crtc *crtc,
diff --git a/drivers/gpu/drm/arm/malidp_drv.c b/drivers/gpu/drm/arm/malidp_drv.c
index 5442baf310c8..e954c22bb974 100644
--- a/drivers/gpu/drm/arm/malidp_drv.c
+++ b/drivers/gpu/drm/arm/malidp_drv.c
@@ -13,9 +13,11 @@
13#include <linux/module.h> 13#include <linux/module.h>
14#include <linux/clk.h> 14#include <linux/clk.h>
15#include <linux/component.h> 15#include <linux/component.h>
16#include <linux/console.h>
16#include <linux/of_device.h> 17#include <linux/of_device.h>
17#include <linux/of_graph.h> 18#include <linux/of_graph.h>
18#include <linux/of_reserved_mem.h> 19#include <linux/of_reserved_mem.h>
20#include <linux/pm_runtime.h>
19 21
20#include <drm/drmP.h> 22#include <drm/drmP.h>
21#include <drm/drm_atomic.h> 23#include <drm/drm_atomic.h>
@@ -91,6 +93,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
91{ 93{
92 struct drm_device *drm = state->dev; 94 struct drm_device *drm = state->dev;
93 95
96 pm_runtime_get_sync(drm->dev);
97
94 drm_atomic_helper_commit_modeset_disables(drm, state); 98 drm_atomic_helper_commit_modeset_disables(drm, state);
95 99
96 drm_atomic_helper_commit_planes(drm, state, 0); 100 drm_atomic_helper_commit_planes(drm, state, 0);
@@ -101,6 +105,8 @@ static void malidp_atomic_commit_tail(struct drm_atomic_state *state)
101 105
102 drm_atomic_helper_wait_for_vblanks(drm, state); 106 drm_atomic_helper_wait_for_vblanks(drm, state);
103 107
108 pm_runtime_put(drm->dev);
109
104 drm_atomic_helper_cleanup_planes(drm, state); 110 drm_atomic_helper_cleanup_planes(drm, state);
105} 111}
106 112
@@ -283,6 +289,37 @@ static bool malidp_has_sufficient_address_space(const struct resource *res,
283 289
284#define MAX_OUTPUT_CHANNELS 3 290#define MAX_OUTPUT_CHANNELS 3
285 291
292static int malidp_runtime_pm_suspend(struct device *dev)
293{
294 struct drm_device *drm = dev_get_drvdata(dev);
295 struct malidp_drm *malidp = drm->dev_private;
296 struct malidp_hw_device *hwdev = malidp->dev;
297
298 /* we can only suspend if the hardware is in config mode */
299 WARN_ON(!hwdev->in_config_mode(hwdev));
300
301 hwdev->pm_suspended = true;
302 clk_disable_unprepare(hwdev->mclk);
303 clk_disable_unprepare(hwdev->aclk);
304 clk_disable_unprepare(hwdev->pclk);
305
306 return 0;
307}
308
309static int malidp_runtime_pm_resume(struct device *dev)
310{
311 struct drm_device *drm = dev_get_drvdata(dev);
312 struct malidp_drm *malidp = drm->dev_private;
313 struct malidp_hw_device *hwdev = malidp->dev;
314
315 clk_prepare_enable(hwdev->pclk);
316 clk_prepare_enable(hwdev->aclk);
317 clk_prepare_enable(hwdev->mclk);
318 hwdev->pm_suspended = false;
319
320 return 0;
321}
322
286static int malidp_bind(struct device *dev) 323static int malidp_bind(struct device *dev)
287{ 324{
288 struct resource *res; 325 struct resource *res;
@@ -311,7 +348,6 @@ static int malidp_bind(struct device *dev)
311 memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev)); 348 memcpy(hwdev, of_device_get_match_data(dev), sizeof(*hwdev));
312 malidp->dev = hwdev; 349 malidp->dev = hwdev;
313 350
314
315 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 351 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
316 hwdev->regs = devm_ioremap_resource(dev, res); 352 hwdev->regs = devm_ioremap_resource(dev, res);
317 if (IS_ERR(hwdev->regs)) 353 if (IS_ERR(hwdev->regs))
@@ -344,14 +380,17 @@ static int malidp_bind(struct device *dev)
344 goto alloc_fail; 380 goto alloc_fail;
345 } 381 }
346 382
347 /* Enable APB clock in order to get access to the registers */ 383 drm->dev_private = malidp;
348 clk_prepare_enable(hwdev->pclk); 384 dev_set_drvdata(dev, drm);
349 /* 385
350 * Enable AXI clock and main clock so that prefetch can start once 386 /* Enable power management */
351 * the registers are set 387 pm_runtime_enable(dev);
352 */ 388
353 clk_prepare_enable(hwdev->aclk); 389 /* Resume device to enable the clocks */
354 clk_prepare_enable(hwdev->mclk); 390 if (pm_runtime_enabled(dev))
391 pm_runtime_get_sync(dev);
392 else
393 malidp_runtime_pm_resume(dev);
355 394
356 dev_id = of_match_device(malidp_drm_of_match, dev); 395 dev_id = of_match_device(malidp_drm_of_match, dev);
357 if (!dev_id) { 396 if (!dev_id) {
@@ -391,14 +430,12 @@ static int malidp_bind(struct device *dev)
391 out_depth = (out_depth << 8) | (output_width[i] & 0xf); 430 out_depth = (out_depth << 8) | (output_width[i] & 0xf);
392 malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base); 431 malidp_hw_write(hwdev, out_depth, hwdev->map.out_depth_base);
393 432
394 drm->dev_private = malidp;
395 dev_set_drvdata(dev, drm);
396 atomic_set(&malidp->config_valid, 0); 433 atomic_set(&malidp->config_valid, 0);
397 init_waitqueue_head(&malidp->wq); 434 init_waitqueue_head(&malidp->wq);
398 435
399 ret = malidp_init(drm); 436 ret = malidp_init(drm);
400 if (ret < 0) 437 if (ret < 0)
401 goto init_fail; 438 goto query_hw_fail;
402 439
403 /* Set the CRTC's port so that the encoder component can find it */ 440 /* Set the CRTC's port so that the encoder component can find it */
404 malidp->crtc.port = of_graph_get_port_by_id(dev->of_node, 0); 441 malidp->crtc.port = of_graph_get_port_by_id(dev->of_node, 0);
@@ -420,6 +457,7 @@ static int malidp_bind(struct device *dev)
420 DRM_ERROR("failed to initialise vblank\n"); 457 DRM_ERROR("failed to initialise vblank\n");
421 goto vblank_fail; 458 goto vblank_fail;
422 } 459 }
460 pm_runtime_put(dev);
423 461
424 drm_mode_config_reset(drm); 462 drm_mode_config_reset(drm);
425 463
@@ -445,7 +483,9 @@ register_fail:
445 drm_fbdev_cma_fini(malidp->fbdev); 483 drm_fbdev_cma_fini(malidp->fbdev);
446 malidp->fbdev = NULL; 484 malidp->fbdev = NULL;
447 } 485 }
486 drm_kms_helper_poll_fini(drm);
448fbdev_fail: 487fbdev_fail:
488 pm_runtime_get_sync(dev);
449 drm_vblank_cleanup(drm); 489 drm_vblank_cleanup(drm);
450vblank_fail: 490vblank_fail:
451 malidp_se_irq_fini(drm); 491 malidp_se_irq_fini(drm);
@@ -457,13 +497,14 @@ bind_fail:
457 of_node_put(malidp->crtc.port); 497 of_node_put(malidp->crtc.port);
458 malidp->crtc.port = NULL; 498 malidp->crtc.port = NULL;
459 malidp_fini(drm); 499 malidp_fini(drm);
460init_fail: 500query_hw_fail:
501 pm_runtime_put(dev);
502 if (pm_runtime_enabled(dev))
503 pm_runtime_disable(dev);
504 else
505 malidp_runtime_pm_suspend(dev);
461 drm->dev_private = NULL; 506 drm->dev_private = NULL;
462 dev_set_drvdata(dev, NULL); 507 dev_set_drvdata(dev, NULL);
463query_hw_fail:
464 clk_disable_unprepare(hwdev->mclk);
465 clk_disable_unprepare(hwdev->aclk);
466 clk_disable_unprepare(hwdev->pclk);
467 drm_dev_unref(drm); 508 drm_dev_unref(drm);
468alloc_fail: 509alloc_fail:
469 of_reserved_mem_device_release(dev); 510 of_reserved_mem_device_release(dev);
@@ -475,7 +516,6 @@ static void malidp_unbind(struct device *dev)
475{ 516{
476 struct drm_device *drm = dev_get_drvdata(dev); 517 struct drm_device *drm = dev_get_drvdata(dev);
477 struct malidp_drm *malidp = drm->dev_private; 518 struct malidp_drm *malidp = drm->dev_private;
478 struct malidp_hw_device *hwdev = malidp->dev;
479 519
480 drm_dev_unregister(drm); 520 drm_dev_unregister(drm);
481 if (malidp->fbdev) { 521 if (malidp->fbdev) {
@@ -483,18 +523,21 @@ static void malidp_unbind(struct device *dev)
483 malidp->fbdev = NULL; 523 malidp->fbdev = NULL;
484 } 524 }
485 drm_kms_helper_poll_fini(drm); 525 drm_kms_helper_poll_fini(drm);
526 pm_runtime_get_sync(dev);
527 drm_vblank_cleanup(drm);
486 malidp_se_irq_fini(drm); 528 malidp_se_irq_fini(drm);
487 malidp_de_irq_fini(drm); 529 malidp_de_irq_fini(drm);
488 drm_vblank_cleanup(drm);
489 component_unbind_all(dev, drm); 530 component_unbind_all(dev, drm);
490 of_node_put(malidp->crtc.port); 531 of_node_put(malidp->crtc.port);
491 malidp->crtc.port = NULL; 532 malidp->crtc.port = NULL;
492 malidp_fini(drm); 533 malidp_fini(drm);
534 pm_runtime_put(dev);
535 if (pm_runtime_enabled(dev))
536 pm_runtime_disable(dev);
537 else
538 malidp_runtime_pm_suspend(dev);
493 drm->dev_private = NULL; 539 drm->dev_private = NULL;
494 dev_set_drvdata(dev, NULL); 540 dev_set_drvdata(dev, NULL);
495 clk_disable_unprepare(hwdev->mclk);
496 clk_disable_unprepare(hwdev->aclk);
497 clk_disable_unprepare(hwdev->pclk);
498 drm_dev_unref(drm); 541 drm_dev_unref(drm);
499 of_reserved_mem_device_release(dev); 542 of_reserved_mem_device_release(dev);
500} 543}
@@ -537,11 +580,52 @@ static int malidp_platform_remove(struct platform_device *pdev)
537 return 0; 580 return 0;
538} 581}
539 582
583static int __maybe_unused malidp_pm_suspend(struct device *dev)
584{
585 struct drm_device *drm = dev_get_drvdata(dev);
586 struct malidp_drm *malidp = drm->dev_private;
587
588 drm_kms_helper_poll_disable(drm);
589 console_lock();
590 drm_fbdev_cma_set_suspend(malidp->fbdev, 1);
591 console_unlock();
592 malidp->pm_state = drm_atomic_helper_suspend(drm);
593 if (IS_ERR(malidp->pm_state)) {
594 console_lock();
595 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
596 console_unlock();
597 drm_kms_helper_poll_enable(drm);
598 return PTR_ERR(malidp->pm_state);
599 }
600
601 return 0;
602}
603
604static int __maybe_unused malidp_pm_resume(struct device *dev)
605{
606 struct drm_device *drm = dev_get_drvdata(dev);
607 struct malidp_drm *malidp = drm->dev_private;
608
609 drm_atomic_helper_resume(drm, malidp->pm_state);
610 console_lock();
611 drm_fbdev_cma_set_suspend(malidp->fbdev, 0);
612 console_unlock();
613 drm_kms_helper_poll_enable(drm);
614
615 return 0;
616}
617
618static const struct dev_pm_ops malidp_pm_ops = {
619 SET_SYSTEM_SLEEP_PM_OPS(malidp_pm_suspend, malidp_pm_resume) \
620 SET_RUNTIME_PM_OPS(malidp_runtime_pm_suspend, malidp_runtime_pm_resume, NULL)
621};
622
540static struct platform_driver malidp_platform_driver = { 623static struct platform_driver malidp_platform_driver = {
541 .probe = malidp_platform_probe, 624 .probe = malidp_platform_probe,
542 .remove = malidp_platform_remove, 625 .remove = malidp_platform_remove,
543 .driver = { 626 .driver = {
544 .name = "mali-dp", 627 .name = "mali-dp",
628 .pm = &malidp_pm_ops,
545 .of_match_table = malidp_drm_of_match, 629 .of_match_table = malidp_drm_of_match,
546 }, 630 },
547}; 631};
diff --git a/drivers/gpu/drm/arm/malidp_drv.h b/drivers/gpu/drm/arm/malidp_drv.h
index dbc617c6e4ef..cd4c04c65ead 100644
--- a/drivers/gpu/drm/arm/malidp_drv.h
+++ b/drivers/gpu/drm/arm/malidp_drv.h
@@ -24,6 +24,7 @@ struct malidp_drm {
24 struct drm_crtc crtc; 24 struct drm_crtc crtc;
25 wait_queue_head_t wq; 25 wait_queue_head_t wq;
26 atomic_t config_valid; 26 atomic_t config_valid;
27 struct drm_atomic_state *pm_state;
27}; 28};
28 29
29#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc) 30#define crtc_to_malidp_device(x) container_of(x, struct malidp_drm, crtc)
diff --git a/drivers/gpu/drm/arm/malidp_hw.h b/drivers/gpu/drm/arm/malidp_hw.h
index 00974b59407d..ea2dbae08990 100644
--- a/drivers/gpu/drm/arm/malidp_hw.h
+++ b/drivers/gpu/drm/arm/malidp_hw.h
@@ -156,6 +156,9 @@ struct malidp_hw_device {
156 u8 min_line_size; 156 u8 min_line_size;
157 u16 max_line_size; 157 u16 max_line_size;
158 158
159 /* track the device PM state */
160 bool pm_suspended;
161
159 /* size of memory used for rotating layers, up to two banks available */ 162 /* size of memory used for rotating layers, up to two banks available */
160 u32 rotation_memory[2]; 163 u32 rotation_memory[2];
161}; 164};
@@ -173,12 +176,14 @@ extern const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES];
173 176
174static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg) 177static inline u32 malidp_hw_read(struct malidp_hw_device *hwdev, u32 reg)
175{ 178{
179 WARN_ON(hwdev->pm_suspended);
176 return readl(hwdev->regs + reg); 180 return readl(hwdev->regs + reg);
177} 181}
178 182
179static inline void malidp_hw_write(struct malidp_hw_device *hwdev, 183static inline void malidp_hw_write(struct malidp_hw_device *hwdev,
180 u32 value, u32 reg) 184 u32 value, u32 reg)
181{ 185{
186 WARN_ON(hwdev->pm_suspended);
182 writel(value, hwdev->regs + reg); 187 writel(value, hwdev->regs + reg);
183} 188}
184 189