rk_fb: add extern screen open iommu, when dual screen display using iommu
authorShen Zhenyi <szy@rock-chips.com>
Mon, 12 Oct 2015 06:27:00 +0000 (14:27 +0800)
committerGerrit Code Review <gerrit@rock-chips.com>
Mon, 12 Oct 2015 07:44:50 +0000 (15:44 +0800)
Change-Id: Ia216d102df6841d4497144fe3c53aaeea9860178
Signed-off-by: Shen Zhenyi <szy@rock-chips.com>
drivers/video/rockchip/rk_fb.c

index d2e74fccacd06c2d5eb45ed91e232d79c9a495cd..5a30657a10cec7954b9177df684ba249fec49c1b 100755 (executable)
@@ -3381,7 +3381,9 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        char name[6] = {0};
        int i, win_id;
        static bool load_screen = false;
-       char *envp[3];
+       char *envp[4];
+       char envplcdc[32];
+       char envpfbdev[32];
        int ret, list_is_empty = 0;
 
        if (unlikely(!rk_fb) || unlikely(!screen))
@@ -3426,14 +3428,13 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        }
 
        envp[0] = "switch screen";
-       envp[1] = kmalloc(32, GFP_KERNEL);
-       if (envp[1] == NULL) {
-               pr_err("switch screen kmalloc envp[1] fail\n");
-               mutex_unlock(&dev_drv->switch_screen);
-               return 0;
-       }
-       sprintf(envp[1], "SCREEN=%d,ENABLE=%d", screen->type, enable);
-       envp[2] = NULL;
+       memset(envplcdc, 0, sizeof(envplcdc));
+       memset(envpfbdev, 0, sizeof(envpfbdev));
+       sprintf(envplcdc, "SCREEN=%d,ENABLE=%d", screen->type, enable);
+       sprintf(envpfbdev, "FBDEV=%d", dev_drv->fb_index_base);
+       envp[1] = envplcdc;
+       envp[2] = envpfbdev;
+       envp[3] = NULL;
 
        if ((rk_fb->disp_mode == ONE_DUAL) ||
            (rk_fb->disp_mode == NO_DUAL)) {
@@ -3457,7 +3458,6 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                if (dev_drv->cur_screen->type != screen->type) {
                        dev_drv->hdmi_switch = 0;
                        mutex_unlock(&dev_drv->switch_screen);
-                       kfree(envp[1]);
                        return 0;
                }
 
@@ -3510,7 +3510,6 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        }
                }
                 kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
-                kfree(envp[1]);
 
                hdmi_switch_state = 0;
                dev_drv->hdmi_switch = 0;
@@ -3542,7 +3541,9 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id);
                        win = dev_drv->win[win_id];
                        if (win && fb_par->state) {
+                               mutex_lock(&dev_drv->win_config);
                                dev_drv->ops->load_screen(dev_drv, 1);
+                               mutex_unlock(&dev_drv->win_config);
 
                                info->var.activate |= FB_ACTIVATE_FORCE;
                                if (rk_fb->disp_mode == ONE_DUAL) {
@@ -3582,7 +3583,6 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                dev_drv->ops->load_screen(dev_drv, 0);
        }
        kobject_uevent_env(&dev_drv->dev->kobj, KOBJ_CHANGE, envp);
-        kfree(envp[1]);
 
        hdmi_switch_state = 1;
        load_screen = true;
@@ -3753,6 +3753,8 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
        dma_addr_t fb_mem_phys;
        void *fb_mem_virt;
 #endif
+       ion_phys_addr_t phy_addr;
+       size_t len;
 
        win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id);
        if (win_id < 0)
@@ -3779,9 +3781,64 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi)
 #endif
                memset(fbi->screen_base, 0, fbi->fix.smem_len);
        } else {
-               fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
-               fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len;
-               fbi->screen_base = rk_fb->fb[0]->screen_base;
+               if (dev_drv->prop == EXTEND && dev_drv->iommu_enabled) {
+                       struct rk_lcdc_driver *dev_drv_prmry;
+                       int win_id_prmry;
+                       fb_mem_size = get_fb_size(dev_drv->reserved_fb);
+#if defined(CONFIG_ION_ROCKCHIP)
+                       dev_drv_prmry = rk_get_prmry_lcdc_drv();
+                       if (dev_drv_prmry == NULL)
+                               return -ENODEV;
+                       win_id_prmry =
+                               dev_drv_prmry->ops->fb_get_win_id(dev_drv_prmry,
+                                                                fbi->fix.id);
+                       if (win_id_prmry < 0)
+                               return -ENODEV;
+                       else
+                               fb_par->ion_hdl =
+                               dev_drv_prmry->win[win_id_prmry]->area[0].ion_hdl;
+                               fbi->screen_base =
+                                       ion_map_kernel(rk_fb->ion_client,
+                                                      fb_par->ion_hdl);
+                               dev_drv->win[win_id]->area[0].ion_hdl =
+                                       fb_par->ion_hdl;
+       #ifdef CONFIG_ROCKCHIP_IOMMU
+                               if (dev_drv->mmu_dev)
+                                       ret = ion_map_iommu(dev_drv->dev,
+                                                           rk_fb->ion_client,
+                                                           fb_par->ion_hdl,
+                                                           (unsigned long *)&phy_addr,
+                                                           (unsigned long *)&len);
+                               else
+                                       ret = ion_phys(rk_fb->ion_client,
+                                                      fb_par->ion_hdl,
+                                                      &phy_addr, &len);
+       #endif
+                               if (ret < 0) {
+                                       dev_err(fbi->dev, "ion map to get phy addr failed\n");
+                                       return -ENOMEM;
+                               }
+                               fbi->fix.smem_start = phy_addr;
+                               fbi->fix.smem_len = len;
+#else
+                       fb_mem_virt = dma_alloc_writecombine(fbi->dev,
+                                                            fb_mem_size,
+                                                            &fb_mem_phys,
+                                                            GFP_KERNEL);
+                       if (!fb_mem_virt) {
+                               pr_err("%s: Failed to allocate framebuffer\n",
+                                      __func__);
+                               return -ENOMEM;
+                       }
+                       fbi->fix.smem_len = fb_mem_size;
+                       fbi->fix.smem_start = fb_mem_phys;
+                       fbi->screen_base = fb_mem_virt;
+#endif
+               } else {
+                       fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start;
+                       fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len;
+                       fbi->screen_base = rk_fb->fb[0]->screen_base;
+               }
        }
 
        fbi->screen_size = fbi->fix.smem_len;
@@ -4217,7 +4274,15 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
        } else {
                 struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
                 extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
-                rk_fb_alloc_buffer(extend_fbi);
+               extend_fbi->fbops->fb_open(extend_fbi, 1);
+#if defined(CONFIG_ROCKCHIP_IOMMU)
+               if (dev_drv->iommu_enabled) {
+                       if (dev_drv->mmu_dev)
+                               rockchip_iovmm_set_fault_handler(dev_drv->dev,
+                                                                rk_fb_sysmmu_fault_handler);
+               }
+#endif
+               rk_fb_alloc_buffer(extend_fbi);
        }
 #endif
        return 0;