video: rockchip: fb: no need close all win when hdmi switch screen at first time
[firefly-linux-kernel-4.4.55.git] / drivers / video / rockchip / rk_fb.c
index ab794068038955ddc694f2e47dacdad192a0b6c1..c8393580a0591778ece9416f72190590b7192b06 100644 (file)
@@ -31,6 +31,8 @@
 #include <linux/linux_logo.h>
 #include <linux/dma-mapping.h>
 #include <linux/regulator/consumer.h>
+#include <linux/of_address.h>
+#include <linux/memblock.h>
 
 #include "bmp_helper.h"
 
@@ -192,6 +194,12 @@ int rk_fb_pixel_width(int data_format)
        case YUV444_A:
                pixel_width = 8;
                break;
+       case YUYV422:
+       case UYVY422:
+       case YUYV420:
+       case UYVY420:
+               pixel_width = 16;
+               break;
        default:
                pr_warn("%s: unsupported format: 0x%x\n",
                        __func__, data_format);
@@ -202,7 +210,7 @@ int rk_fb_pixel_width(int data_format)
 
 static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
 {
-       int fb_data_fmt;
+       int fb_data_fmt = 0;
 
        if (data_format) {
                switch (data_format) {
@@ -263,6 +271,18 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel)
                case HAL_PIXEL_FORMAT_FBDC_U8U8U8:      /* fbdc rgb888 */
                        fb_data_fmt = FBDC_RGBX_888;
                        break;
+               case HAL_PIXEL_FORMAT_YUYV422:          /* yuyv422 */
+                       fb_data_fmt = YUYV422;
+                       break;
+               case HAL_PIXEL_FORMAT_YUYV420:          /* yuyv420 */
+                       fb_data_fmt = YUYV420;
+                       break;
+               case HAL_PIXEL_FORMAT_UYVY422:          /* uyvy422 */
+                       fb_data_fmt = UYVY422;
+                       break;
+               case HAL_PIXEL_FORMAT_UYVY420:          /* uyvy420 */
+                       fb_data_fmt = UYVY420;
+                       break;
                default:
                        pr_warn("%s: unsupported format: 0x%x\n",
                                __func__, data_format);
@@ -477,6 +497,8 @@ int rk_fb_video_mode_from_timing(const struct display_timing *dt,
        screen->lvds_format = dt->lvds_format;
        screen->face = dt->face;
        screen->color_mode = dt->color_mode;
+       screen->width = dt->screen_widt;
+       screen->height = dt->screen_hight;
        screen->dsp_lut = dt->dsp_lut;
        screen->cabc_lut = dt->cabc_lut;
        screen->cabc_gamma_base = dt->cabc_gamma_base;
@@ -602,6 +624,18 @@ char *get_format_string(enum data_format format, char *fmt)
        case FBDC_RGBX_888:
                strcpy(fmt, "FBDC_RGBX_888");
                break;
+       case YUYV422:
+               strcpy(fmt, "YUYV422");
+               break;
+       case YUYV420:
+               strcpy(fmt, "YUYV420");
+               break;
+       case UYVY422:
+               strcpy(fmt, "UYVY422");
+               break;
+       case UYVY420:
+               strcpy(fmt, "UYVY420");
+               break;
        default:
                strcpy(fmt, "invalid");
                break;
@@ -1626,6 +1660,7 @@ static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv,
                                win->area[i].smem_start =
                                        reg_win_data->reg_area_data[i].smem_start;
                                if (inf->disp_mode == DUAL ||
+                                   inf->disp_mode == DUAL_LCD ||
                                    inf->disp_mode == NO_DUAL) {
                                        win->area[i].xpos =
                                                reg_win_data->reg_area_data[i].xpos;
@@ -2164,24 +2199,24 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
        struct rk_screen *screen = dev_drv->cur_screen;/*screen0;*/
        struct fb_info *fbi;
        int i, ion_fd, acq_fence_fd;
-       u32 xvir, yvir;
-       u32 xoffset, yoffset;
+       u32 xvir = 0, yvir = 0;
+       u32 xoffset = 0, yoffset = 0;
 
        struct ion_handle *hdl;
        size_t len;
-       int index_buf;
-       u8 fb_data_fmt;
-       u8 pixel_width;
-       u32 vir_width_bit;
-       u32 stride, uv_stride;
-       u32 stride_32bit_1;
-       u32 stride_32bit_2;
-       u16 uv_x_off, uv_y_off, uv_y_act;
+       int index_buf = 0;
+       u8 fb_data_fmt = 0;
+       u8 pixel_width = 0;
+       u32 vir_width_bit = 0;
+       u32 stride = 0, uv_stride = 0;
+       u32 stride_32bit_1 = 0;
+       u32 stride_32bit_2 = 0;
+       u16 uv_x_off = 0, uv_y_off = 0, uv_y_act = 0;
        u8 is_pic_yuv = 0;
        u8 ppixel_a = 0, global_a = 0;
        ion_phys_addr_t phy_addr;
        int ret = 0;
-       int buff_len;
+       int buff_len = 0;
 
        reg_win_data->reg_area_data[0].smem_start = -1;
        reg_win_data->area_num = 0;
@@ -2194,8 +2229,10 @@ static int rk_fb_set_win_buffer(struct fb_info *info,
                                    ion_import_dma_buf(rk_fb->ion_client,
                                                       ion_fd);
                                if (IS_ERR(hdl)) {
-                                       pr_info("%s: Could not import handle:"
-                                               " %ld\n", __func__, (long)hdl);
+                                       pr_info("%s: win[%d]area[%d] can't import handle\n",
+                                               __func__, win_par->win_id, i);
+                                       pr_info("fd: %d, hdl: 0x%p, ion_client: 0x%p\n",
+                                               ion_fd, hdl, rk_fb->ion_client);
                                        return -EINVAL;
                                        break;
                                }
@@ -2615,6 +2652,7 @@ err_null_frame:
        win_data->ret_fence_fd = -1;
        pr_info("win num = %d,null frame\n", regs->win_num);
 err2:
+       rk_fb_config_debug(dev_drv, win_data, regs, 0);
        kfree(regs);
        mutex_unlock(&dev_drv->output_lock);
 
@@ -3155,9 +3193,9 @@ static int rk_fb_set_par(struct fb_info *info)
        u32 xvir = var->xres_virtual;
        u8 data_format = var->nonstd & 0xff;
        u8 fb_data_fmt;
-       u8 pixel_width;
+       u8 pixel_width = 0;
        u32 vir_width_bit;
-       u32 stride, uv_stride;
+       u32 stride, uv_stride = 0;
        u32 stride_32bit_1;
        u32 stride_32bit_2;
        u16 uv_x_off, uv_y_off, uv_y_act;
@@ -3521,10 +3559,10 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                }
        }
 
-       envp[0] = "switch screen";
+       envp[0] = "switch vop screen";
        memset(envplcdc, 0, sizeof(envplcdc));
        memset(envpfbdev, 0, sizeof(envpfbdev));
-       sprintf(envplcdc, "SCREEN=%d,ENABLE=%d", screen->type, enable);
+       sprintf(envplcdc, "SCREEN=%d,ENABLE=%d,VOPID=%d", screen->type, enable, dev_drv->id);
        sprintf(envpfbdev, "FBDEV=%d", dev_drv->fb_index_base);
        envp[1] = envplcdc;
        envp[2] = envpfbdev;
@@ -3594,7 +3632,6 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                        /* 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)
@@ -3608,6 +3645,13 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                mutex_unlock(&dev_drv->switch_screen);
                return 0;
        } else {
+               if (load_screen || (rk_fb->disp_policy != DISPLAY_POLICY_BOX)) {
+                       for (i = 0; i < dev_drv->lcdc_win_num; i++) {
+                               if (dev_drv->win[i] && dev_drv->win[i]->state &&
+                                       dev_drv->ops->win_direct_en)
+                                       dev_drv->ops->win_direct_en(dev_drv, i, 0);
+                       }
+               }
                if (dev_drv->uboot_logo) {
                        if (dev_drv->cur_screen->mode.xres !=
                                screen->mode.xres ||
@@ -3624,6 +3668,7 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR;
                dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR;
        }
+
        if (!dev_drv->uboot_logo || load_screen ||
            (rk_fb->disp_policy != DISPLAY_POLICY_BOX)) {
                for (i = 0; i < dev_drv->lcdc_win_num; i++) {
@@ -3660,14 +3705,15 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id)
                                        dev_drv->ops->cfg_done(dev_drv);
                                } else if (!dev_drv->win[win_id]->state) {
                                        dev_drv->ops->open(dev_drv, win_id, 1);
-                                       dev_drv->suspend_flag = 0;
-                                       mutex_lock(&dev_drv->win_config);
-                                       info->var.xoffset = 0;
-                                       info->var.yoffset = 0;
-                                       info->fbops->fb_set_par(info);
-                                       info->fbops->fb_pan_display(&info->var,
-                                                                   info);
-                                       mutex_unlock(&dev_drv->win_config);
+                                       /* dev_drv->suspend_flag = 0; */
+                                       /* mutex_lock(&dev_drv->win_config);
+                                        * info->var.xoffset = 0;
+                                        * info->var.yoffset = 0;
+                                        * info->fbops->fb_set_par(info);
+                                        * info->fbops->fb_pan_display(&info->var,
+                                        *                          info);
+                                        * mutex_unlock(&dev_drv->win_config);
+                                        */
                                }
                        }
                }
