rk3368 lcdc: overlay mode depend on screen color mode
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
old mode 100755 (executable)
new mode 100644 (file)
index b48edc5..25fa86b
@@ -35,7 +35,7 @@
 #include "bmp_helper.h"
 
 #if defined(CONFIG_RK_HDMI)
-#include "hdmi/rk_hdmi.h"
+#include "hdmi/rockchip-hdmi.h"
 #endif
 
 #if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2)
@@ -148,12 +148,15 @@ int rk_fb_pixel_width(int data_format)
        case XBGR888:
        case ABGR888:
        case ARGB888:
+       case FBDC_ARGB_888:
+       case FBDC_RGBX_888:
                pixel_width = 4 * 8;
                break;
        case RGB888:
                pixel_width = 3 * 8;
                break;
        case RGB565:
+       case FBDC_RGB_565:
                pixel_width = 2 * 8;
                break;
        case YUV422:
@@ -212,6 +215,15 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
                case HAL_PIXEL_FORMAT_YCrCb_420_SP_10:  /* yuv444 */
                        fb_data_fmt = YUV444_A;
                        break;
+               case HAL_PIXEL_FORMAT_FBDC_RGB565:      /* fbdc rgb565*/
+                       fb_data_fmt = FBDC_RGB_565;
+                       break;
+               case HAL_PIXEL_FORMAT_FBDC_U8U8U8U8:    /* fbdc argb888 */
+                       fb_data_fmt = FBDC_ARGB_888;
+                       break;
+               case HAL_PIXEL_FORMAT_FBDC_U8U8U8:      /* fbdc rgb888 */
+                       fb_data_fmt = FBDC_RGBX_888;
+                       break;
                default:
                        printk(KERN_WARNING "%s:un supported format:0x%x\n",
                               __func__, data_format);
@@ -427,6 +439,7 @@ int rk_fb_video_mode_from_timing(const struct display_timing *dt,
        screen->face = dt->face;
        screen->color_mode = dt->color_mode;
        screen->dsp_lut = dt->dsp_lut;
+       screen->cabc_lut = dt->cabc_lut;
 
        if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE)
                screen->pin_dclk = 1;
@@ -529,6 +542,15 @@ char *get_format_string(enum data_format format, char *fmt)
        case ABGR888:
                strcpy(fmt, "ABGR888");
                break;
+       case FBDC_RGB_565:
+               strcpy(fmt, "FBDC_RGB_565");
+               break;
+       case FBDC_ARGB_888:
+               strcpy(fmt, "FBDC_ARGB_888");
+               break;
+       case FBDC_RGBX_888:
+               strcpy(fmt, "FBDC_RGBX_888");
+               break;
        default:
                strcpy(fmt, "invalid");
                break;
@@ -1284,7 +1306,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var,
        }
 
        /* x y mirror ,jump line */
