rk fb:rk3288 lcdc: temporarily workround iommu unmaped the buffer when it being used
authoryxj <yxj@rock-chips.com>
Wed, 7 May 2014 00:49:44 +0000 (08:49 +0800)
committeryxj <yxj@rock-chips.com>
Thu, 8 May 2014 01:10:16 +0000 (09:10 +0800)
arch/arm/boot/dts/rk3288.dtsi
drivers/video/rockchip/lcdc/rk3288_lcdc.c
drivers/video/rockchip/rk_fb.c
include/linux/rk_fb.h

index 42e63363665a174a7cd185a7a081b596d0da44e0..7e16ec221367b24605a3edd455931482e0254d6a 100755 (executable)
                compatible = "rockchip,rk3288-lcdc";
                rockchip,prop = <PRMRY>;
                rochchip,pwr18 = <0>;
+               rockchip,iommu-enabled = <1>;
                reg = <0xff940000 0x10000>;
                interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
                pinctrl-names = "default", "gpio";
                compatible = "rockchip,rk3288-lcdc";
                rockchip,prop = <EXTEND>;
                rockchip,pwr18 = <0>;
+               rockchip,iommu-enabled = <1>;
                reg = <0xff930000 0x10000>;
                interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
                //pinctrl-names = "default", "gpio";
index 6209406a94b97dde3ea501a80ef167838c57b4b5..a4e053a9a7ad59fab7bc1555f35cc83896ca6dcc 100755 (executable)
@@ -224,11 +224,7 @@ static int rk3288_lcdc_pre_init(struct rk_lcdc_driver *dev_drv)
        rk3288_lcdc_clk_enable(lcdc_dev);
 
        /*backup reg config at uboot*/
-#ifdef CONFIG_ROCKCHIP_IOMMU
-               for (i = 0; i < 0x330;) {
-#else
-               for (i = 0; i < 0x1a0;) {
-#endif
+       for (i = 0; i < 0x1a0;) {
                lcdc_readl(lcdc_dev,i);
                i += 4;
        }
@@ -864,11 +860,10 @@ static int rk3288_lcdc_reg_update(struct rk_lcdc_driver *dev_drv)
 
 static int rk3288_lcdc_reg_restore(struct lcdc_device *lcdc_dev)
 {
-#ifdef CONFIG_ROCKCHIP_IOMMU
-       memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x330);
-#else
-       memcpy((u8 *) lcdc_dev->regs, (u8 *) lcdc_dev->regsbak, 0x1fc);
-#endif
+       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);
        return 0;
 }
 static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
@@ -886,6 +881,7 @@ static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv)
                lcdc_msk_reg(lcdc_dev, SYS_CTRL1, mask, val);
        }
        spin_unlock(&lcdc_dev->reg_lock);
+       return 0;
 }
 
 static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
@@ -915,8 +911,6 @@ static int rk3288_lcdc_set_dclk(struct rk_lcdc_driver *dev_drv)
 
 static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
 {
-       int ret = -EINVAL;
-       int fps;
        u16 face = 0;
        u32 v=0;
        struct lcdc_device *lcdc_dev =
@@ -1196,6 +1190,7 @@ static int rk3288_lcdc_enable_irq(struct rk_lcdc_driver *dev_drv)
                         v_PWM_GEN_INTR_EN(1);
                 lcdc_msk_reg(lcdc_dev, INTR_CTRL1, mask, val);
 #endif         
+       return 0;
 }
 
 static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
@@ -1209,9 +1204,8 @@ static int rk3288_lcdc_open(struct rk_lcdc_driver *dev_drv, int win_id,
                rk3288_lcdc_pre_init(dev_drv);
                rk3288_lcdc_clk_enable(lcdc_dev);
                rk3288_lcdc_reg_restore(lcdc_dev);
-               #ifdef CONFIG_ROCKCHIP_IOMMU
+               if (dev_drv->iommu_enabled)
                        rk3288_lcdc_mmu_en(dev_drv);
-               #endif
                if ((support_uboot_display()&&(lcdc_dev->prop == PRMRY))) {
                        rk3288_lcdc_set_dclk(dev_drv);
                        rk3288_lcdc_enable_irq(dev_drv);
@@ -1341,7 +1335,7 @@ static int rk3288_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id)
                                struct lcdc_device, driver);
        struct rk_lcdc_win *win = NULL;
        struct rk_screen *screen = dev_drv->cur_screen;