@@ -4093,9 +4139,28 @@ bool is_prmry_rk_lcdc_registered(void)
                return false;
 }
 
-__weak phys_addr_t uboot_logo_base;
-__weak phys_addr_t uboot_logo_size;
-__weak phys_addr_t uboot_logo_offset;
+phys_addr_t uboot_logo_base;
+phys_addr_t uboot_logo_size;
+phys_addr_t uboot_logo_offset;
+
+static int __init rockchip_uboot_mem_late_init(void)
+{
+       int err;
+
+       if (uboot_logo_size) {
+               void *start = phys_to_virt(uboot_logo_base);
+               void *end = phys_to_virt(uboot_logo_base + uboot_logo_size);
+
+               err = memblock_free(uboot_logo_base, uboot_logo_size);
+               if (err < 0)
+                       pr_err("%s: freeing memblock failed: %d\n",
+                              __func__, err);
+               free_reserved_area(start, end, -1, "logo");
+       }
+       return 0;
+}
+
+late_initcall(rockchip_uboot_mem_late_init);
 
 int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                   struct rk_lcdc_win *win, int id)
@@ -4142,6 +4207,8 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                fbi->fix = def_fix;
                sprintf(fbi->fix.id, "fb%d", rk_fb->num_fb);
                fb_videomode_to_var(&fbi->var, &dev_drv->cur_screen->mode);
