From: yxj Date: Wed, 7 May 2014 00:49:44 +0000 (+0800) Subject: rk fb:rk3288 lcdc: temporarily workround iommu unmaped the buffer when it being used X-Git-Tag: firefly_0821_release~5338 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=99ceaf4398710eed1657e485bc12f55bbea135c6;p=firefly-linux-kernel-4.4.55.git rk fb:rk3288 lcdc: temporarily workround iommu unmaped the buffer when it being used --- diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi index 42e63363665a..7e16ec221367 100755 --- a/arch/arm/boot/dts/rk3288.dtsi +++ b/arch/arm/boot/dts/rk3288.dtsi @@ -743,6 +743,7 @@ compatible = "rockchip,rk3288-lcdc"; rockchip,prop = ; rochchip,pwr18 = <0>; + rockchip,iommu-enabled = <1>; reg = <0xff940000 0x10000>; interrupts = ; pinctrl-names = "default", "gpio"; @@ -757,6 +758,7 @@ compatible = "rockchip,rk3288-lcdc"; rockchip,prop = ; rockchip,pwr18 = <0>; + rockchip,iommu-enabled = <1>; reg = <0xff930000 0x10000>; interrupts = ; //pinctrl-names = "default", "gpio"; diff --git a/drivers/video/rockchip/lcdc/rk3288_lcdc.c b/drivers/video/rockchip/lcdc/rk3288_lcdc.c index 6209406a94b9..a4e053a9a7ad 100755 --- a/drivers/video/rockchip/lcdc/rk3288_lcdc.c +++ b/drivers/video/rockchip/lcdc/rk3288_lcdc.c @@ -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; } diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 106c48c22fd1..0b92c5539e7e 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -49,6 +49,8 @@ #include #include #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;iarea_num;i++){ area_data = ®_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;ilcdc_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,®s->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;iwin_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;iwin_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)) { diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index a0d9cfb5a09e..e0655cfa4262 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -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;