rk_vop: rk3288: fix kernel logo crash with iommu enable
authorMark Yao <mark.yao@rock-chips.com>
Thu, 9 Jul 2015 10:03:09 +0000 (18:03 +0800)
committerMark Yao <mark.yao@rock-chips.com>
Thu, 9 Jul 2015 10:04:28 +0000 (18:04 +0800)
Signed-off-by: Mark Yao <mark.yao@rock-chips.com>
drivers/video/rockchip/lcdc/rk3288_lcdc.c
drivers/video/rockchip/lcdc/rk3288_lcdc.h

index 6ef06dbe53addb71fc2b55c7fc7444dfb5dfdc76..bdc75e36a26b2dc7dc9c6be140258d28ea53ff48 100755 (executable)
@@ -371,8 +371,8 @@ static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
                dev_err(lcdc_dev->dev, "failed to get lcdc%d clk source\n",
                        lcdc_dev->id);
        }
-
-       rk_disp_pwr_enable(dev_drv);
+       if (!support_uboot_display())
+               rk_disp_pwr_enable(dev_drv);
        rk3288_lcdc_clk_enable(lcdc_dev);
 
        /*backup reg config at uboot*/
@@ -405,8 +405,9 @@ static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
        val  =  v_AUTO_GATING_EN(0);
        lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask,val);
        lcdc_cfg_done(lcdc_dev);
-       if (dev_drv->iommu_enabled) /*disable win0 to workaround iommu pagefault*/
-               win0_enable(lcdc_dev, 0);
+       /*disable win0 to workaround iommu pagefault */
+       /*if (dev_drv->iommu_enabled) */
+       /*      win0_enable(lcdc_dev, 0); */
        lcdc_dev->pre_init = true;
 
 
@@ -1021,10 +1022,7 @@ static int rk3288_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
 
 static int rk3288_lcdc_reg_restore(struct lcdc_device *lcdc_dev)
 {
-       if (lcdc_dev->driver.iommu_enabled)
-               memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x330);
-       else
-               memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x1fc);
+       memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x1fc);
        return 0;
 }
 static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
@@ -1037,30 +1035,40 @@ static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
                pr_info("%s,clk_on = %d\n", __func__, lcdc_dev->clk_on);
                return 0;
        }
-       spin_lock(&lcdc_dev->reg_lock);
-       if (likely(lcdc_dev->clk_on)) {
-               mask = m_MMU_EN;
-               val = v_MMU_EN(1);
-               lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
-               mask = m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;
-               val = v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1);
-               lcdc_msk_reg(lcdc_dev, SYS_CTRL1, mask, val);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       if (dev_drv->iommu_enabled) {
+               if (!lcdc_dev->iommu_status && dev_drv->mmu_dev) {
+
+               if (likely(lcdc_dev->clk_on)) {
+                       spin_lock(&lcdc_dev->reg_lock);
+                       mask = m_MMU_EN;
+                       val = v_MMU_EN(1);
+                       lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
+                       mask = m_AXI_MAX_OUTSTANDING_EN | m_AXI_OUTSTANDING_MAX_NUM;
+                       val = v_AXI_OUTSTANDING_MAX_NUM(31) | v_AXI_MAX_OUTSTANDING_EN(1);
+                       lcdc_msk_reg(lcdc_dev, SYS_CTRL1, mask, val);
+                       spin_unlock(&lcdc_dev->reg_lock);
+       }
+                       lcdc_dev->iommu_status = 1;
+                       rockchip_iovmm_activate(dev_drv->dev);
+               }
        }
-       spin_unlock(&lcdc_dev->reg_lock);
+#endif
        return 0;
 }
 
-static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
+static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv, int reset_rate)
 {
 #ifdef CONFIG_RK_FPGA
        return 0;
 #endif
-       int ret,fps;
+       int ret = 0,fps;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        struct rk_screen *screen = dev_drv->cur_screen;
 
-       ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock);
+        if (reset_rate)
+               ret = clk_set_rate(lcdc_dev->dclk, screen->mode.pixclock);/*set pll */
        if (ret)
                dev_err(dev_drv->dev, "set lcdc%d dclk failed\n", lcdc_dev->id);
        lcdc_dev->pixclock =
