aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Yao <mark.yao@rock-chips.com>2015-02-04 00:10:31 -0500
committerMark Yao <mark.yao@rock-chips.com>2015-03-16 01:50:57 -0400
commit1067219b27e29e925e7bdbb85b72c4c2bec0267e (patch)
tree430c815856edad28881382ae06cbe655d05a0953
parent52ab7891fb8e45bda6015da8b5ac82ad600355e3 (diff)
drm/rockchip: vop: power off until vop standby take effect
Vop standby will take effect at end of current frame, if dsp_hold_valid_irq happen, it means vop standby complete. we must wait standby complete when we want to disable aclk, if not, memory bus maybe dead. Reviewed-by: Heiko Stuebner <heiko@sntech.de> Reviewed-by: Daniel Kurtz <djkurtz@chromium.org> Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c77
1 files changed, 64 insertions, 13 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 04b619a8d064..d041921b3bb9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -89,6 +89,7 @@ struct vop {
89 /* mutex vsync_ work */ 89 /* mutex vsync_ work */
90 struct mutex vsync_mutex; 90 struct mutex vsync_mutex;
91 bool vsync_work_pending; 91 bool vsync_work_pending;
92 struct completion dsp_hold_completion;
92 93
93 const struct vop_data *data; 94 const struct vop_data *data;
94 95
@@ -382,6 +383,36 @@ static bool is_alpha_support(uint32_t format)
382 } 383 }
383} 384}
384 385
386static void vop_dsp_hold_valid_irq_enable(struct vop *vop)
387{
388 unsigned long flags;
389
390 if (WARN_ON(!vop->is_enabled))
391 return;
392
393 spin_lock_irqsave(&vop->irq_lock, flags);
394
395 vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
396 DSP_HOLD_VALID_INTR_EN(1));
397
398 spin_unlock_irqrestore(&vop->irq_lock, flags);
399}
400
401static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
402{
403 unsigned long flags;
404
405 if (WARN_ON(!vop->is_enabled))
406 return;
407
408 spin_lock_irqsave(&vop->irq_lock, flags);
409
410 vop_mask_write(vop, INTR_CTRL0, DSP_HOLD_VALID_INTR_MASK,
411 DSP_HOLD_VALID_INTR_EN(0));
412
413 spin_unlock_irqrestore(&vop->irq_lock, flags);
414}
415
385static void vop_enable(struct drm_crtc *crtc) 416static void vop_enable(struct drm_crtc *crtc)
386{ 417{
387 struct vop *vop = to_vop(crtc); 418 struct vop *vop = to_vop(crtc);
@@ -454,26 +485,36 @@ static void vop_disable(struct drm_crtc *crtc)
454 485
455 drm_vblank_off(crtc->dev, vop->pipe); 486 drm_vblank_off(crtc->dev, vop->pipe);
456 487
457 disable_irq(vop->irq);
458
459 /* 488 /*
460 * TODO: Since standby doesn't take effect until the next vblank, 489 * Vop standby will take effect at end of current frame,
461 * when we turn off dclk below, the vop is probably still active. 490 * if dsp hold valid irq happen, it means standby complete.
491 *
492 * we must wait standby complete when we want to disable aclk,
493 * if not, memory bus maybe dead.
462 */ 494 */
495 reinit_completion(&vop->dsp_hold_completion);
496 vop_dsp_hold_valid_irq_enable(vop);
497
463 spin_lock(&vop->reg_lock); 498 spin_lock(&vop->reg_lock);
464 499
465 VOP_CTRL_SET(vop, standby, 1); 500 VOP_CTRL_SET(vop, standby, 1);
466 501
467 spin_unlock(&vop->reg_lock); 502 spin_unlock(&vop->reg_lock);
468 503
504 wait_for_completion(&vop->dsp_hold_completion);
505
506 vop_dsp_hold_valid_irq_disable(vop);
507
508 disable_irq(vop->irq);
509
469 vop->is_enabled = false; 510 vop->is_enabled = false;
511
470 /* 512 /*
471 * disable dclk to stop frame scan, so we can safely detach iommu, 513 * vop standby complete, so iommu detach is safe.
472 */ 514 */
473 clk_disable(vop->dclk);
474
475 rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev); 515 rockchip_drm_dma_detach_device(vop->drm_dev, vop->dev);
476 516
517 clk_disable(vop->dclk);
477 clk_disable(vop->aclk); 518 clk_disable(vop->aclk);
478 clk_disable(vop->hclk); 519 clk_disable(vop->hclk);
479} 520}
@@ -1086,6 +1127,7 @@ static irqreturn_t vop_isr(int irq, void *data)
1086 struct vop *vop = data; 1127 struct vop *vop = data;
1087 uint32_t intr0_reg, active_irqs; 1128 uint32_t intr0_reg, active_irqs;
1088 unsigned long flags; 1129 unsigned long flags;
1130 int ret = IRQ_NONE;
1089 1131
1090 /* 1132 /*
1091 * INTR_CTRL0 register has interrupt status, enable and clear bits, we 1133 * INTR_CTRL0 register has interrupt status, enable and clear bits, we
@@ -1104,15 +1146,23 @@ static irqreturn_t vop_isr(int irq, void *data)
1104 if (!active_irqs) 1146 if (!active_irqs)
1105 return IRQ_NONE; 1147 return IRQ_NONE;
1106 1148
1107 /* Only Frame Start Interrupt is enabled; other irqs are spurious. */ 1149 if (active_irqs & DSP_HOLD_VALID_INTR) {
1108 if (!(active_irqs & FS_INTR)) { 1150 complete(&vop->dsp_hold_completion);
1109 DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs); 1151 active_irqs &= ~DSP_HOLD_VALID_INTR;
1110 return IRQ_NONE; 1152 ret = IRQ_HANDLED;
1111 } 1153 }
1112 1154
1113 drm_handle_vblank(vop->drm_dev, vop->pipe); 1155 if (active_irqs & FS_INTR) {
1156 drm_handle_vblank(vop->drm_dev, vop->pipe);
1157 active_irqs &= ~FS_INTR;
1158 ret = (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED;
1159 }
1114 1160
1115 return (vop->vsync_work_pending) ? IRQ_WAKE_THREAD : IRQ_HANDLED; 1161 /* Unhandled irqs are spurious. */
1162 if (active_irqs)
1163 DRM_ERROR("Unknown VOP IRQs: %#02x\n", active_irqs);
1164
1165 return ret;
1116} 1166}
1117 1167
1118static int vop_create_crtc(struct vop *vop) 1168static int vop_create_crtc(struct vop *vop)
@@ -1194,6 +1244,7 @@ static int vop_create_crtc(struct vop *vop)
1194 goto err_cleanup_crtc; 1244 goto err_cleanup_crtc;
1195 } 1245 }
1196 1246
1247 init_completion(&vop->dsp_hold_completion);
1197 crtc->port = port; 1248 crtc->port = port;
1198 vop->pipe = drm_crtc_index(crtc); 1249 vop->pipe = drm_crtc_index(crtc);
1199 rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe); 1250 rockchip_register_crtc_funcs(drm_dev, &private_crtc_funcs, vop->pipe);