rk3288 lcdc: add support vop mmu
authorhjc <hjc@rock-chips.com>
Sat, 15 Mar 2014 06:47:59 +0000 (14:47 +0800)
committerhjc <hjc@rock-chips.com>
Sat, 15 Mar 2014 06:47:59 +0000 (14:47 +0800)
drivers/video/rockchip/lcdc/rk3288_lcdc.c
drivers/video/rockchip/rk_fb.c
include/linux/rk_fb.h

index cc041fc88a6d97b4062ed127e1bd90022f5f018f..731788392b23ddc131485c4a1fde4b2e2f53cf8e 100755 (executable)
@@ -920,6 +920,14 @@ static int rk3288_load_screen(struct rk_lcdc_driver *dev_drv, bool initscreen)
                        break;
                }
                lcdc_msk_reg(lcdc_dev, SYS_CTRL, mask, val);
+#ifdef USE_ION_MMU
+               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);           
+#endif 
 #ifndef CONFIG_RK_FPGA
                writel_relaxed(v, RK_GRF_VIRT + RK3288_GRF_SOC_CON6);
 #endif         
@@ -1244,7 +1252,7 @@ static int rk3288_lcdc_win_display(struct rk_lcdc_driver *dev_drv, struct rk_lcd
                val = v_WIN0_EMPTY_INTR_EN(1) | v_WIN1_EMPTY_INTR_EN(1) | v_WIN2_EMPTY_INTR_EN(1) |
                        v_WIN3_EMPTY_INTR_EN(1)| v_HWC_EMPTY_INTR_EN(1) | v_POST_BUF_EMPTY_INTR_EN(1) |
                        v_PWM_GEN_INTR_EN(1);
-               lcdc_msk_reg(lcdc_dev, INTR_CTRL1, mask, val);
+               /*lcdc_msk_reg(lcdc_dev, INTR_CTRL1, mask, val);*/
 #endif         
                lcdc_cfg_done(lcdc_dev);
 
@@ -1303,7 +1311,7 @@ static int rk3288_lcdc_pan_display(struct rk_lcdc_driver *dev_drv, int win_id)
                 val = v_WIN0_EMPTY_INTR_EN(1) | v_WIN1_EMPTY_INTR_EN(1) | v_WIN2_EMPTY_INTR_EN(1) |
                         v_WIN3_EMPTY_INTR_EN(1)| v_HWC_EMPTY_INTR_EN(1) | v_POST_BUF_EMPTY_INTR_EN(1) |
                         v_PWM_GEN_INTR_EN(1);
-                lcdc_msk_reg(lcdc_dev, INTR_CTRL1, mask, val);
+                /*lcdc_msk_reg(lcdc_dev, INTR_CTRL1, mask, val);*/
 #endif
                lcdc_cfg_done(lcdc_dev);
        }
@@ -2703,6 +2711,18 @@ static int rk3288_set_dsp_lut(struct rk_lcdc_driver *dev_drv, int *lut)
        return ret;
 }
 