-       u32 mask, val;
+       
 #if defined(WAIT_FOR_SYNC)
        int timeout;
        unsigned long flags;
@@ -2165,6 +2159,7 @@ static int rk3288_lcdc_ioctl(struct rk_lcdc_driver *dev_drv, unsigned int cmd,
 
 static int rk3288_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv)
 {
+       u32 reg;
        struct lcdc_device *lcdc_dev =
            container_of(dev_drv, struct lcdc_device, driver);
        if (dev_drv->suspend_flag)
@@ -2172,6 +2167,9 @@ static int rk3288_lcdc_early_suspend(struct rk_lcdc_driver *dev_drv)
        
        dev_drv->suspend_flag = 1;
        flush_kthread_worker(&dev_drv->update_regs_worker);
+       
+       for (reg = MMU_DTE_ADDR; reg <= MMU_AUTO_GATING; reg +=4)
+                       lcdc_readl(lcdc_dev, reg);
        if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable)
                dev_drv->trsm_ops->disable();
        
@@ -3208,7 +3206,6 @@ static struct rk_lcdc_drv_ops lcdc_drv_ops = {
        .set_dsp_hue            = rk3288_lcdc_set_hue,
        .set_dsp_bcsh_bcs       = rk3288_lcdc_set_bcsh_bcs,
        .dump_reg               = rk3288_lcdc_reg_dump,
-       .mmu_en                 = rk3288_lcdc_mmu_en,
        .cfg_done               = rk3288_lcdc_config_done,
        .set_irq_to_cpu         = rk3288_lcdc_set_irq_to_cpu,
 };
@@ -3317,6 +3314,14 @@ static int rk3288_lcdc_parse_dt(struct lcdc_device *lcdc_dev)
                lcdc_dev->pwr18 = false;        /*default set it as 3.xv power supply */
        else
                lcdc_dev->pwr18 = (val ? true : false);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       if (of_property_read_u32(np, "rockchip,iommu-enabled", &val))
+               lcdc_dev->driver.iommu_enabled = 0;
+       else
+               lcdc_dev->driver.iommu_enabled = val;
+#else
+       lcdc_dev->driver.iommu_enabled = 0;
+#endif
        return 0;
 }
 
@@ -3385,13 +3390,14 @@ static int rk3288_lcdc_probe(struct platform_device *pdev)
                        lcdc_dev->irq, ret);
                return ret;
        }
-#ifdef CONFIG_ROCKCHIP_IOMMU
+
+       if (dev_drv->iommu_enabled) {
                if(lcdc_dev->id == 0){
                        strcpy(dev_drv->mmu_dts_name, "iommu,vopb_mmu");
                }else{
                        strcpy(dev_drv->mmu_dts_name, "iommu,vopl_mmu");
                }
-#endif
+       }
 
        ret = rk_fb_register(dev_drv, lcdc_win, lcdc_dev->id);
        if (ret < 0) {
@@ -3400,7 +3406,8 @@ static int rk3288_lcdc_probe(struct platform_device *pdev)
        }
        lcdc_dev->screen = dev_drv->screen0;
        
-       dev_info(dev, "lcdc%d probe ok\n", lcdc_dev->id);
+       dev_info(dev, "lcdc%d probe ok, iommu %s\n",
+               lcdc_dev->id, dev_drv->iommu_enabled ? "enabled" : "disabled");
 
        return 0;
 }
index 106c48c22fd167b158908a999ca64ac82f045943..0b92c5539e7e076095d4a9fb7ad24aa1514af32d 100755 (executable)
@@ -49,6 +49,8 @@
 #include <linux/rockchip/sysmmu.h>
 #include <linux/dma-buf.h>
 #endif
