drm/rockchip: vop: fix iommu crash when resume
authorMark Yao <mark.yao@rock-chips.com>
Thu, 19 Jan 2017 06:19:00 +0000 (14:19 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Thu, 19 Jan 2017 06:58:51 +0000 (14:58 +0800)
Iommu crash with that path:
   vop_disable:
      1, disable all windows and set vop config done
      2, vop enter to standy, all windows not works, but their registers
         are not clean, when you read window's enable bit, may found the
         window is enable.

   vop_enable:
      1, memcpy(vop->regsbak, vop->regs, len)
         save current vop registers to vop->regsbak, then you can found
         window is enable on regsbak.
      2, VOP_WIN_SET(vop, win, gate, 1);
         force enable window gate, but gate and enable is on same
         hardware register, the means window enable rewrite to vop hardware.
   then:
      when some on do vop_config_done but not reconfigure the bad
      register window, iommu crash.

Do register configure before memcpy(vop->regsbak, vop->regs, len) is not
safe, after that would be save.

Change-Id: I55b7846b1d39901c6b357fe541c9af1729b2c6b9
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/gpu/drm/rockchip/rockchip_drm_vop.c

index 959417b9c8ce6482fd570fe3f2724380d9f12d1a..a879bb79cb4862c2838030e1eba656ca3328f132 100644 (file)
@@ -793,15 +793,33 @@ static void vop_enable(struct drm_crtc *crtc)
        VOP_CTRL_SET(vop, global_regdone_en, 1);
        VOP_CTRL_SET(vop, dsp_blank, 0);
 
+       /*
+        * We need to make sure that all windows are disabled before resume
+        * the crtc. Otherwise we might try to scan from a destroyed
+        * buffer later.
+        */
        for (i = 0; i < vop->num_wins; i++) {
                struct vop_win *win = &vop->win[i];
 
+               if (win->phy->scl && win->phy->scl->ext) {
+                       VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE);
+                       VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE);
+                       VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE);
+                       VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE);
+               }
+               VOP_WIN_SET(vop, win, enable, 0);
                VOP_WIN_SET(vop, win, gate, 1);
        }
+       VOP_CTRL_SET(vop, afbdc_en, 0);
+       vop_cfg_done(vop);
+
        vop->is_enabled = true;
 
        spin_lock(&vop->reg_lock);
 
+       /*
+        * enable vop, all the register would take effect when vop exit standby
+        */
        VOP_CTRL_SET(vop, standby, 0);
 
        spin_unlock(&vop->reg_lock);
@@ -821,28 +839,6 @@ err_disable_hclk:
 static void vop_crtc_disable(struct drm_crtc *crtc)
 {
        struct vop *vop = to_vop(crtc);
-       int i;
-
-       /*
-        * We need to make sure that all windows are disabled before we
-        * disable that crtc. Otherwise we might try to scan from a destroyed
-        * buffer later.
-        */
-       for (i = 0; i < vop->num_wins; i++) {
-               struct vop_win *win = &vop->win[i];
-
-               spin_lock(&vop->reg_lock);
-               if (win->phy->scl && win->phy->scl->ext) {
-                       VOP_SCL_SET_EXT(vop, win, yrgb_hor_scl_mode, SCALE_NONE);
-                       VOP_SCL_SET_EXT(vop, win, yrgb_ver_scl_mode, SCALE_NONE);
-                       VOP_SCL_SET_EXT(vop, win, cbcr_hor_scl_mode, SCALE_NONE);
-                       VOP_SCL_SET_EXT(vop, win, cbcr_ver_scl_mode, SCALE_NONE);
-               }
-               VOP_WIN_SET(vop, win, enable, 0);
-               spin_unlock(&vop->reg_lock);
-       }
-       VOP_CTRL_SET(vop, afbdc_en, 0);
-       vop_cfg_done(vop);
 
        drm_crtc_vblank_off(crtc);