From ee4ae207448b4c867be9e3d4a2133cc77a30a0df Mon Sep 17 00:00:00 2001 From: hjc Date: Fri, 18 Apr 2014 11:18:27 +0800 Subject: [PATCH] rk3288 lcdc: add support iommu --- drivers/video/rockchip/rk_fb.c | 172 +++++++++++++-------------------- include/linux/rk_fb.h | 3 +- 2 files changed, 67 insertions(+), 108 deletions(-) diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 9b54022919a7..ecb1263fcfed 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -45,12 +45,10 @@ #if defined(CONFIG_ION_ROCKCHIP) #include -#ifdef USE_ION_MMU #include #include #include #endif -#endif #define H_USE_FENCE 1 static int hdmi_switch_complete; static struct platform_device *fb_pdev; @@ -61,6 +59,8 @@ int (*video_data_to_mirroring)(struct fb_info *info, u32 yuv_phy[2]); EXPORT_SYMBOL(video_data_to_mirroring); #endif +struct rk_fb_reg_win_data g_reg_win_data[4]; +static int g_first_buf = 1; static struct rk_fb_trsm_ops *trsm_lvds_ops; static struct rk_fb_trsm_ops *trsm_edp_ops; @@ -997,59 +997,19 @@ void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv, printk("error waiting on fence\n"); } -#ifdef USE_ION_MMU -static unsigned int rk_fb_map_ion_handle(struct fb_info *info, - struct rk_fb_reg_area_data *reg_area_data, - struct ion_handle *ion_handle,struct dma_buf *buf) -{ - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; - reg_area_data->dma_buf = buf; - reg_area_data->attachment = - dma_buf_attach(reg_area_data->dma_buf, dev_drv->dev); - if (IS_ERR_OR_NULL(reg_area_data->attachment)) { - dev_err(dev_drv->dev, "dma_buf_attach() failed: %ld\n", - PTR_ERR(reg_area_data->attachment)); - goto err_buf_map_attach; - } - - reg_area_data->sg_table = dma_buf_map_attachment(reg_area_data->attachment, - DMA_BIDIRECTIONAL); - if (IS_ERR_OR_NULL(reg_area_data->sg_table)) { - dev_err(dev_drv->dev, "dma_buf_map_attachment() failed: %ld\n", - PTR_ERR(reg_area_data->sg_table)); - goto err_buf_map_attachment; - } - - reg_area_data->dma_addr = iovmm_map(dev_drv->dev, reg_area_data->sg_table->sgl, 0, - buf->size); - if (!reg_area_data->dma_addr || IS_ERR_VALUE(reg_area_data->dma_addr)) { - dev_err(dev_drv->dev, "iovmm_map() failed: %d\n", reg_area_data->dma_addr); - goto err_iovmm_map; - } - reg_area_data->ion_handle = ion_handle; - return reg_area_data->dma_buf->size; - -err_iovmm_map: - dma_buf_unmap_attachment(reg_area_data->attachment, - reg_area_data->sg_table,DMA_BIDIRECTIONAL); -err_buf_map_attachment: - dma_buf_detach(buf, reg_area_data->attachment); -err_buf_map_attach: - return 0; -} - +#ifdef CONFIG_ROCKCHIP_IOMMU int rk_fb_sysmmu_fault_handler(struct device *dev, enum rk_sysmmu_inttype itype, unsigned long pgtable_base, - unsigned long fault_addr,unsigned int statu) + unsigned long fault_addr,unsigned int status) { - /*struct fb_info *fbi = dev_get_drvdata(dev); + struct fb_info *fbi = dev_get_drvdata(dev); struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; pr_err("PAGE FAULT occurred at 0x%lx (Page table base: 0x%lx),status=%d\n", - fault_addr, pgtable_base,statu); + fault_addr, pgtable_base,status); dev_drv->ops->dump_reg(dev_drv); pr_err("Generating Kernel OOPS... because it is unrecoverable.\n"); - BUG();*/ + BUG(); return 0; } @@ -1060,22 +1020,13 @@ void rk_fb_free_dma_buf(struct device *dev,struct rk_fb_reg_win_data *reg_win_da int i,index_buf; struct rk_fb_reg_area_data *area_data; struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); -#ifdef H_USE_FENCE - for(i=0;ireg_area_data[i].acq_fence) - sync_fence_put(reg_win_data->reg_area_data[i].acq_fence); - } -#endif + for(i=0;iarea_num;i++){ area_data = ®_win_data->reg_area_data[i]; index_buf = area_data->index_buf; -#ifdef USE_ION_MMU - iovmm_unmap(dev,area_data->dma_addr); - dma_buf_unmap_attachment(area_data->attachment, area_data->sg_table, - DMA_BIDIRECTIONAL); - dma_buf_detach(area_data->dma_buf, area_data->attachment); - dma_buf_put(area_data->dma_buf); -#endif + #ifdef CONFIG_ROCKCHIP_IOMMU + ion_unmap_iommu(dev, rk_fb->ion_client, area_data->ion_handle); + #endif if(area_data->ion_handle != NULL) ion_free(rk_fb->ion_client, area_data->ion_handle); } @@ -1152,7 +1103,6 @@ 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; @@ -1264,9 +1214,16 @@ ext_win_exit: #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]); + } + } for(i=0;iwin_num;i++){ - rk_fb_free_dma_buf(dev_drv->dev,®s->reg_win_data[i]); + memcpy(&g_reg_win_data[i], &(regs->reg_win_data[i]), sizeof(struct rk_fb_reg_win_data)); } + g_first_buf = 0; + if (dev_drv->wait_fs == 1) kfree(regs); } @@ -1344,11 +1301,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info, u16 uv_x_off,uv_y_off,uv_y_act; u8 is_pic_yuv=0; u8 ppixel_a=0,global_a=0; -#ifdef USE_ION_MMU - struct dma_buf *buf; -#else ion_phys_addr_t phy_addr; -#endif + reg_win_data->reg_area_data[0].smem_start = -1; reg_win_data->area_num = 0; if(win_par->area_par[0].phy_addr == 0){ @@ -1364,19 +1318,13 @@ static int rk_fb_set_win_buffer(struct fb_info *info, } reg_win_data->area_num++; reg_win_data->reg_area_data[i].ion_handle = hdl; - #ifndef USE_ION_MMU + #ifndef CONFIG_ROCKCHIP_IOMMU ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len); - reg_win_data->reg_area_data[i].smem_start = phy_addr; #else - buf = ion_share_dma_buf(rk_fb->ion_client, hdl); - if (IS_ERR_OR_NULL(buf)) { - dev_err(info->dev, "ion_share_dma_buf() failed\n"); - goto err_share_dma_buf; - } - rk_fb_map_ion_handle(info,®_win_data->reg_area_data[i],hdl,buf); - reg_win_data->reg_area_data[i].smem_start = - reg_win_data->reg_area_data[i].dma_addr; + ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl, + (unsigned long *)&phy_addr, (unsigned long *)&len); #endif + reg_win_data->reg_area_data[i].smem_start = phy_addr; reg_win_data->area_buf_num++; reg_win_data->reg_area_data[i].index_buf = 1; } @@ -1537,7 +1485,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info, } } return 0; -#ifdef USE_ION_MMU +#ifdef CONFIG_ROCKCHIP_IOMMU err_share_dma_buf: ion_free(rk_fb->ion_client, hdl); return -ENOMEM; @@ -2247,6 +2195,18 @@ static int fb_setcolreg(unsigned regno, return 0; } +static int rk_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) +{ + struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); + struct rk_lcdc_win *win; + win = dev_drv->win[win_id]; + + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + + return dma_buf_mmap(win->area[0].dma_buf, vma, 0); +} + static struct fb_ops fb_ops = { .owner = THIS_MODULE, .fb_open = rk_fb_open, @@ -2626,11 +2586,7 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) #if defined(CONFIG_ION_ROCKCHIP) struct ion_handle *handle; ion_phys_addr_t phy_addr; -#ifdef USE_ION_MMU - struct dma_buf *buf; -#else size_t len; -#endif #endif win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id); if (win_id < 0) @@ -2647,26 +2603,25 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) dev_err(fbi->device, "failed to ion_alloc:%ld\n",PTR_ERR(handle)); return -ENOMEM; } + win->area[0].dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle); + if (IS_ERR_OR_NULL(win->area[0].dma_buf)) { + printk("ion_share_dma_buf() failed\n"); + goto err_share_dma_buf; + } win->area[0].ion_hdl = handle; fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle); -#ifndef USE_ION_MMU - ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); - fbi->fix.smem_start = phy_addr; - fbi->fix.smem_len = len; - printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n",phy_addr); +#ifndef CONFIG_ROCKCHIP_IOMMU + ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); #else - buf = ion_share_dma_buf(rk_fb->ion_client, handle); - if (IS_ERR_OR_NULL(buf)) { - dev_err(fbi->device, "ion_share_dma_buf() failed\n"); - goto err_share_dma_buf; - } - rk_fb_map_ion_handle(fbi,&dev_drv->reg_area_data,handle,buf); - fbi->fix.smem_start = dev_drv->reg_area_data.dma_addr; - fbi->fix.smem_len = buf->size; - printk(KERN_INFO "alloc_buffer:kernel_vir_addr=0x%x,mmu_vir_addr=0x%x,len=0x%x\n", - fbi->screen_base,fbi->fix.smem_start,fbi->fix.smem_len); + 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, + (unsigned long *)&phy_addr, (unsigned long *)&len); + printk("%s: ion_map_iommu: %x,%x\n", __func__, phy_addr, len); #endif - + fbi->fix.smem_start = phy_addr; + fbi->fix.smem_len = len; + printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n",phy_addr); #else dma_addr_t fb_mem_phys; void *fb_mem_virt; @@ -2714,11 +2669,11 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) } return ret; -#ifdef USE_ION_MMU + err_share_dma_buf: ion_free(rk_fb->ion_client, handle); return -ENOMEM; -#endif + } static int rk_release_fb_buffer(struct fb_info *fbi) @@ -2845,7 +2800,7 @@ 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 USE_ION_MMU + #ifdef CONFIG_ROCKCHIP_IOMMU struct device *mmu_dev = NULL; #endif if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT) @@ -2884,17 +2839,20 @@ 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 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 USE_ION_MMU - mmu_dev = - rockchip_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name); - 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); + #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); } diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index 417e7e866431..6ff86f179fdd 100755 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -84,7 +84,7 @@ #define Y_MIRROR 2 #define X_Y_MIRROR 3 -/*#define USE_ION_MMU 1*/ +//#define USE_ION_MMU 1 #if defined(CONFIG_ION_ROCKCHIP) extern struct ion_client *rockchip_ion_client_create(const char * name); #endif @@ -284,6 +284,7 @@ struct rk_lcdc_win_area{ #if defined(CONFIG_ION_ROCKCHIP) struct ion_handle *ion_hdl; int dma_buf_fd; + struct dma_buf *dma_buf; #endif u32 dsp_stx; u32 dsp_sty; -- 2.34.1