rk3288 lcdc: add support iommu
authorhjc <hjc@rock-chips.com>
Fri, 18 Apr 2014 03:18:27 +0000 (11:18 +0800)
committerhjc <hjc@rock-chips.com>
Fri, 18 Apr 2014 03:19:38 +0000 (11:19 +0800)
drivers/video/rockchip/rk_fb.c
include/linux/rk_fb.h

index 9b54022919a7c3ce2daf78bec2fa1202c52b9d93..ecb1263fcfedf30138d5635b4485dabb2dd545b5 100755 (executable)
 
 #if defined(CONFIG_ION_ROCKCHIP)
 #include <linux/rockchip_ion.h>
-#ifdef USE_ION_MMU
 #include <linux/rockchip/iovmm.h>
 #include <linux/rockchip/sysmmu.h>
 #include <linux/dma-buf.h>
 #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;i<RK_WIN_MAX_AREA;i++){
-               if(reg_win_data->reg_area_data[i].acq_fence)
-                       sync_fence_put(reg_win_data->reg_area_data[i].acq_fence);
-       }
-#endif
+       
        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 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;i<regs->win_num;i++){
+                       rk_fb_free_dma_buf(dev_drv->dev,&g_reg_win_data[i]);
+               }
+       }
        for(i=0;i<regs->win_num;i++){
-               rk_fb_free_dma_buf(dev_drv->dev,&regs->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,&reg_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);
                }       
index 417e7e8664313bb53f88432e7532ce2f93d9fde8..6ff86f179fdd63ab15bb91963e147fd44ff6539c 100755 (executable)
@@ -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;