rockchip: rk3399: check vop status when we wait dma finish flag
authorLin Huang <hl@rock-chips.com>
Thu, 1 Dec 2016 08:55:05 +0000 (16:55 +0800)
committerXing Zheng <zhengxing@rock-chips.com>
Fri, 24 Feb 2017 12:07:44 +0000 (20:07 +0800)
When vop is disabled and we read the vop register the system will
hang, so check vop status when we wait for the DMA finish flag to
avoid this sitiuation. This is done by checking for standby, DMA stop
mode, and disabled window states. Any one of these will prevent the
DMA finish flag from triggering.

Signed-off-by: Lin Huang <hl@rock-chips.com>
Signed-off-by: Derek Basehore <dbasehore@chromium.org>
plat/rockchip/rk3399/drivers/m0/src/dram.c

index 79452c9aa937076903497261c96f630d529646aa..6f351a42fedca9ae85532a2e17ed45d9358fe863 100644 (file)
 /* VOP */
 #define VOP_SYS_CTRL           0x8
 #define VOP_SYS_CTRL1          0xc
+#define VOP_WIN0_CTRL0         0x30
 #define        VOP_INTR_CLEAR0         0x284
 #define VOP_INTR_RAW_STATUS0   0x28c
 
 /* VOP_SYS_CTRL */
+#define VOP_DMA_STOP_EN                (1 << 21)
 #define VOP_STANDBY_EN         (1 << 22)
 
+/* VOP_WIN0_CTRL0 */
+#define WB_ENABLE              (1 << 0)
+
 /* VOP_INTR_CLEAR0 */
 #define        INT_CLR_DMA_FINISH      (1 << 15)
 #define INT_CLR_LINE_FLAG1     (1 << 4)
 #define CIC_CTRL1              0x4
 #define CIC_STATUS0            0x10
 
-struct ddr_freq_param {
-       uint32_t vop_big_en;
-       uint32_t vop_lit_en;
-       uint32_t dclk0_div;
-       uint32_t dclk1_div;
-};
-
-static struct ddr_freq_param rk3399_ddr_arg;
-
-static void get_vop_status(void)
+static inline int check_dma_status(uint32_t vop_addr, uint32_t *clr_dma_flag)
 {
-       rk3399_ddr_arg.vop_big_en = 0;
-       rk3399_ddr_arg.vop_lit_en = 0;
-
-       if ((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) & PD_VOP_PWR_STAT) == 0) {
-               /* get vop0 status */
-               if ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE10_CON) &
-                                 (DCLK_VOP0_SRC_EN | ACLK_VOP0_PRE_SRC_EN |
-                                  HCLK_VOP0_PRE_EN)) == 0)
-                       if ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE28_CON) &
-                                        (HCLK_VOP0_EN | ACLK_VOP0_EN)) == 0)
-                               if ((mmio_read_32(VOP_BIG_BASE_ADDR +
-                                                 VOP_SYS_CTRL) &
-                                                 VOP_STANDBY_EN) == 0)
-                                       rk3399_ddr_arg.vop_big_en = 1;
-
-               /* get vop1 satus */
-               if ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE10_CON) &
-                                 (DCLK_VOP1_SRC_EN | ACLK_VOP1_PRE_SRC_EN |
-                                  HCLK_VOP1_PRE_EN)) == 0)
-                       if ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE28_CON) &
-                                         (HCLK_VOP1_EN | ACLK_VOP1_EN)) == 0)
-                               if ((mmio_read_32(VOP_LITE_BASE_ADDR +
-                                                 VOP_SYS_CTRL) &
-                                                 VOP_STANDBY_EN) == 0)
-                                       rk3399_ddr_arg.vop_lit_en = 1;
+       if (*clr_dma_flag) {
+               mmio_write_32(vop_addr + VOP_INTR_CLEAR0, 0x80008000);
+               *clr_dma_flag = 0;
        }
