diff options
author | Mark Yao <mark.yao@rock-chips.com> | 2015-02-04 00:10:31 -0500 |
---|---|---|
committer | Mark Yao <mark.yao@rock-chips.com> | 2015-03-16 01:50:57 -0400 |
commit | 1067219b27e29e925e7bdbb85b72c4c2bec0267e (patch) | |
tree | 430c815856edad28881382ae06cbe655d05a0953 | |
parent | 52ab7891fb8e45bda6015da8b5ac82ad600355e3 (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.c | 77 |
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 | ||
386 | static 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 | |||
401 | static 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 | |||
385 | static void vop_enable(struct drm_crtc *crtc) | 416 | static 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 | ||
1118 | static int vop_create_crtc(struct vop *vop) | 1168 | static 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); |