+
+
 #define H_USE_FENCE 1
 static int hdmi_switch_complete;
 static struct platform_device *fb_pdev;
@@ -60,8 +62,8 @@ EXPORT_SYMBOL(video_data_to_mirroring);
 #endif
 
 struct rk_fb_reg_win_data g_reg_win_data[4];
+static int g_last_win_num;
 static int g_first_buf = 1;
-
 static struct rk_fb_trsm_ops *trsm_lvds_ops;
 static struct rk_fb_trsm_ops *trsm_edp_ops;
 static struct rk_fb_trsm_ops *trsm_mipi_ops;
@@ -998,24 +1000,52 @@ void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv,
 }
 
 #ifdef CONFIG_ROCKCHIP_IOMMU
+static int g_last_addr[4];
+u32 freed_addr[10];
+u32 freed_index;
+
+#define DUMP_CHUNK 256
+char buf[PAGE_SIZE];
+
 int rk_fb_sysmmu_fault_handler(struct device *dev,
                enum rk_sysmmu_inttype itype, unsigned long pgtable_base,
                unsigned long fault_addr,unsigned int status)
 {
-       struct fb_info *fbi = dev_get_drvdata(dev);
-       struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par;
-
+       struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv();
+       int i = 0;
        pr_err("PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx),status=%d\n",
                        fault_addr, pgtable_base,status);
-       dev_drv->ops->dump_reg(dev_drv);
-       pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
-       BUG();
+       printk("last config addr:\n"
+               "win0:0x%08x\n"
+               "win1:0x%08x\n"
+               "win2:0x%08x\n"
+               "win3:0x%08x\n",
+               g_last_addr[0],
+               g_last_addr[1],
+               g_last_addr[2],
+               g_last_addr[3]);
+       printk("last freed buffer:\n");
+       for (i = 0; freed_addr[i] != 0xfefefefe; i++)
+               printk("%d:0x%08x\n",i, freed_addr[i]);
+       dev_drv->ops->get_disp_info(dev_drv, buf,0) ;
+       for (i = 0; i < PAGE_SIZE; i += DUMP_CHUNK) {
+               if ((PAGE_SIZE - i) > DUMP_CHUNK) {
+                       char c = buf[i + DUMP_CHUNK];
+                       buf[i + DUMP_CHUNK] = 0;
+                       pr_cont("%s", buf + i);
+                       buf[i + DUMP_CHUNK] = c;
+               } else {
+                       buf[PAGE_SIZE -1] = 0;
+                       pr_cont("%s", buf + i);
+               }
+       }
 
        return 0;
 }
 #endif
 
-void rk_fb_free_dma_buf(struct device *dev,struct rk_fb_reg_win_data *reg_win_data)
+
+void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv,struct rk_fb_reg_win_data *reg_win_data)
 {
        int i,index_buf;
        struct rk_fb_reg_area_data *area_data;
@@ -1024,12 +1054,16 @@ void rk_fb_free_dma_buf(struct device *dev,struct rk_fb_reg_win_data *reg_win_da
        for(i=0;i<reg_win_data->area_num;i++){
                area_data = &reg_win_data->reg_area_data[i];
                index_buf = area_data->index_buf;
-               #ifdef CONFIG_ROCKCHIP_IOMMU
-               ion_unmap_iommu(dev, rk_fb->ion_client, area_data->ion_handle);
-               #endif
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client,
+                                               area_data->ion_handle);
+                       freed_addr[freed_index++] = area_data->smem_start;
+               }
+#endif
                if(area_data->ion_handle != NULL)
                        ion_free(rk_fb->ion_client, area_data->ion_handle);
-               }
+       }
        memset(reg_win_data, 0, sizeof(struct rk_fb_reg_win_data));
 }
 