-}
-
-static void wait_vop_dma_finish(void)
-{
-       uint32_t vop_adr;
 
-       get_vop_status();
+       if ((mmio_read_32(vop_addr + VOP_SYS_CTRL) &
+            (VOP_STANDBY_EN | VOP_DMA_STOP_EN)) ||
+           !(mmio_read_32(vop_addr + VOP_WIN0_CTRL0) & WB_ENABLE) ||
+           (mmio_read_32(vop_addr + VOP_INTR_RAW_STATUS0) &
+           INT_RAW_STATUS_DMA_FINISH))
+               return 1;
 
-       if (rk3399_ddr_arg.vop_big_en)
-               vop_adr = VOP_BIG_BASE_ADDR;
-       else if (rk3399_ddr_arg.vop_lit_en)
-               vop_adr = VOP_LITE_BASE_ADDR;
-       else
-               return;
+       return 0;
+}
 
-       /* clean dma finish irq and wait for it */
-       mmio_write_32(vop_adr + VOP_INTR_CLEAR0,
-                     INT_CLR_DMA_FINISH | (INT_CLR_DMA_FINISH << 16));
+static int wait_vop_dma_finish(void)
+{
+       uint32_t clr_dma_flag = 1;
+       uint32_t ret = 0;
+
+       stopwatch_init_usecs_expire(60000);
+       while (((mmio_read_32(PMU_BASE + PMU_PWRDN_ST) &
+               PD_VOP_PWR_STAT) == 0)) {
+               /*
+                * VOPL case:
+                * CRU_CLKGATE10_CON(bit10): ACLK_VOP1_PRE_SRC_EN
+                * CRU_CLKGATE10_CON(bit11): HCLK_VOP1_PRE_EN
+                * CRU_CLKGATE10_CON(bit13): DCLK_VOP1_SRC_EN
+                * CRU_CLKGATE28_CON(bit7): ACLK_VOP1_EN
+                * CRU_CLKGATE28_CON(bit6): HCLK_VOP1_EN
+                *
+                * VOPB case:
+                * CRU_CLKGATE10_CON(bit8): ACLK_VOP0_PRE_SRC_EN
+                * CRU_CLKGATE10_CON(bit9): HCLK_VOP0_PRE_EN
+                * CRU_CLKGATE10_CON(bit12): DCLK_VOP0_SRC_EN
+                * CRU_CLKGATE28_CON(bit3): ACLK_VOP0_EN
+                * CRU_CLKGATE28_CON(bit2): HCLK_VOP0_EN
+                */
+               if (((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE10_CON) &
+                     0x2c00) == 0) &&
+                   ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE28_CON) &
+                     0xc0) == 0)) {
+                       if (check_dma_status(VOP_LITE_BASE_ADDR, &clr_dma_flag))
+                               return;
+               } else if (((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE10_CON) &
+                            0x1300) == 0) &&
+                          ((mmio_read_32(CRU_BASE_ADDR + CRU_CLKGATE28_CON) &
+                            0x0c) == 0)) {
+                       if (check_dma_status(VOP_BIG_BASE_ADDR, &clr_dma_flag))
+                               return;
+               } else {
+                       /* No VOPs are enabled, so don't wait. */
+                       return;
+               }
+
+               if (stopwatch_expired()) {
+                       ret = 1;
+                       goto out;
+               }
+       }
 
-       while ((mmio_read_32(vop_adr + VOP_INTR_RAW_STATUS0) &
-               INT_RAW_STATUS_DMA_FINISH) == 0)
-               ;
+out:
+       stopwatch_reset();
+       return ret;
 }
 
 static void idle_port(void)
@@ -207,6 +219,7 @@ static void ddr_set_pll(void)
 void handle_dram(void)
 {
        wait_vop_dma_finish();
+
        idle_port();
 
        mmio_write_32(CIC_BASE_ADDR + CIC_CTRL0,