-       if (screen->y_mirror == 1) {
+       if ((screen->y_mirror == 1) ||
+           (win->mirror_en == 1)) {
                if (screen->interlace == 1) {
                        win->area[0].y_offset = yoffset * stride * 2 +
                            ((win->area[0].yact - 1) * 2 + 1) * stride +
@@ -1304,7 +1327,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var,
                }
        }
        if (is_pic_yuv == 1) {
-               if (screen->y_mirror == 1) {
+               if ((screen->y_mirror == 1) ||
+                   (win->mirror_en == 1)) {
                        if (screen->interlace == 1) {
                                win->area[0].c_offset =
                                    uv_y_off * uv_stride * 2 +
@@ -1784,7 +1808,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        struct fb_fix_screeninfo *fix = &info->fix;
        struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par;
        struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv;
-       struct rk_screen *screen = dev_drv->cur_screen;
+       /*if hdmi size move to hwc,screen should point to cur_screen*/
+       struct rk_screen *screen = dev_drv->screen0;/*cur_screen;*/
        struct fb_info *fbi;
        int i, ion_fd, acq_fence_fd;
        u32 xvir, yvir;
@@ -1874,19 +1899,22 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        }
 
        reg_win_data->mirror_en = win_par->mirror_en;
-       reg_win_data->reg_area_data[0].fbdc_en = win_par->area_par[0].fbdc_en;
-       reg_win_data->reg_area_data[0].fbdc_cor_en =
-               win_par->area_par[0].fbdc_cor_en;
-       reg_win_data->reg_area_data[0].fbdc_data_format =
-               win_par->area_par[0].fbdc_data_format;
        for (i = 0; i < reg_win_data->area_num; i++) {
                rk_fb_check_config_var(&win_par->area_par[i], screen);
 
                fb_data_fmt = rk_fb_data_fmt(win_par->area_par[i].data_format, 0);
                reg_win_data->reg_area_data[i].data_format = fb_data_fmt;
+               if (fb_data_fmt >= FBDC_RGB_565) {
+                       reg_win_data->reg_area_data[i].fbdc_en = 1;
+                       reg_win_data->reg_area_data[i].fbdc_cor_en = 1;
+               } else {
+                       reg_win_data->reg_area_data[i].fbdc_en = 0;
+                       reg_win_data->reg_area_data[i].fbdc_cor_en = 0;
+               }
                pixel_width = rk_fb_pixel_width(fb_data_fmt);
 
                ppixel_a |= ((fb_data_fmt == ARGB888) ||
+                            (fb_data_fmt == FBDC_ARGB_888) ||
                             (fb_data_fmt == ABGR888)) ? 1 : 0;
                /* visiable pos in panel */
                reg_win_data->reg_area_data[i].xpos = win_par->area_par[i].xpos;
@@ -2040,6 +2068,12 @@ static int rk_fb_set_win_config(struct fb_info *info,
        int ret = 0, i, j = 0;
        int list_is_empty = 0;
 
+       if (dev_drv->suspend_flag) {
+               dev_drv->timeline_max++;
+               sw_sync_timeline_inc(dev_drv->timeline, 1);
+               return 0;
+       }
+
        regs = kzalloc(sizeof(struct rk_fb_reg_data), GFP_KERNEL);
        if (!regs) {
                printk(KERN_INFO "could not allocate rk_fb_reg_data\n");
@@ -2073,11 +2107,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);
-               printk(KERN_INFO "suspend_flag = 1\n");
-               goto err;
-       }
 
        dev_drv->timeline_max++;
 #ifdef H_USE_FENCE
@@ -2106,6 +2135,7 @@ static int rk_fb_set_win_config(struct fb_info *info,
        win_data->ret_fence_fd = get_unused_fd();
        if (win_data->ret_fence_fd < 0) {
                printk("ret_fence_fd=%d\n", win_data->ret_fence_fd);
+               win_data->ret_fence_fd = -1;
                ret = -EFAULT;
                goto err;
        }
@@ -2725,6 +2755,13 @@ static int rk_fb_set_par(struct fb_info *info)
        }
 
        fb_data_fmt = rk_fb_data_fmt(data_format, var->bits_per_pixel);
+       if (fb_data_fmt >= FBDC_RGB_565) {
+               win->area[0].fbdc_en = 1;
+               win->area[0].fbdc_cor_en = 1;
+       } else {
+               win->area[0].fbdc_en = 0;
+               win->area[0].fbdc_cor_en = 0;
+       }
        pixel_width = rk_fb_pixel_width(fb_data_fmt);
        vir_width_bit = pixel_width * xvir;
        /* pixel_width = byte_num * 8 */
@@ -2771,51 +2808,6 @@ static int rk_fb_set_par(struct fb_info *info)
                break;
        }
 
-       /* x y mirror ,jump line */
-       if (screen->y_mirror == 1) {
-               if (screen->interlace == 1) {
-                       win->area[0].y_offset = yoffset * stride * 2 +
-                           ((win->area[0].yact - 1) * 2 + 1) * stride +
-                           xoffset * pixel_width / 8;
-               } else {
-                       win->area[0].y_offset = yoffset * stride +
-                           (win->area[0].yact - 1) * stride +
-                           xoffset * pixel_width / 8;
-               }
-       } else {
-               if (screen->interlace == 1) {
-                       win->area[0].y_offset =
-                           yoffset * stride * 2 + xoffset * pixel_width / 8;
-               } else {
-                       win->area[0].y_offset =
-                           yoffset * stride + xoffset * pixel_width / 8;
-               }
-       }
-       if (is_pic_yuv == 1) {
-               if (screen->y_mirror == 1) {
-                       if (screen->interlace == 1) {
-                               win->area[0].c_offset =
-                                   uv_y_off * uv_stride * 2 +
-                                   ((uv_y_act - 1) * 2 + 1) * uv_stride +
-                                   uv_x_off * pixel_width / 8;
-                       } else {
-                               win->area[0].c_offset = uv_y_off * uv_stride +
-                                   (uv_y_act - 1) * uv_stride +
-                                   uv_x_off * pixel_width / 8;
-                       }
-               } else {
-                       if (screen->interlace == 1) {
-                               win->area[0].c_offset =
-                                   uv_y_off * uv_stride * 2 +
-                                   uv_x_off * pixel_width / 8;
-                       } else {
-                               win->area[0].c_offset =
-                                   uv_y_off * uv_stride +
-                                   uv_x_off * pixel_width / 8;
-                       }
-               }
-       }
-
        win->area[0].format = fb_data_fmt;
        win->area[0].y_vir_stride = stride >> 2;
        win->area[0].uv_vir_stride = uv_stride >> 2;
@@ -2833,6 +2825,7 @@ static int rk_fb_set_par(struct fb_info *info)
        win->area_num = 1;
        win->alpha_mode = 4;    /* AB_SRC_OVER; */
        win->alpha_en = ((win->area[0].format == ARGB888) ||
+                        (win->area[0].format == FBDC_ARGB_888) ||
                         (win->area[0].format == ABGR888)) ? 1 : 0;
        win->g_alpha_val = 0;
 
@@ -2908,6 +2901,7 @@ static struct fb_ops fb_ops = {
        .fb_set_par = rk_fb_set_par,
        .fb_blank = rk_fb_blank,
        .fb_ioctl = rk_fb_ioctl,
+       .fb_compat_ioctl = rk_fb_ioctl,
        .fb_pan_display = rk_fb_pan_display,
        .fb_read = rk_fb_read,
        .fb_write = rk_fb_write,
@@ -3071,11 +3065,17 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        if (enable == 2 /*&& dev_drv->enable*/)
                return 0;
 
-       if (rk_fb->disp_mode == ONE_DUAL) {
+       if ((rk_fb->disp_mode == ONE_DUAL) ||
+           (rk_fb->disp_mode == NO_DUAL)) {
+               if ((dev_drv->ops->backlight_close) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
+                       dev_drv->ops->backlight_close(dev_drv, 1);
                if (dev_drv->ops->dsp_black)
                        dev_drv->ops->dsp_black(dev_drv, 1);
-               if (dev_drv->ops->set_screen_scaler)
-                       dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 0);
+               if ((dev_drv->ops->set_screen_scaler) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
+                       dev_drv->ops->set_screen_scaler(dev_drv,
+                                                       dev_drv->screen0, 0);
        }
        if (dev_drv->uboot_logo && (screen->type != dev_drv->cur_screen->type))
                dev_drv->uboot_logo = 0;
@@ -3085,7 +3085,8 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        return 0;
 
                /* if used one lcdc to dual disp, no need to close win */
-               if (rk_fb->disp_mode == ONE_DUAL) {
+               if ((rk_fb->disp_mode == ONE_DUAL) ||
+                   (rk_fb->disp_mode == NO_DUAL)) {
                        dev_drv->cur_screen = dev_drv->screen0;
                        dev_drv->ops->load_screen(dev_drv, 1);
 
@@ -3102,9 +3103,14 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
 
                        if (dev_drv->ops->dsp_black)
                                dev_drv->ops->dsp_black(dev_drv, 0);
-               } else if (rk_fb->num_lcdc > 1 && rk_fb->disp_policy == DISPLAY_POLICY_BOX) {
+                       if ((dev_drv->ops->backlight_close) &&
+                           (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
+                               dev_drv->ops->backlight_close(dev_drv, 0);
+               } else if (rk_fb->num_lcdc > 1) {
                        /* If there is more than one lcdc device, we disable
                           the layer which attached to this device */
+                       dev_drv->suspend_flag = 1;
+                       flush_kthread_worker(&dev_drv->update_regs_worker);
                        for (i = 0; i < dev_drv->lcdc_win_num; i++) {
                                if (dev_drv->win[i] && dev_drv->win[i]->state)
                                        dev_drv->ops->open(dev_drv, i, 0);
@@ -3116,6 +3122,7 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
        } else {
                if (dev_drv->screen1)
                        dev_drv->cur_screen = dev_drv->screen1;
+
                memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen));
                dev_drv->cur_screen->xsize = dev_drv->cur_screen->mode.xres;
                dev_drv->cur_screen->ysize = dev_drv->cur_screen->mode.yres;
@@ -3130,8 +3137,10 @@ 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);
                        if (dev_drv->win[win_id]) {
                                if (fb_par->state) {
-                                       if (!dev_drv->win[win_id]->state)
+                                       if (!dev_drv->win[win_id]->state) {
                                                dev_drv->ops->open(dev_drv, win_id, 1);
+                                               dev_drv->suspend_flag = 0;
+                                       }
                                        if (!load_screen) {
                                                dev_drv->ops->load_screen(dev_drv, 1);
                                                load_screen = 1;
@@ -3155,11 +3164,16 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                dev_drv->uboot_logo = 0;
        }
        hdmi_switch_complete = 1;
-       if (rk_fb->disp_mode == ONE_DUAL) {
-               if (dev_drv->ops->set_screen_scaler)
+       if ((rk_fb->disp_mode == ONE_DUAL) || (rk_fb->disp_mode == NO_DUAL)) {
+               if ((dev_drv->ops->set_screen_scaler) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX))
                        dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 1);
                if (dev_drv->ops->dsp_black)
                        dev_drv->ops->dsp_black(dev_drv, 0);
+               if ((dev_drv->ops->backlight_close) &&
+                   (rk_fb->disp_policy != DISPLAY_POLICY_BOX) &&
+                   (rk_fb->disp_mode == ONE_DUAL))
+                       dev_drv->ops->backlight_close(dev_drv, 0);
        }
        return 0;
 }
@@ -3416,7 +3430,7 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb,
        dev_drv->screen0 = screen;
        dev_drv->cur_screen = screen;
        /* devie use one lcdc + rk61x scaler for dual display */
-       if (rk_fb->disp_mode == ONE_DUAL) {
+       if ((rk_fb->disp_mode == ONE_DUAL) || (rk_fb->disp_mode == NO_DUAL)) {
                struct rk_screen *screen1 =
                                devm_kzalloc(dev_drv->dev,
                                             sizeof(struct rk_screen),
@@ -3657,8 +3671,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                        vaddr = vmap(pages, nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
                        if (!vaddr) {
-                               pr_err("failed to vmap phy addr %x\n",
-                                       uboot_logo_base + uboot_logo_offset);
+                               pr_err("failed to vmap phy addr 0x%lx\n",
+                                      (long)(uboot_logo_base +
+                                      uboot_logo_offset));
                                return -1;
                        }
 
@@ -3692,7 +3707,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
 
                        return 0;
                } else if (dev_drv->uboot_logo && uboot_logo_base) {
-                       phys_addr_t start = uboot_logo_base;
+                       u32 start = uboot_logo_base;
                        int logo_len, i=0;
                        unsigned int nr_pages;
                        struct page **pages;
@@ -3719,8 +3734,8 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                        vaddr = vmap(pages, nr_pages, VM_MAP,
                                        pgprot_writecombine(PAGE_KERNEL));
                        if (!vaddr) {
-                               pr_err("failed to vmap phy addr %x\n",
-                                       uboot_logo_base);
+                               pr_err("failed to vmap phy addr 0x%llx\n",
+                                      uboot_logo_base);
                                return -1;
                        }
 
@@ -3740,6 +3755,10 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                freed_index = 0;
                        }
                        return 0;
+               } else {
+                       if (dev_drv->ops->mmu_en)
+                               dev_drv->ops->mmu_en(dev_drv);
+                       freed_index = 0;
                }
 #if defined(CONFIG_LOGO)
                main_fbi->fbops->fb_set_par(main_fbi);