aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArchit Taneja <architt@codeaurora.org>2017-07-28 06:47:01 -0400
committerRob Clark <robdclark@gmail.com>2017-08-02 07:53:46 -0400
commitd68fe15b1878acf6a88367c360bc98b309a9270e (patch)
treefd285d6f25696bb5ae74cd35bb024fc145ae32b0
parent8f93e043d048b671c32c6f0a5102fefa800c4618 (diff)
drm/msm/mdp5: Use runtime PM get/put API instead of toggling clocks
mdp5_enable/disable calls are scattered all around in the MDP5 code. Use the pm_runtime_get/put calls here instead, and populate the runtime PM suspend/resume ops to manage the clocks. About the overall design: MDP5 is a child of the top level MDSS device. MDSS is also the parent to DSI, HDMI and other interfaces. When we enable MDP5's power domain, we end up enabling MDSS's PD too. It is only MDSS's PD that actually controlls the GDSC HW. Therefore, calling runtime_get/put on the MDP5 device is like just requesting a vote to enable/disable the GDSC. Functionally, replacing the clock enable/disable calls with the RPM API can result in the power domain (GDSC) state being toggled if no other child isn't powered on. This can result in the register context being lost. We make sure (in future commits) that code paths don't end up configuring registers and then later lose state, resulting in a bad HW state. For now, we've replaced each mdp5_enable/disable with runtime_get/put API. We could optimize things later by removing runtime_get/put calls which don't really need to be there. This could prevent unnecessary toggling of the power domain and clocks. Signed-off-by: Archit Taneja <architt@codeaurora.org> Signed-off-by: Rob Clark <robdclark@gmail.com>
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c7
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c21
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c7
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c27
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c49
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h3
6 files changed, 78 insertions, 36 deletions
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
index aa7402e03f67..60790df91bfa 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_cmd_encoder.c
@@ -192,6 +192,7 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
192{ 192{
193 struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder); 193 struct mdp5_encoder *mdp5_cmd_enc = to_mdp5_encoder(encoder);
194 struct mdp5_kms *mdp5_kms; 194 struct mdp5_kms *mdp5_kms;
195 struct device *dev;
195 int intf_num; 196 int intf_num;
196 u32 data = 0; 197 u32 data = 0;
197 198
@@ -214,14 +215,16 @@ int mdp5_cmd_encoder_set_split_display(struct drm_encoder *encoder,
214 /* Smart Panel, Sync mode */ 215 /* Smart Panel, Sync mode */
215 data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL; 216 data |= MDP5_SPLIT_DPL_UPPER_SMART_PANEL;
216 217
218 dev = &mdp5_kms->pdev->dev;
219
217 /* Make sure clocks are on when connectors calling this function. */ 220 /* Make sure clocks are on when connectors calling this function. */
218 mdp5_enable(mdp5_kms); 221 pm_runtime_get_sync(dev);
219 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data); 222 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, data);
220 223
221 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, 224 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER,
222 MDP5_SPLIT_DPL_LOWER_SMART_PANEL); 225 MDP5_SPLIT_DPL_LOWER_SMART_PANEL);
223 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1); 226 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_EN, 1);
224 mdp5_disable(mdp5_kms); 227 pm_runtime_put_autosuspend(dev);
225 228
226 return 0; 229 return 0;
227} 230}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index 735a87a699fa..aa9d56972e3d 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -414,6 +414,7 @@ static void mdp5_crtc_disable(struct drm_crtc *crtc)
414 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); 414 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
415 struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); 415 struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
416 struct mdp5_kms *mdp5_kms = get_kms(crtc); 416 struct mdp5_kms *mdp5_kms = get_kms(crtc);
417 struct device *dev = &mdp5_kms->pdev->dev;
417 418
418 DBG("%s", crtc->name); 419 DBG("%s", crtc->name);
419 420
@@ -424,7 +425,7 @@ static void mdp5_crtc_disable(struct drm_crtc *crtc)
424 mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done); 425 mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->pp_done);
425 426
426 mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err); 427 mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
427 mdp5_disable(mdp5_kms); 428 pm_runtime_put_autosuspend(dev);
428 429
429 mdp5_crtc->enabled = false; 430 mdp5_crtc->enabled = false;
430} 431}
@@ -434,13 +435,14 @@ static void mdp5_crtc_enable(struct drm_crtc *crtc)
434 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc); 435 struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
435 struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state); 436 struct mdp5_crtc_state *mdp5_cstate = to_mdp5_crtc_state(crtc->state);
436 struct mdp5_kms *mdp5_kms = get_kms(crtc); 437 struct mdp5_kms *mdp5_kms = get_kms(crtc);
438 struct device *dev = &mdp5_kms->pdev->dev;
437 439
438 DBG("%s", crtc->name); 440 DBG("%s", crtc->name);
439 441
440 if (WARN_ON(mdp5_crtc->enabled)) 442 if (WARN_ON(mdp5_crtc->enabled))
441 return; 443 return;
442 444
443 mdp5_enable(mdp5_kms); 445 pm_runtime_get_sync(dev);
444 mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err); 446 mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
445 447
446 if (mdp5_cstate->cmd_mode) 448 if (mdp5_cstate->cmd_mode)
@@ -725,6 +727,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
725 struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline; 727 struct mdp5_pipeline *pipeline = &mdp5_cstate->pipeline;
726 struct drm_device *dev = crtc->dev; 728 struct drm_device *dev = crtc->dev;
727 struct mdp5_kms *mdp5_kms = get_kms(crtc); 729 struct mdp5_kms *mdp5_kms = get_kms(crtc);
730 struct platform_device *pdev = mdp5_kms->pdev;
728 struct msm_kms *kms = &mdp5_kms->base.base; 731 struct msm_kms *kms = &mdp5_kms->base.base;
729 struct drm_gem_object *cursor_bo, *old_bo = NULL; 732 struct drm_gem_object *cursor_bo, *old_bo = NULL;
730 uint32_t blendcfg, stride; 733 uint32_t blendcfg, stride;
@@ -753,7 +756,7 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
753 if (!handle) { 756 if (!handle) {
754 DBG("Cursor off"); 757 DBG("Cursor off");
755 cursor_enable = false; 758 cursor_enable = false;
756 mdp5_enable(mdp5_kms); 759 pm_runtime_get_sync(&pdev->dev);
757 goto set_cursor; 760 goto set_cursor;
758 } 761 }
759 762
@@ -768,6 +771,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
768 lm = mdp5_cstate->pipeline.mixer->lm; 771 lm = mdp5_cstate->pipeline.mixer->lm;
769 stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0); 772 stride = width * drm_format_plane_cpp(DRM_FORMAT_ARGB8888, 0);
770 773
774 pm_runtime_get_sync(&pdev->dev);
775
771 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); 776 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
772 old_bo = mdp5_crtc->cursor.scanout_bo; 777 old_bo = mdp5_crtc->cursor.scanout_bo;
773 778
@@ -777,8 +782,6 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
777 782
778 get_roi(crtc, &roi_w, &roi_h); 783 get_roi(crtc, &roi_w, &roi_h);
779 784
780 mdp5_enable(mdp5_kms);
781
782 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride); 785 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
783 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm), 786 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
784 MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888)); 787 MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
@@ -796,6 +799,8 @@ static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
796 799
797 spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags); 800 spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
798 801
802 pm_runtime_put_autosuspend(&pdev->dev);
803
799set_cursor: 804set_cursor:
800 ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable); 805 ret = mdp5_ctl_set_cursor(ctl, pipeline, 0, cursor_enable);
801 if (ret) { 806 if (ret) {
@@ -807,7 +812,7 @@ set_cursor:
807 crtc_flush(crtc, flush_mask); 812 crtc_flush(crtc, flush_mask);
808 813
809end: 814end:
810 mdp5_disable(mdp5_kms); 815 pm_runtime_put_autosuspend(&pdev->dev);
811 if (old_bo) { 816 if (old_bo) {
812 drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo); 817 drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
813 /* enable vblank to complete cursor work: */ 818 /* enable vblank to complete cursor work: */
@@ -840,7 +845,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
840 845
841 get_roi(crtc, &roi_w, &roi_h); 846 get_roi(crtc, &roi_w, &roi_h);
842 847
843 mdp5_enable(mdp5_kms); 848 pm_runtime_get_sync(&mdp5_kms->pdev->dev);
844 849
845 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags); 850 spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
846 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm), 851 mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
@@ -853,7 +858,7 @@ static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
853 858
854 crtc_flush(crtc, flush_mask); 859 crtc_flush(crtc, flush_mask);
855 860
856 mdp5_disable(mdp5_kms); 861 pm_runtime_put_autosuspend(&mdp5_kms->pdev->dev);
857 862
858 return 0; 863 return 0;
859} 864}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index 70bef51245af..0ca9e4033bb6 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -350,6 +350,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
350 struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder); 350 struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
351 struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder); 351 struct mdp5_encoder *mdp5_slave_enc = to_mdp5_encoder(slave_encoder);
352 struct mdp5_kms *mdp5_kms; 352 struct mdp5_kms *mdp5_kms;
353 struct device *dev;
353 int intf_num; 354 int intf_num;
354 u32 data = 0; 355 u32 data = 0;
355 356
@@ -369,8 +370,10 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
369 else 370 else
370 return -EINVAL; 371 return -EINVAL;
371 372
373 dev = &mdp5_kms->pdev->dev;
372 /* Make sure clocks are on when connectors calling this function. */ 374 /* Make sure clocks are on when connectors calling this function. */
373 mdp5_enable(mdp5_kms); 375 pm_runtime_get_sync(dev);
376
374 /* Dumb Panel, Sync mode */ 377 /* Dumb Panel, Sync mode */
375 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0); 378 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_UPPER, 0);
376 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data); 379 mdp5_write(mdp5_kms, REG_MDP5_SPLIT_DPL_LOWER, data);
@@ -378,7 +381,7 @@ int mdp5_vid_encoder_set_split_display(struct drm_encoder *encoder,
378 381
379 mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true); 382 mdp5_ctl_pair(mdp5_encoder->ctl, mdp5_slave_enc->ctl, true);
380 383
381 mdp5_disable(mdp5_kms); 384 pm_runtime_put_autosuspend(dev);
382 385
383 return 0; 386 return 0;
384} 387}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
index 3ce8b9dec9c1..bb5deb00c899 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
@@ -49,16 +49,19 @@ static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
49void mdp5_irq_preinstall(struct msm_kms *kms) 49void mdp5_irq_preinstall(struct msm_kms *kms)
50{ 50{
51 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 51 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
52 mdp5_enable(mdp5_kms); 52 struct device *dev = &mdp5_kms->pdev->dev;
53
54 pm_runtime_get_sync(dev);
53 mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff); 55 mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
54 mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); 56 mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
55 mdp5_disable(mdp5_kms); 57 pm_runtime_put_autosuspend(dev);
56} 58}
57 59
58int mdp5_irq_postinstall(struct msm_kms *kms) 60int mdp5_irq_postinstall(struct msm_kms *kms)
59{ 61{
60 struct mdp_kms *mdp_kms = to_mdp_kms(kms); 62 struct mdp_kms *mdp_kms = to_mdp_kms(kms);
61 struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms); 63 struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
64 struct device *dev = &mdp5_kms->pdev->dev;
62 struct mdp_irq *error_handler = &mdp5_kms->error_handler; 65 struct mdp_irq *error_handler = &mdp5_kms->error_handler;
63 66
64 error_handler->irq = mdp5_irq_error_handler; 67 error_handler->irq = mdp5_irq_error_handler;
@@ -67,9 +70,9 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
67 MDP5_IRQ_INTF2_UNDER_RUN | 70 MDP5_IRQ_INTF2_UNDER_RUN |
68 MDP5_IRQ_INTF3_UNDER_RUN; 71 MDP5_IRQ_INTF3_UNDER_RUN;
69 72
70 mdp5_enable(mdp5_kms); 73 pm_runtime_get_sync(dev);
71 mdp_irq_register(mdp_kms, error_handler); 74 mdp_irq_register(mdp_kms, error_handler);
72 mdp5_disable(mdp5_kms); 75 pm_runtime_put_autosuspend(dev);
73 76
74 return 0; 77 return 0;
75} 78}
@@ -77,9 +80,11 @@ int mdp5_irq_postinstall(struct msm_kms *kms)
77void mdp5_irq_uninstall(struct msm_kms *kms) 80void mdp5_irq_uninstall(struct msm_kms *kms)
78{ 81{
79 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 82 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
80 mdp5_enable(mdp5_kms); 83 struct device *dev = &mdp5_kms->pdev->dev;
84
85 pm_runtime_get_sync(dev);
81 mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000); 86 mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
82 mdp5_disable(mdp5_kms); 87 pm_runtime_put_autosuspend(dev);
83} 88}
84 89
85irqreturn_t mdp5_irq(struct msm_kms *kms) 90irqreturn_t mdp5_irq(struct msm_kms *kms)
@@ -109,11 +114,12 @@ irqreturn_t mdp5_irq(struct msm_kms *kms)
109int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) 114int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
110{ 115{
111 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 116 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
117 struct device *dev = &mdp5_kms->pdev->dev;
112 118
113 mdp5_enable(mdp5_kms); 119 pm_runtime_get_sync(dev);
114 mdp_update_vblank_mask(to_mdp_kms(kms), 120 mdp_update_vblank_mask(to_mdp_kms(kms),
115 mdp5_crtc_vblank(crtc), true); 121 mdp5_crtc_vblank(crtc), true);
116 mdp5_disable(mdp5_kms); 122 pm_runtime_put_autosuspend(dev);
117 123
118 return 0; 124 return 0;
119} 125}
@@ -121,9 +127,10 @@ int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
121void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) 127void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
122{ 128{
123 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 129 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
130 struct device *dev = &mdp5_kms->pdev->dev;
124 131
125 mdp5_enable(mdp5_kms); 132 pm_runtime_get_sync(dev);
126 mdp_update_vblank_mask(to_mdp_kms(kms), 133 mdp_update_vblank_mask(to_mdp_kms(kms),
127 mdp5_crtc_vblank(crtc), false); 134 mdp5_crtc_vblank(crtc), false);
128 mdp5_disable(mdp5_kms); 135 pm_runtime_put_autosuspend(dev);
129} 136}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 1c603aef3c59..b0800bad8ac8 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -30,11 +30,10 @@ static const char *iommu_ports[] = {
30static int mdp5_hw_init(struct msm_kms *kms) 30static int mdp5_hw_init(struct msm_kms *kms)
31{ 31{
32 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 32 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
33 struct platform_device *pdev = mdp5_kms->pdev; 33 struct device *dev = &mdp5_kms->pdev->dev;
34 unsigned long flags; 34 unsigned long flags;
35 35
36 pm_runtime_get_sync(&pdev->dev); 36 pm_runtime_get_sync(dev);
37 mdp5_enable(mdp5_kms);
38 37
39 /* Magic unknown register writes: 38 /* Magic unknown register writes:
40 * 39 *
@@ -66,8 +65,7 @@ static int mdp5_hw_init(struct msm_kms *kms)
66 65
67 mdp5_ctlm_hw_reset(mdp5_kms->ctlm); 66 mdp5_ctlm_hw_reset(mdp5_kms->ctlm);
68 67
69 mdp5_disable(mdp5_kms); 68 pm_runtime_put_sync(dev);
70 pm_runtime_put_sync(&pdev->dev);
71 69
72 return 0; 70 return 0;
73} 71}
@@ -111,8 +109,9 @@ static void mdp5_swap_state(struct msm_kms *kms, struct drm_atomic_state *state)
111static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state) 109static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
112{ 110{
113 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 111 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
112 struct device *dev = &mdp5_kms->pdev->dev;
114 113
115 mdp5_enable(mdp5_kms); 114 pm_runtime_get_sync(dev);
116 115
117 if (mdp5_kms->smp) 116 if (mdp5_kms->smp)
118 mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp); 117 mdp5_smp_prepare_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
@@ -121,11 +120,12 @@ static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *st
121static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state) 120static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
122{ 121{
123 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms)); 122 struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
123 struct device *dev = &mdp5_kms->pdev->dev;
124 124
125 if (mdp5_kms->smp) 125 if (mdp5_kms->smp)
126 mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp); 126 mdp5_smp_complete_commit(mdp5_kms->smp, &mdp5_kms->state->smp);
127 127
128 mdp5_disable(mdp5_kms); 128 pm_runtime_put_autosuspend(dev);
129} 129}
130 130
131static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms, 131static void mdp5_wait_for_crtc_commit_done(struct msm_kms *kms,
@@ -486,11 +486,12 @@ fail:
486static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms, 486static void read_mdp_hw_revision(struct mdp5_kms *mdp5_kms,
487 u32 *major, u32 *minor) 487 u32 *major, u32 *minor)
488{ 488{
489 struct device *dev = &mdp5_kms->pdev->dev;
489 u32 version; 490 u32 version;
490 491
491 mdp5_enable(mdp5_kms); 492 pm_runtime_get_sync(dev);
492 version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION); 493 version = mdp5_read(mdp5_kms, REG_MDP5_HW_VERSION);
493 mdp5_disable(mdp5_kms); 494 pm_runtime_put_autosuspend(dev);
494 495
495 *major = FIELD(version, MDP5_HW_VERSION_MAJOR); 496 *major = FIELD(version, MDP5_HW_VERSION_MAJOR);
496 *minor = FIELD(version, MDP5_HW_VERSION_MINOR); 497 *minor = FIELD(version, MDP5_HW_VERSION_MINOR);
@@ -643,7 +644,7 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
643 * have left things on, in which case we'll start getting faults if 644 * have left things on, in which case we'll start getting faults if
644 * we don't disable): 645 * we don't disable):
645 */ 646 */
646 mdp5_enable(mdp5_kms); 647 pm_runtime_get_sync(&pdev->dev);
647 for (i = 0; i < MDP5_INTF_NUM_MAX; i++) { 648 for (i = 0; i < MDP5_INTF_NUM_MAX; i++) {
648 if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) || 649 if (mdp5_cfg_intf_is_virtual(config->hw->intf.connect[i]) ||
649 !config->hw->intf.base[i]) 650 !config->hw->intf.base[i])
@@ -652,7 +653,6 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
652 653
653 mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3); 654 mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(i), 0x3);
654 } 655 }
655 mdp5_disable(mdp5_kms);
656 mdelay(16); 656 mdelay(16);
657 657
658 if (config->platform.iommu) { 658 if (config->platform.iommu) {
@@ -678,6 +678,8 @@ struct msm_kms *mdp5_kms_init(struct drm_device *dev)
678 aspace = NULL;; 678 aspace = NULL;;
679 } 679 }
680 680
681 pm_runtime_put_autosuspend(&pdev->dev);
682
681 ret = modeset_init(mdp5_kms); 683 ret = modeset_init(mdp5_kms);
682 if (ret) { 684 if (ret) {
683 dev_err(&pdev->dev, "modeset_init failed: %d\n", ret); 685 dev_err(&pdev->dev, "modeset_init failed: %d\n", ret);
@@ -1005,6 +1007,30 @@ static int mdp5_dev_remove(struct platform_device *pdev)
1005 return 0; 1007 return 0;
1006} 1008}
1007 1009
1010static int mdp5_runtime_suspend(struct device *dev)
1011{
1012 struct platform_device *pdev = to_platform_device(dev);
1013 struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
1014
1015 DBG("");
1016
1017 return mdp5_disable(mdp5_kms);
1018}
1019
1020static int mdp5_runtime_resume(struct device *dev)
1021{
1022 struct platform_device *pdev = to_platform_device(dev);
1023 struct mdp5_kms *mdp5_kms = platform_get_drvdata(pdev);
1024
1025 DBG("");
1026
1027 return mdp5_enable(mdp5_kms);
1028}
1029
1030static const struct dev_pm_ops mdp5_pm_ops = {
1031 SET_RUNTIME_PM_OPS(mdp5_runtime_suspend, mdp5_runtime_resume, NULL)
1032};
1033
1008static const struct of_device_id mdp5_dt_match[] = { 1034static const struct of_device_id mdp5_dt_match[] = {
1009 { .compatible = "qcom,mdp5", }, 1035 { .compatible = "qcom,mdp5", },
1010 /* to support downstream DT files */ 1036 /* to support downstream DT files */
@@ -1019,6 +1045,7 @@ static struct platform_driver mdp5_driver = {
1019 .driver = { 1045 .driver = {
1020 .name = "msm_mdp", 1046 .name = "msm_mdp",
1021 .of_match_table = mdp5_dt_match, 1047 .of_match_table = mdp5_dt_match,
1048 .pm = &mdp5_pm_ops,
1022 }, 1049 },
1023}; 1050};
1024 1051
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index 17caa0e8c8ae..b42461cda22d 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -255,9 +255,6 @@ static inline uint32_t lm2ppdone(struct mdp5_hw_mixer *mixer)
255 return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp; 255 return MDP5_IRQ_PING_PONG_0_DONE << mixer->pp;
256} 256}
257 257
258int mdp5_disable(struct mdp5_kms *mdp5_kms);
259int mdp5_enable(struct mdp5_kms *mdp5_kms);
260
261void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask, 258void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask,
262 uint32_t old_irqmask); 259 uint32_t old_irqmask);
263void mdp5_irq_preinstall(struct msm_kms *kms); 260void mdp5_irq_preinstall(struct msm_kms *kms);