+static int rk3288_lcdc_mmu_en(struct rk_lcdc_driver *dev_drv, bool en)
+{
+       struct lcdc_device *lcdc_dev =
+           container_of(dev_drv, struct lcdc_device, driver);
+       /*close win*/
+       lcdc_msk_reg(lcdc_dev, SYS_CTRL, m_MMU_EN,
+                    v_MMU_EN(en));
+       lcdc_cfg_done(lcdc_dev);
+       return 0;
+}
+
+
 static int rk3288_lcdc_dpi_open(struct rk_lcdc_driver *dev_drv, bool open)
 {
        struct lcdc_device *lcdc_dev =
@@ -2918,31 +2938,32 @@ static struct rk_lcdc_win lcdc_win[] = {
 };
 
 static struct rk_lcdc_drv_ops lcdc_drv_ops = {
-       .open = rk3288_lcdc_open,
-       .load_screen = rk3288_load_screen,
-       .set_par = rk3288_lcdc_set_par,
-       .pan_display = rk3288_lcdc_pan_display,
-       .lcdc_reg_update = rk3288_lcdc_reg_update,
-       .blank = rk3288_lcdc_blank,
-       .ioctl = rk3288_lcdc_ioctl,
-       .suspend = rk3288_lcdc_early_suspend,
-       .resume = rk3288_lcdc_early_resume,
-       .get_win_state = rk3288_lcdc_get_win_state,
-       .ovl_mgr = rk3288_lcdc_ovl_mgr,
-       .get_disp_info = rk3288_lcdc_get_disp_info,
-       .fps_mgr = rk3288_lcdc_fps_mgr,
-       .fb_get_win_id = rk3288_lcdc_get_win_id,
-       .fb_win_remap = rk3288_fb_win_remap,
-       .set_dsp_lut = rk3288_set_dsp_lut,
-       .poll_vblank = rk3288_lcdc_poll_vblank,
-       .dpi_open = rk3288_lcdc_dpi_open,
-       .dpi_win_sel = rk3288_lcdc_dpi_win_sel,
-       .dpi_status = rk3288_lcdc_dpi_status,
-       .get_dsp_addr = rk3288_lcdc_get_dsp_addr,
-       .set_dsp_cabc = rk3288_lcdc_set_dsp_cabc,
-       .set_dsp_hue = rk3288_lcdc_set_hue,
-       .set_dsp_bcsh_bcs = rk3288_lcdc_set_bcsh_bcs,
-       .dump_reg = rk3288_lcdc_reg_dump,
+       .open                   = rk3288_lcdc_open,
+       .load_screen            = rk3288_load_screen,
+       .set_par                = rk3288_lcdc_set_par,
+       .pan_display            = rk3288_lcdc_pan_display,
+       .lcdc_reg_update        = rk3288_lcdc_reg_update,
+       .blank                  = rk3288_lcdc_blank,
+       .ioctl                  = rk3288_lcdc_ioctl,
+       .suspend                = rk3288_lcdc_early_suspend,
+       .resume                 = rk3288_lcdc_early_resume,
+       .get_win_state          = rk3288_lcdc_get_win_state,
+       .ovl_mgr                = rk3288_lcdc_ovl_mgr,
+       .get_disp_info          = rk3288_lcdc_get_disp_info,
+       .fps_mgr                = rk3288_lcdc_fps_mgr,
+       .fb_get_win_id          = rk3288_lcdc_get_win_id,
+       .fb_win_remap           = rk3288_fb_win_remap,
+       .set_dsp_lut            = rk3288_set_dsp_lut,
+       .poll_vblank            = rk3288_lcdc_poll_vblank,
+       .dpi_open               = rk3288_lcdc_dpi_open,
+       .dpi_win_sel            = rk3288_lcdc_dpi_win_sel,
+       .dpi_status             = rk3288_lcdc_dpi_status,
+       .get_dsp_addr           = rk3288_lcdc_get_dsp_addr,
+       .set_dsp_cabc           = rk3288_lcdc_set_dsp_cabc,
+       .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,
 };
 static int rk3288_lcdc_parse_irq(struct lcdc_device *lcdc_dev,unsigned int reg_val)
 {
@@ -3011,7 +3032,7 @@ static irqreturn_t rk3288_lcdc_isr(int irq, void *dev_id)
        #if 0
                intr1_reg = lcdc_readl(lcdc_dev, INTR_CTRL1);
                if(intr1_reg != 0){
-                       rk3288_lcdc_parse_irq(intr1_reg);
+                       rk3288_lcdc_parse_irq(lcdc_dev,intr1_reg);
                }
        #endif  
        return IRQ_HANDLED;
@@ -3107,12 +3128,27 @@ static int rk3288_lcdc_probe(struct platform_device *pdev)
        }
 
        ret = devm_request_irq(dev, lcdc_dev->irq, rk3288_lcdc_isr,
-                              IRQF_DISABLED, dev_name(dev), lcdc_dev);
+                              IRQF_DISABLED | IRQF_SHARED, dev_name(dev), lcdc_dev);
        if (ret) {
                dev_err(&pdev->dev, "cannot requeset irq %d - err %d\n",
                        lcdc_dev->irq, ret);
                return ret;
        }