@@ -1105,7 +1139,7 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win,struct rk_fb_reg_win_dat
 
 static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_data *regs)
 {
-       int i,j,ret=0;
+       int i,j;
        struct rk_lcdc_win *win;
        ktime_t timestamp = dev_drv->vsync_info.timestamp;
        //struct rk_fb_reg_win_data old_reg_win_data[RK30_MAX_LAYER_SUPPORT];
@@ -1115,7 +1149,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_da
        bool wait_for_vsync;
        int count = 100;
        unsigned int dsp_addr[4];
-
+       long timeout;
        for(i=0;i<dev_drv->lcdc_win_num;i++){ 
                //old_reg_win_data[i]= regs->reg_win_data[i];
                win = dev_drv->win[i];
@@ -1127,7 +1161,11 @@ static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_da
                        rk_fb_update_driver(win,&regs->reg_win_data[j]);
                        win->state = 1;
                        dev_drv->ops->set_par(dev_drv,i);
-                       dev_drv->ops->pan_display(dev_drv,i);           
+                       dev_drv->ops->pan_display(dev_drv,i);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+                       if (dev_drv->iommu_enabled)
+                               g_last_addr[i] = win->area[0].smem_start + win->area[0].y_offset;
+#endif
                }else{
                        win->z_order = -1;
                        win->state = 0;
@@ -1214,11 +1252,12 @@ ext_win_exit:
        //ret = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
        //              !ktime_equal(timestamp, dev_drv->vsync_info.timestamp),msecs_to_jiffies(dev_drv->cur_screen->ft+5));
        do {
-               ret = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
-                               !ktime_equal(timestamp, dev_drv->vsync_info.timestamp),msecs_to_jiffies(dev_drv->cur_screen->ft+5));            
+               timestamp = dev_drv->vsync_info.timestamp;
+               timeout = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
+                               ktime_compare(dev_drv->vsync_info.timestamp, timestamp) > 0,msecs_to_jiffies(25));
                dev_drv->ops->get_dsp_addr(dev_drv,dsp_addr);
                wait_for_vsync = false;
-               for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+               /*for (i = 0; i < dev_drv->lcdc_win_num; i++) {
                        if(dev_drv->win[i]->state == 1){
                                u32 new_start = regs->reg_win_data[i].reg_area_data[0].smem_start +
                                                regs->reg_win_data[i].reg_area_data[0].y_offset;
@@ -1228,19 +1267,31 @@ ext_win_exit:
                                        break;
                                }
                        }
-               }
+               }*/
        } while (wait_for_vsync && count--);
 #ifdef H_USE_FENCE
        sw_sync_timeline_inc(dev_drv->timeline, 1);
 #endif
        if(!g_first_buf){
-               for(i=0;i<regs->win_num;i++){
-                       rk_fb_free_dma_buf(dev_drv->dev,&g_reg_win_data[i]);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       freed_index = 0;
+                       if (timeout >= 3)
+                               msleep(15);
+               }
+#endif
+               for(i=0;i< g_last_win_num;i++){
+                       rk_fb_free_dma_buf(dev_drv,&g_reg_win_data[i]);
                }
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled)
+                       freed_addr[freed_index] = 0xfefefefe;
+#endif
        }
        for(i=0;i<regs->win_num;i++){
                memcpy(&g_reg_win_data[i], &(regs->reg_win_data[i]), sizeof(struct rk_fb_reg_win_data));
        }
+       g_last_win_num = regs->win_num;
        g_first_buf = 0;
 
        if (dev_drv->wait_fs == 1)
@@ -1340,8 +1391,11 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                                #ifndef CONFIG_ROCKCHIP_IOMMU
                                        ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
                                #else
-                                       ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl,
-                                               (unsigned long *)&phy_addr, (unsigned long *)&len);
+                                       if (dev_drv->iommu_enabled)
+                                               ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl,
+                                                       (unsigned long *)&phy_addr, (unsigned long *)&len);
+                                       else
+                                               ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
                                #endif
                                reg_win_data->reg_area_data[i].smem_start = phy_addr;
                                reg_win_data->area_buf_num++;
@@ -1504,11 +1558,6 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                }
        }       
        return 0;
-#ifdef CONFIG_ROCKCHIP_IOMMU   
-err_share_dma_buf:
-       ion_free(rk_fb->ion_client, hdl);
-       return -ENOMEM; 
-#endif 
 }
 
 static int rk_fb_set_win_config(struct fb_info *info,
@@ -2702,14 +2751,14 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id)
                }
                win->area[0].ion_hdl = handle;
                fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle);
