rk_fb: sysfs: make use vmap/vunmap in pairs.
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
index 4a97c5fd7b4e0c3aa8e67dab23b4a4603246313a..aef2035c843078a51a84015ac04350ee074dacfc 100755 (executable)
@@ -65,9 +65,6 @@ 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_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;
@@ -77,6 +74,18 @@ int support_uboot_display(void)
        return uboot_logo_on;
 }
 
+int rk_fb_get_display_policy(void)
+{
+       struct rk_fb *rk_fb;
+
+       if (fb_pdev) {
+               rk_fb = platform_get_drvdata(fb_pdev);
+               return rk_fb->disp_policy;
+       } else {
+               return DISPLAY_POLICY_SDK;
+       }
+}
+
 int rk_fb_trsm_ops_register(struct rk_fb_trsm_ops *ops, int type)
 {
        switch (type) {
@@ -276,8 +285,11 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv)
                                        pwr_ctr->pwr_ctr.volt = 0;
                        }
                };
-               of_property_read_u32(child, "rockchip,delay", &val);
-               pwr_ctr->pwr_ctr.delay = val;
+
+               if (!of_property_read_u32(child, "rockchip,delay", &val))
+                       pwr_ctr->pwr_ctr.delay = val;
+               else
+                       pwr_ctr->pwr_ctr.delay = 0;
                list_add_tail(&pwr_ctr->list, &dev_drv->pwrlist_head);
        }
 
@@ -325,8 +337,9 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
                        if (pwr_ctr->rgl_name)
                                regulator_lcd = regulator_get(NULL, pwr_ctr->rgl_name);
                        if (regulator_lcd == NULL) {
-                               dev_err(dev_drv->dev, "%s: regulator get failed,regulator name:%s\n",
-                                           __func__, pwr_ctr->rgl_name);
+                               dev_err(dev_drv->dev,
+                                       "%s: regulator get failed,regulator name:%s\n",
+                                       __func__, pwr_ctr->rgl_name);
                                continue;
                        }
                        regulator_set_voltage(regulator_lcd, pwr_ctr->volt, pwr_ctr->volt);
@@ -334,7 +347,10 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv)
                                if (regulator_enable(regulator_lcd) == 0 || count == 0)
                                        break;
                                else
-                                       count--;
+                                       dev_err(dev_drv->dev,
+                                               "regulator_enable failed,count=%d\n",
+                                               count);
+                               count--;
                        }
                        regulator_put(regulator_lcd);
                        msleep(pwr_ctr->delay);
@@ -364,15 +380,19 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv)
                        if (pwr_ctr->rgl_name)
                                regulator_lcd = regulator_get(NULL, pwr_ctr->rgl_name);
                        if (regulator_lcd == NULL) {
-                               dev_err(dev_drv->dev, "%s: regulator get failed,regulator name:%s\n",
-                                           __func__, pwr_ctr->rgl_name);
+                               dev_err(dev_drv->dev,
+                                       "%s: regulator get failed,regulator name:%s\n",
+                                       __func__, pwr_ctr->rgl_name);
                                continue;
                        }
                        while (regulator_is_enabled(regulator_lcd) > 0) {
                                if (regulator_disable(regulator_lcd) == 0 || count == 0)
                                        break;
                                else
-                                       count--;
+                                       dev_err(dev_drv->dev,
+                                               "regulator_disable failed,count=%d\n",
+                                               count);
+                               count--;
                        }
                        regulator_put(regulator_lcd);
                }
@@ -1909,12 +1929,15 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv,
                win_data = rk_fb_get_win_data(regs, i);
                if (win_data) {
                        if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
-                            win_data->data_format == YUV420)
+                           (win_data->data_format == YUV420 ||
+                            win_data->data_format == YUV420_A))
                                continue;
+                       mutex_lock(&dev_drv->win_config);
                        rk_fb_update_win(dev_drv, win, win_data);
                        win->state = 1;
                        dev_drv->ops->set_par(dev_drv, i);
                        dev_drv->ops->pan_display(dev_drv, i);