+#ifdef USE_ION_MMU
+#ifdef CONFIG_RK_FPGA  
+               if(lcdc_dev->id == 0){
+                       strcpy(dev_drv->mmu_dts_name, "iommu,vopb_mmu");
+               }else{
+                       strcpy(dev_drv->mmu_dts_name, "iommu,vopl_mmu");
+               }
+#else
+               if(lcdc_dev->id == 0){
+                       strcpy(dev_drv->mmu_dts_name, "iommu,vopl_mmu");
+               }else{
+                       strcpy(dev_drv->mmu_dts_name, "iommu,vopb_mmu");
+               }
+#endif
+#endif
 
        ret = rk_fb_register(dev_drv, lcdc_win, lcdc_dev->id);
        if (ret < 0) {
index c48781212fe38c0ffa07d9377b6522107d1c4f2f..ac8ab17fb42152694c4ab06e86788fa56f1d8868 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
-
 
 static int hdmi_switch_complete;
 static struct platform_device *fb_pdev;
@@ -910,16 +914,89 @@ 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;
+}
 
-void rk_fb_free_dma_buf(struct rk_fb_reg_win_data *reg_win_data)
+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)
 {
+       /*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);
+       dev_drv->ops->dump_reg(dev_drv);
+       pr_err("Generating Kernel OOPS... because it is unrecoverable.\n");
+       BUG();*/
+
+       return 0;
+}
+#endif
+
+void rk_fb_free_dma_buf(struct device *dev,struct rk_fb_reg_win_data *reg_win_data)
+{
+       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
-       int i;
        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;
+               if(index_buf == 1){
+                       #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
+                       ion_free(rk_fb->ion_client, area_data->ion_handle);
+               }
+       }
        memset(reg_win_data, 0, sizeof(struct rk_fb_reg_win_data));
 }
 
@@ -1036,7 +1113,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver * dev_drv,struct rk_fb_reg_da
        sw_sync_timeline_inc(dev_drv->timeline, 1);
 
        for(i=0;i<regs->win_num;i++){
-               rk_fb_free_dma_buf(&regs->reg_win_data[i]);
+               rk_fb_free_dma_buf(dev_drv->dev,&regs->reg_win_data[i]);
        }
 }
 
@@ -1071,7 +1148,6 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        u32 xoffset,yoffset;
 
        struct ion_handle *hdl;
-       ion_phys_addr_t phy_addr;
        size_t len;
        int index_buf;
        u8  fb_data_fmt;
@@ -1085,6 +1161,12 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        u16 uv_x_off,uv_y_off;
        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;