-#ifndef CONFIG_ROCKCHIP_IOMMU
-               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
-#else
-               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
-               printk("ion_phys: %x,%x\n", phy_addr, len);
-               ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle,
+#ifdef CONFIG_ROCKCHIP_IOMMU
+               if (dev_drv->iommu_enabled)
+                       ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle,
                                        (unsigned long *)&phy_addr, (unsigned long *)&len);
-               printk("%s: ion_map_iommu: %x,%x\n", __func__, phy_addr, len);
+               else
+                       ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
+#else
+               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);   
 #endif
                fbi->fix.smem_start = phy_addr;
                fbi->fix.smem_len = len;
@@ -2892,9 +2941,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
        struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev);
        struct fb_info *fbi;
        int i = 0, ret = 0, index = 0;
-       #ifdef CONFIG_ROCKCHIP_IOMMU
-               struct device *mmu_dev = NULL;
-       #endif
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       struct device *mmu_dev = NULL;
+#endif
        if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT)
                return -ENXIO;
 
@@ -2931,23 +2980,11 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                fbi->var.width = dev_drv->cur_screen->width;
                fbi->var.height = dev_drv->cur_screen->height;
                fbi->var.pixclock = dev_drv->pixclock;
-#ifdef CONFIG_ROCKCHIP_IOMMU
-               fb_ops.fb_mmap = rk_fb_mmap;
-#endif
+               if (dev_drv->iommu_enabled)
+                       fb_ops.fb_mmap = rk_fb_mmap;
                fbi->fbops = &fb_ops;
                fbi->flags = FBINFO_FLAG_DEFAULT;
                fbi->pseudo_palette = dev_drv->win[i]->pseudo_pal;
-               if (i == 0){ /* only alloc memory for main fb*/
-               #ifdef CONFIG_ROCKCHIP_IOMMU
-                       mmu_dev = rockchip_get_sysmmu_device_by_compatible("iommu,vopl_mmu");
-                       if (mmu_dev) {
-                               platform_set_sysmmu(mmu_dev, dev_drv->dev);
-                               rockchip_sysmmu_set_fault_handler(dev_drv->dev, rk_fb_sysmmu_fault_handler);
-                               iovmm_activate(dev_drv->dev);
-                       }
-               #endif          
-                       rk_fb_alloc_buffer(fbi, rk_fb->num_fb);
-               }       
                ret = register_framebuffer(fbi);
                if (ret < 0) {
                        dev_err(&fb_pdev->dev, "%s fb%d register_framebuffer fail!\n",
@@ -3002,6 +3039,21 @@ if (dev_drv->prop == PRMRY) {
        main_fbi->fbops->fb_open(main_fbi, 1);
        if(support_uboot_display())
                return 0;
+
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+       if (dev_drv->iommu_enabled) {/* only alloc memory for main fb*/ 
+               mmu_dev = rockchip_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name);
+               if (mmu_dev) {
+                       platform_set_sysmmu(mmu_dev, dev_drv->dev);
+                       rockchip_sysmmu_set_fault_handler(dev_drv->dev,
+                                       rk_fb_sysmmu_fault_handler);
+                       iovmm_activate(dev_drv->dev);
+               }
+               else
+                       dev_err(dev_drv->dev, "failed to get rockchip iommu device\n");
+       }
+#endif
+       rk_fb_alloc_buffer(main_fbi, 0);
        main_fbi->fbops->fb_set_par(main_fbi);
 #if  defined(CONFIG_LOGO_LINUX_BMP)
        if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
index a0d9cfb5a09e0e4db807c1dff9582a76a47190e5..e0655cfa42629a27119997190b22824c1529989a 100755 (executable)
@@ -496,6 +496,7 @@ struct rk_lcdc_driver {
        char fb2_win_id;
        char fb3_win_id;
        char mmu_dts_name[40];
+       int iommu_enabled;
        struct rk_fb_reg_area_data reg_area_data;
        struct mutex fb_win_id_mutex;