@@ -1287,9 +1295,12 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                lcdc_msk_reg(lcdc_dev, DSP_VACT_ST_END, mask, val);
 
                rk3288_lcdc_post_cfg(dev_drv);
+               mask = m_DSP_LINE_FLAG_NUM;
+               val = v_DSP_LINE_FLAG_NUM(vsync_len + upper_margin + y_res);
+               lcdc_msk_reg(lcdc_dev, INTR_CTRL0, mask, val);
        }
        spin_unlock(&lcdc_dev->reg_lock);
-       rk3288_lcdc_set_dclk(dev_drv);
+       rk3288_lcdc_set_dclk(dev_drv, 1);
        if (screen->type != SCREEN_HDMI && dev_drv->trsm_ops &&
            dev_drv->trsm_ops->enable)
                dev_drv->trsm_ops->enable();
@@ -1406,15 +1417,12 @@ static int rk3288_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv)
        struct lcdc_device *lcdc_dev = container_of(dev_drv,
                                        struct lcdc_device, driver);
        u32 mask,val;
-       struct rk_screen *screen = dev_drv->cur_screen;
        
        mask = m_FS_INTR_CLR | m_FS_INTR_EN | m_LINE_FLAG_INTR_CLR |
                            m_LINE_FLAG_INTR_EN | m_BUS_ERROR_INTR_CLR | 
-                           m_BUS_ERROR_INTR_EN | m_DSP_LINE_FLAG_NUM;
+                           m_BUS_ERROR_INTR_EN;
        val = v_FS_INTR_CLR(1) | v_FS_INTR_EN(1) | v_LINE_FLAG_INTR_CLR(1) |
-           v_LINE_FLAG_INTR_EN(1) | v_BUS_ERROR_INTR_CLR(1) | v_BUS_ERROR_INTR_EN(0) |
-           v_DSP_LINE_FLAG_NUM(screen->mode.vsync_len + screen->mode.upper_margin +
-           screen->mode.yres);
+           v_LINE_FLAG_INTR_EN(1) | v_BUS_ERROR_INTR_CLR(1) | v_BUS_ERROR_INTR_EN(0);
        lcdc_msk_reg(lcdc_dev, INTR_CTRL0, mask, val);  
 #ifdef LCDC_IRQ_EMPTY_DEBUG
                 mask = m_WIN0_EMPTY_INTR_EN | m_WIN1_EMPTY_INTR_EN | m_WIN2_EMPTY_INTR_EN |
@@ -1456,16 +1464,14 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                                        return -1;
                                }
                        }
-                       if (dev_drv->mmu_dev)
-                               rockchip_iovmm_activate(dev_drv->dev);
                }
 #endif
                rk3288_lcdc_reg_restore(lcdc_dev);
-               if (dev_drv->iommu_enabled)
-                       rk3288_lcdc_mmu_en(dev_drv);
+               /*if (dev_drv->iommu_enabled)
+                  rk3368_lcdc_mmu_en(dev_drv); */
                if ((support_uboot_display()&&(lcdc_dev->prop == PRMRY))) {
-                       rk3288_lcdc_set_dclk(dev_drv);
-                       rk3288_lcdc_enable_irq(dev_drv);
+                       rk3288_lcdc_set_dclk(dev_drv, 0);
+                       /* rk3288_lcdc_enable_irq(dev_drv); */
                } else {
                        rk3288_load_screen(dev_drv, 1);
                }
@@ -3761,6 +3767,7 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .dump_reg               = rk3288_lcdc_reg_dump,
        .cfg_done               = rk3288_lcdc_config_done,
        .set_irq_to_cpu         = rk3288_lcdc_set_irq_to_cpu,
+       .mmu_en    = rk3288_lcdc_mmu_en,
        .set_overscan           = rk3288_lcdc_set_overscan,
 
 };
index 29372aef5b97de72ecb0584e7108dee8c27f9cb9..3c9fa21796780662983420d3ed7ea829fade2c64 100755 (executable)
@@ -1336,6 +1336,7 @@ struct lcdc_device{
        u32 pixclock;   
 
        u32 standby;                                            /*1:standby,0:wrok*/
+       u32 iommu_status;
 };
 
 struct alpha_config{