+               fbi->var.width = dev_drv->cur_screen->width;
+               fbi->var.height = dev_drv->cur_screen->height;
                fbi->var.grayscale |=
                    (fbi->var.xres << 8) + (fbi->var.yres << 20);
 #if defined(CONFIG_LOGO_LINUX_BMP)
@@ -4257,8 +4324,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                start += PAGE_SIZE;
                                i++;
                        }
-                       vaddr = vmap(pages, nr_pages, VM_MAP,
-                                    pgprot_writecombine(PAGE_KERNEL));
+                       vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
                        if (!vaddr) {
                                pr_err("failed to vmap phy addr 0x%lx\n",
                                       (long)(uboot_logo_base +
@@ -4332,8 +4398,7 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                                start += PAGE_SIZE;
                                i++;
                        }
-                       vaddr = vmap(pages, nr_pages, VM_MAP,
-                                    pgprot_writecombine(PAGE_KERNEL));
+                       vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL);
                        if (!vaddr) {
                                pr_err("failed to vmap phy addr 0x%x\n",
                                       start);
@@ -4389,13 +4454,15 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv,
                struct fb_info *extend_fbi = rk_fb->fb[dev_drv->fb_index_base];
 
                extend_fbi->var.pixclock = rk_fb->fb[0]->var.pixclock;
-               extend_fbi->fbops->fb_open(extend_fbi, 1);
-               if (dev_drv->iommu_enabled) {
-                       if (dev_drv->mmu_dev)
-                               rockchip_iovmm_set_fault_handler(dev_drv->dev,
-                                                                rk_fb_sysmmu_fault_handler);
+               if (rk_fb->disp_mode == DUAL_LCD) {
+                       extend_fbi->fbops->fb_open(extend_fbi, 1);
+                       if (dev_drv->iommu_enabled) {
+                               if (dev_drv->mmu_dev)
+                                       rockchip_iovmm_set_fault_handler(dev_drv->dev,
+                                                                        rk_fb_sysmmu_fault_handler);
+                       }
+                       rk_fb_alloc_buffer(extend_fbi);
                }
-               rk_fb_alloc_buffer(extend_fbi);
        }
 #endif
        return 0;
@@ -4433,7 +4500,8 @@ static int rk_fb_probe(struct platform_device *pdev)
 {
        struct rk_fb *rk_fb = NULL;
        struct device_node *np = pdev->dev.of_node;
-       u32 mode;
+       u32 mode, ret;
+       struct device_node *node;
 
        if (!np) {
                dev_err(&pdev->dev, "Missing device tree node.\n");
@@ -4475,6 +4543,27 @@ static int rk_fb_probe(struct platform_device *pdev)
        }
 #endif
 
+       node = of_parse_phandle(np, "memory-region", 0);
+       if (node) {
+               struct resource r;
+
+               ret = of_address_to_resource(node, 0, &r);
+               if (ret)
+                       return ret;
+
+               if (uboot_logo_on) {
+                       uboot_logo_base = r.start;
+                       uboot_logo_size = resource_size(&r);
+
+                       if (uboot_logo_size > SZ_16M)
+                               uboot_logo_offset = SZ_16M;
+                       else
+                               uboot_logo_offset = 0;
+               }
+               pr_info("logo: base=0x%llx, size=0x%llx, offset=0x%llx\n",
+                       uboot_logo_base, uboot_logo_size, uboot_logo_offset);
+       }
+
        fb_pdev = pdev;
        dev_info(&pdev->dev, "rockchip framebuffer driver probe\n");
        return 0;