+                       mutex_unlock(&dev_drv->win_config);
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                        if (dev_drv->iommu_enabled) {
                                g_last_addr[i] = win_data->reg_area_data[0].smem_start +
@@ -1974,12 +1997,26 @@ ext_win_exit:
                timeout = wait_event_interruptible_timeout(dev_drv->vsync_info.wait,
                                ktime_compare(dev_drv->vsync_info.timestamp, timestamp) > 0,
                                msecs_to_jiffies(25));
+               if ((rk_fb->disp_mode == DUAL) &&
+                   (hdmi_get_hotplug() == HDMI_HPD_ACTIVED) &&
+                   hdmi_switch_complete) {
+                       /*
+                        * If dual output, we need make sure the extend display
+                        * cfg take effect before release fence.
+                        */
+                       ext_dev_drv = rk_get_extend_lcdc_drv();
+                       timeout = wait_event_interruptible_timeout(ext_dev_drv->vsync_info.wait,
+                                       ktime_compare(ext_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++) {
                        if (dev_drv->win[i]->state == 1) {
                                if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
                                    (dev_drv->win[i]->format == YUV420 ||
+                                    dev_drv->win[i]->format == YUV420_A ||
                                     !strcmp(dev_drv->win[i]->name, "hwc"))) {
                                        continue;
                                } else {
@@ -2007,27 +2044,37 @@ ext_win_exit:
 #ifdef H_USE_FENCE
        sw_sync_timeline_inc(dev_drv->timeline, 1);
 #endif
-       if (!g_first_buf) {
+       if (dev_drv->front_regs) {
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled) {
+                       if (dev_drv->ops->mmu_en)
+                               dev_drv->ops->mmu_en(dev_drv);
                        freed_index = 0;
                        g_last_timeout = timeout;
                }
 #endif
-               for (i = 0; i < g_last_win_num; i++)
-                       rk_fb_free_dma_buf(dev_drv, &g_reg_win_data[i]);
+
+               mutex_lock(&dev_drv->front_lock);
+
+               for (i = 0; i < dev_drv->front_regs->win_num; i++) {
+                       win_data = &dev_drv->front_regs->reg_win_data[i];
+                       rk_fb_free_dma_buf(dev_drv, win_data);
+               }
+               kfree(dev_drv->front_regs);
+
+               mutex_unlock(&dev_drv->front_lock);
 
 #if defined(CONFIG_ROCKCHIP_IOMMU)
                if (dev_drv->iommu_enabled)
                        freed_addr[freed_index] = 0xfefefefe;
 #endif
        }
-       for (i = 0; i < regs->win_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;
+
+       mutex_lock(&dev_drv->front_lock);
+
+       dev_drv->front_regs = regs;
+
+       mutex_unlock(&dev_drv->front_lock);
 }
 
 static void rk_fb_update_regs_handler(struct kthread_work *work)
@@ -2045,7 +2092,6 @@ static void rk_fb_update_regs_handler(struct kthread_work *work)
        list_for_each_entry_safe(data, next, &saved_list, list) {
                rk_fb_update_reg(dev_drv, data);
                list_del(&data->list);
-               kfree(data);
        }
 
        if (dev_drv->wait_fs && list_empty(&dev_drv->update_regs_list))
@@ -2316,7 +2362,6 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        /* record buffer information for rk_fb_disp_scale to prevent fence timeout
         * because rk_fb_disp_scale will call function info->fbops->fb_set_par(info);
         */
-       fix->smem_start = reg_win_data->reg_area_data[0].smem_start;
        info->var.yoffset = yoffset;
        info->var.xoffset = xoffset;
        return 0;
@@ -2373,7 +2418,6 @@ static int rk_fb_set_win_config(struct fb_info *info,
        mutex_lock(&dev_drv->output_lock);
        if (!(dev_drv->suspend_flag == 0)) {
                rk_fb_update_reg(dev_drv, regs);
-               kfree(regs);
                printk(KERN_INFO "suspend_flag = 1\n");
                goto err;
        }
@@ -2440,7 +2484,6 @@ static int rk_fb_set_win_config(struct fb_info *info,
                } else if (ret == 0) {
                        rk_fb_update_reg(dev_drv, regs);
                }
-               kfree(regs);
        }
 
 err:
@@ -2670,6 +2713,10 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,
        case RK_FBIOSET_ENABLE:
                if (copy_from_user(&enable, argp, sizeof(enable)))
                        return -EFAULT;
+                               if (enable)
+                                       fb_par->state++;
+                               else
+                                       fb_par->state--;
                dev_drv->ops->open(dev_drv, win_id, enable);
                break;
        case RK_FBIOGET_ENABLE:
@@ -3229,6 +3276,9 @@ static int rk_fb_set_par(struct fb_info *info)
                         (win->format == ABGR888)) ? 1 : 0;
        win->g_alpha_val = 0;
 
+       if (rk_fb->disp_policy == DISPLAY_POLICY_BOX &&
+           (win->format == YUV420 || win->format == YUV420_A))
+           win->state = 1;
        if (rk_fb->disp_mode == DUAL) {
                if (extend_win->state && hdmi_switch_complete) {
                        if (info != extend_info) {
@@ -3495,8 +3545,10 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        info->var.grayscale |=
                                (dev_drv->cur_screen->mode.xres << 8) +
                                (dev_drv->cur_screen->mode.yres << 20);
+                       mutex_lock(&dev_drv->win_config);
                        info->fbops->fb_set_par(info);
                        info->fbops->fb_pan_display(&info->var, info);
+                       mutex_unlock(&dev_drv->win_config);
 
                        if (dev_drv->ops->dsp_black)
                                dev_drv->ops->dsp_black(dev_drv, 0);
@@ -3550,8 +3602,11 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                                        (dev_drv->cur_screen->xsize << 8) +
                                                        (dev_drv->cur_screen->ysize << 20);
                                        }
+
+                                       mutex_lock(&dev_drv->win_config);
                                        info->fbops->fb_set_par(info);
                                        info->fbops->fb_pan_display(&info->var, info);
+                                       mutex_unlock(&dev_drv->win_config);
                                }
                        }
                }
@@ -3638,9 +3693,11 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id)
                }
        }
 