+       size_t len;
+#endif
        reg_win_data->area_num = 0;
        if(win_par->area_par[0].phy_addr == 0){
                for(i=0;i<RK_WIN_MAX_AREA;i++){ 
@@ -1100,8 +1182,20 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                                }
                                if(j == i){
                                        hdl = ion_import_dma_buf(rk_fb->ion_client, ion_fd);
-                                       ion_phys(rk_fb->ion_client, hdl, &phy_addr, &len);
-                                       reg_win_data->reg_area_data[i].smem_start = phy_addr;
+                                       reg_win_data->reg_area_data[i].ion_handle = hdl;
+                                       #ifndef USE_ION_MMU
+                                               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;
+                                       #endif
                                        reg_win_data->area_buf_num++;
                                        reg_win_data->reg_area_data[i].index_buf = 1;
                                }else{
@@ -1215,6 +1309,11 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                        uv_stride >> 2;
        }       
        return 0;
+#ifdef USE_ION_MMU     
+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,
@@ -1224,12 +1323,15 @@ static int rk_fb_set_win_config(struct fb_info *info,
        struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par;
        struct rk_fb_reg_data *regs;
        struct rk_fb_reg_win_data *reg_win_data;
+#ifdef H_USE_FENCE     
        struct sync_fence *release_fence[RK_MAX_BUF_NUM];
        struct sync_fence *retire_fence;
        struct sync_pt *release_sync_pt[RK_MAX_BUF_NUM];
        struct sync_pt *retire_sync_pt;
-       int ret,i,j=0,fence_fd;
+       int fencd_fd;
        char fence_name[20];
+#endif
+       int ret,i,j=0;
 
        //mutex_lock(&dev_drv->output_lock);
        regs = kzalloc(sizeof(struct rk_fb_reg_data), GFP_KERNEL);
@@ -2241,10 +2343,13 @@ 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;
-       size_t len;
+#ifdef USE_ION_MMU
+       struct dma_buf *buf;
 #else
        dma_addr_t fb_mem_phys;
        void *fb_mem_virt;
+       size_t len;
+#endif 
 #endif
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
        if (win_id < 0)
@@ -2263,10 +2368,24 @@ 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);
-               ion_phys(rk_fb->ion_client, handle, &phy_addr, &len);
-               fbi->fix.smem_start = phy_addr;
-               fbi->fix.smem_len = len;
-               printk("alloc_buffer:smem_start=0x%x\n",phy_addr);
+               #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%x\n",phy_addr);
+               #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);
+               #endif
+               
 #else
 
                fb_mem_virt = dma_alloc_writecombine(fbi->dev, fb_mem_size, &fb_mem_phys,
@@ -2313,6 +2432,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)
@@ -2437,7 +2561,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 USE_ION_MMU
+               struct device *mmu_dev = NULL;
+       #endif
        if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT)
                return -ENXIO;
 
@@ -2477,8 +2603,17 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                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*/
+               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);
+               #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",
index 7df7c8ff9a2b2762110af953ac568129c7cdfc28..7886ef848260aea33ed2c28d1c917f99b0cb2dd8 100755 (executable)
@@ -77,6 +77,7 @@
 #define RK_LF_STATUS_NC                  0xfe
 #define RK_LF_MAX_TIMEOUT                       (1600000UL << 6)       //>0.64s
 
+/*#define USE_ION_MMU 1*/
 #if defined(CONFIG_ION_ROCKCHIP)
 extern struct ion_client *rockchip_ion_client_create(const char * name);
 #endif
@@ -365,6 +366,7 @@ struct rk_lcdc_drv_ops {
        int (*set_dsp_hue) (struct rk_lcdc_driver *dev_drv,int hue);
        int (*set_dsp_bcsh_bcs)(struct rk_lcdc_driver *dev_drv,int bri,int con,int sat);
        int (*dump_reg) (struct rk_lcdc_driver * dev_drv);
+       int (*mmu_en) (struct rk_lcdc_driver * dev_drv,bool en);
 };
 
 struct rk_fb_area_par {
@@ -419,7 +421,14 @@ struct rk_fb_reg_area_data {
        u16 yvir;
        unsigned long smem_start;
        unsigned long cbr_start;        /*Cbr memory start address*/
-       u32 line_length;
+       u32 line_length;        
+       struct ion_handle *ion_handle;
+#ifdef         USE_ION_MMU
+       struct dma_buf *dma_buf;
+       struct dma_buf_attachment *attachment;
+       struct sg_table *sg_table;
+       dma_addr_t dma_addr;
+#endif 
 };
 
 struct rk_fb_reg_win_data {
@@ -467,6 +476,8 @@ struct rk_lcdc_driver {
        char fb1_win_id;
        char fb2_win_id;
        char fb3_win_id;
+       char mmu_dts_name[40];
+       struct rk_fb_reg_area_data reg_area_data;
        struct mutex fb_win_id_mutex;
 
        struct completion frame_done;   //sync for pan_display,whe we set a new frame address to lcdc register,we must make sure the frame begain to display