+       mutex_lock(&dev_drv->win_config);
        info->fbops->fb_set_par(info);
-       /* info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0); */
        dev_drv->ops->cfg_done(dev_drv);
+       mutex_unlock(&dev_drv->win_config);
+
        return 0;
 }
 
@@ -3865,6 +3922,8 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        init_completion(&dev_drv->frame_done);
        spin_lock_init(&dev_drv->cpl_lock);
        mutex_init(&dev_drv->fb_win_id_mutex);
+       mutex_init(&dev_drv->win_config);
+       mutex_init(&dev_drv->front_lock);
        dev_drv->ops->fb_win_remap(dev_drv, dev_drv->fb_win_map);
        dev_drv->first_frame = 1;
        dev_drv->overscan.left = 100;
@@ -4042,7 +4101,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
        }
 
        /* show logo for primary display device */
-#if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO)
+#if !defined(CONFIG_FRAMEBUFFER_CONSOLE)
        if (dev_drv->prop == PRMRY) {
                struct fb_info *main_fbi = rk_fb->fb[0];
                main_fbi->fbops->fb_open(main_fbi, 1);
@@ -4057,6 +4116,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
 
                rk_fb_alloc_buffer(main_fbi, 0);        /* only alloc memory for main fb */
                dev_drv->uboot_logo = support_uboot_display();
+#if !defined(CONFIG_LOGO)
                if (support_uboot_display()) {
                        /*
                        if (dev_drv->iommu_enabled)
@@ -4064,6 +4124,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                        */
                        return 0;
                }
+#else
                main_fbi->fbops->fb_set_par(main_fbi);
 #if  defined(CONFIG_LOGO_LINUX_BMP)
                if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) {
@@ -4077,6 +4138,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                }
 #endif
                main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi);
+#endif
        } else {
                struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1];
                int extend_fb_id = get_extend_fb_id(extend_fbi);