X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Frockchip%2Frk_fb.c;h=3cbe44505371c9146e71696f49dd419c83ef8653;hb=157773d85660deae25d3ca848bece504bce60dbb;hp=bfc6aec5bb9cb8074ce386592051e79cb883162c;hpb=5f159debc66288b552095acce08c2097db23b052;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index bfc6aec5bb9c..3cbe44505371 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -348,6 +348,7 @@ 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->dsp_lut = dt->dsp_lut; if (dt->flags & DISPLAY_FLAGS_PIXDATA_POSEDGE) screen->pin_dclk = 1; @@ -993,7 +994,8 @@ static void rga_win_check(struct rk_lcdc_win *dst_win, } static void win_copy_by_rga(struct rk_lcdc_win *dst_win, - struct rk_lcdc_win *src_win, u16 orientation) + struct rk_lcdc_win *src_win, + u16 orientation, int iommu_en) { struct rga_req Rga_Request; long ret = 0; @@ -1073,8 +1075,13 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, Rga_Request.clip.ymax = dst_win->area[0].yact - 1; Rga_Request.scale_mode = 0; #if defined(CONFIG_ROCKCHIP_IOMMU) - Rga_Request.mmu_info.mmu_en = 1; /* TODO Modify for use mmu */ - Rga_Request.mmu_info.mmu_flag = 1; + if (iommu_en) { + Rga_Request.mmu_info.mmu_en = 1; + Rga_Request.mmu_info.mmu_flag = 1; + } else { + Rga_Request.mmu_info.mmu_en = 0; + Rga_Request.mmu_info.mmu_flag = 0; + } #else Rga_Request.mmu_info.mmu_en = 0; Rga_Request.mmu_info.mmu_flag = 0; @@ -1104,7 +1111,8 @@ static void fb_copy_by_rga(struct fb_info *dst_info, struct fb_info *src_info, ext_dev_drv->ops->fb_get_win_id(ext_dev_drv, dst_info->fix.id); dst_win = ext_dev_drv->win[ext_win_id]; - win_copy_by_rga(dst_win, src_win, ext_dev_drv->rotate_mode); + win_copy_by_rga(dst_win, src_win, ext_dev_drv->rotate_mode, + ext_dev_drv->iommu_enabled); } #endif @@ -1123,10 +1131,11 @@ static int rk_fb_rotate(struct fb_info *dst_info, } static int rk_fb_win_rotate(struct rk_lcdc_win *dst_win, - struct rk_lcdc_win *src_win, u16 rotate) + struct rk_lcdc_win *src_win, + u16 rotate, int iommu_en) { #if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) - win_copy_by_rga(dst_win, src_win, rotate); + win_copy_by_rga(dst_win, src_win, rotate, iommu_en); #else return -1; #endif @@ -1161,6 +1170,11 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, u32 stride_32bit_2; u16 uv_x_off, uv_y_off, uv_y_act; u8 is_pic_yuv = 0; +#ifdef CONFIG_ROCKCHIP_IOMMU + ion_phys_addr_t phy_addr; + size_t len = 0; + int ret = 0; +#endif win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); if (win_id < 0) @@ -1273,16 +1287,40 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, dev_drv->ops->pan_display(dev_drv, win_id); if (rk_fb->disp_mode == DUAL) { - if (extend_win->state && (hdmi_switch_complete)) { + if (extend_win->state && + (hdmi_switch_complete & (1 << extend_win_id))) { extend_win->area[0].y_offset = win->area[0].y_offset; if (extend_dev_drv->rotate_mode > X_Y_MIRROR) { rk_fb_rotate(extend_info, info, win->area[0].y_offset); } else { +#ifdef CONFIG_ROCKCHIP_IOMMU + if (extend_dev_drv->iommu_enabled) { + ret = ion_map_iommu(extend_dev_drv->dev, + rk_fb->ion_client, + win->area[0].ion_hdl, + (unsigned long *)&phy_addr, + (unsigned long *)&len); + if (ret < 0) { + dev_err(extend_dev_drv->dev, "ion map to get phy addr failed\n"); + ion_free(rk_fb->ion_client, win->area[0].ion_hdl); + return -ENOMEM; + } + extend_win->area[0].smem_start = phy_addr; + extend_win->area[0].cbr_start = + win->area[0].cbr_start; + } else { + extend_win->area[0].smem_start = + win->area[0].smem_start; + extend_win->area[0].cbr_start = + win->area[0].cbr_start; + } +#else extend_win->area[0].smem_start = win->area[0].smem_start; extend_win->area[0].cbr_start = win->area[0].cbr_start; +#endif } extend_dev_drv->ops->pan_display(extend_dev_drv, extend_win_id); @@ -1393,6 +1431,9 @@ void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv, int i, index_buf; struct rk_fb_reg_area_data *area_data; struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); +#if defined(CONFIG_ROCKCHIP_IOMMU) + struct rk_lcdc_driver *ext_dev_drv = rk_get_extend_lcdc_drv(); +#endif for (i = 0; i < reg_win_data->area_num; i++) { area_data = ®_win_data->reg_area_data[i]; @@ -1403,6 +1444,12 @@ void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv, area_data->ion_handle); freed_addr[freed_index++] = area_data->smem_start; } + if (rk_fb->disp_mode == DUAL && hdmi_switch_complete == 0xff) { + if (ext_dev_drv->iommu_enabled) + ion_unmap_iommu(ext_dev_drv->dev, + rk_fb->ion_client, + area_data->ion_handle); + } #endif if (area_data->ion_handle != NULL) { ion_unmap_kernel(rk_fb->ion_client, @@ -1452,8 +1499,10 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, win->g_alpha_val = reg_win_data->g_alpha_val; for (i = 0; i < RK_WIN_MAX_AREA; i++) { if (reg_win_data->reg_area_data[i].smem_start > 0) { + win->area[i].ion_hdl = + reg_win_data->reg_area_data[i].ion_handle; win->area[i].smem_start = - reg_win_data->reg_area_data[i].smem_start; + reg_win_data->reg_area_data[i].smem_start; if (inf->disp_mode == DUAL) { win->area[i].xpos = reg_win_data->reg_area_data[i].xpos; @@ -1520,10 +1569,14 @@ static int rk_fb_update_hdmi_win(struct rk_lcdc_win *ext_win, struct rk_lcdc_win *last_win; bool is_yuv = false; static u8 fb_index = 0; - +#ifdef CONFIG_ROCKCHIP_IOMMU + ion_phys_addr_t phy_addr; + size_t len = 0; + int ret = 0; +#endif if ((rk_fb->disp_mode != DUAL) || (hdmi_get_hotplug() != HDMI_HPD_ACTIVED) || - (!hdmi_switch_complete)) { + (hdmi_switch_complete != 0xff)) { printk(KERN_INFO "%s: hdmi is disconnect!\n", __func__); return -1; } @@ -1602,7 +1655,25 @@ static int rk_fb_update_hdmi_win(struct rk_lcdc_win *ext_win, y_stride = ALIGN_N_TIMES(vir_width_bit, 32) / 8; ext_win->area[0].y_vir_stride = y_stride >> 2; } else { +#ifdef CONFIG_ROCKCHIP_IOMMU + if (ext_dev_drv->iommu_enabled) { + ret = ion_map_iommu(ext_dev_drv->dev, + rk_fb->ion_client, + win->area[0].ion_hdl, + (unsigned long *)&phy_addr, + (unsigned long *)&len); + if (ret < 0) { + dev_err(ext_dev_drv->dev, "ion map to get phy addr failed\n"); + ion_free(rk_fb->ion_client, win->area[0].ion_hdl); + return -ENOMEM; + } + ext_win->area[0].smem_start = phy_addr; + } else { + ext_win->area[0].smem_start = win->area[0].smem_start; + } +#else ext_win->area[0].smem_start = win->area[0].smem_start; +#endif ext_win->area[0].y_offset = win->area[0].y_offset; ext_win->area[0].xact = win->area[0].xact; ext_win->area[0].yact = win->area[0].yact; @@ -1682,7 +1753,17 @@ static int rk_fb_update_hdmi_win(struct rk_lcdc_win *ext_win, ext_win->area[0].c_offset = win->area[0].c_offset; } else { ext_win->area[0].uv_vir_stride = win->area[0].uv_vir_stride; +#ifdef CONFIG_ROCKCHIP_IOMMU + if (ext_dev_drv->iommu_enabled) + ext_win->area[0].cbr_start = + ext_win->area[0].smem_start + + ext_win->area[0].y_offset + + ext_win->area[0].xvir * ext_win->area[0].yvir; + else + ext_win->area[0].cbr_start = win->area[0].cbr_start; +#else ext_win->area[0].cbr_start = win->area[0].cbr_start; +#endif ext_win->area[0].c_offset = win->area[0].c_offset; } @@ -1753,7 +1834,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, if ((rk_fb->disp_mode == DUAL) && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED) - && hdmi_switch_complete) { + && (hdmi_switch_complete == 0xff)) { ext_dev_drv = rk_get_extend_lcdc_drv(); if (!ext_dev_drv) { printk(KERN_ERR "hdmi lcdc driver not found!\n"); @@ -1775,7 +1856,8 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, if (ext_dev_drv->rotate_mode > X_Y_MIRROR) rk_fb_win_rotate(ext_win, win, - ext_dev_drv->rotate_mode); + ext_dev_drv->rotate_mode, + ext_dev_drv->iommu_enabled); ext_dev_drv->ops->set_par(ext_dev_drv, i); ext_dev_drv->ops->pan_display(ext_dev_drv, i); @@ -2312,6 +2394,7 @@ EXPORT_SYMBOL(rk_get_real_fps); #ifdef CONFIG_ROCKCHIP_IOMMU #define ION_MAX 10 static struct ion_handle *ion_hanle[ION_MAX]; +static struct ion_handle *ion_hwc[1]; #endif static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) @@ -2346,6 +2429,51 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, } switch (cmd) { + case RK_FBIOSET_HWC_ADDR: + { + u32 hwc_phy[1]; + if (copy_from_user(hwc_phy, argp, 4)) + return -EFAULT; + if (!dev_drv->iommu_enabled) { + fix->smem_start = hwc_phy[0]; + } else { + int usr_fd; + struct ion_handle *hdl; + ion_phys_addr_t phy_addr; + size_t len; + + usr_fd = hwc_phy[0]; + if (!usr_fd) { + fix->smem_start = 0; + fix->mmio_start = 0; + break; + } + + if (ion_hwc[0] != 0) { + ion_free(rk_fb->ion_client, ion_hwc[0]); + ion_hwc[0] = 0; + } + + hdl = ion_import_dma_buf(rk_fb->ion_client, usr_fd); + if (IS_ERR(hdl)) { + dev_err(info->dev, "failed to get hwc ion handle:%ld\n", + PTR_ERR(hdl)); + return -EFAULT; + } + + ret = ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl, + (unsigned long *)&phy_addr, + (unsigned long *)&len); + if (ret < 0) { + dev_err(info->dev, "ion map to get hwc phy addr failed"); + ion_free(rk_fb->ion_client, hdl); + return -ENOMEM; + } + fix->smem_start = phy_addr; + ion_hwc[0] = hdl; + } + break; + } case RK_FBIOSET_YUV_ADDR: { u32 yuv_phy[2]; @@ -2373,12 +2501,20 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, break; } + if (ion_hanle[ION_MAX - 1] != 0) { + /*ion_unmap_kernel(rk_fb->ion_client, ion_hanle[ION_MAX - 1]);*/ + /*ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client, ion_hanle[ION_MAX - 1]);*/ + ion_free(rk_fb->ion_client, ion_hanle[ION_MAX - 1]); + ion_hanle[ION_MAX - 1] = 0; + } + hdl = ion_import_dma_buf(rk_fb->ion_client, usr_fd); if (IS_ERR(hdl)) { dev_err(info->dev, "failed to get ion handle:%ld\n", PTR_ERR(hdl)); return -EFAULT; } + ret = ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl, (unsigned long *)&phy_addr, (unsigned long *)&len); @@ -2389,13 +2525,10 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, } fix->smem_start = phy_addr; fix->mmio_start = phy_addr + offset; + fix->smem_len = len; + /*info->screen_base = ion_map_kernel(rk_fb->ion_client, hdl);*/ - if (ion_hanle[ION_MAX - 1] != 0) { - ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client, ion_hanle[ION_MAX - 1]); - ion_free(rk_fb->ion_client, ion_hanle[ION_MAX - 1]); - } ion_hanle[0] = hdl; - for (tmp = ION_MAX - 1; tmp > 0; tmp--) ion_hanle[tmp] = ion_hanle[tmp - 1]; ion_hanle[0] = 0; @@ -2725,7 +2858,6 @@ static int rk_fb_set_par(struct fb_info *info) struct rk_lcdc_win *extend_win = NULL; struct rk_lcdc_win *win = NULL; struct rk_screen *screen = dev_drv->cur_screen; - struct rk_screen screen_primary; int win_id = 0; u32 cblen = 0, crlen = 0; u16 xsize = 0, ysize = 0; /* winx display window height/width --->LCDC_WINx_DSP_INFO */ @@ -2764,6 +2896,10 @@ static int rk_fb_set_par(struct fb_info *info) if (var->grayscale >> 8) { xsize = (var->grayscale >> 8) & 0xfff; ysize = (var->grayscale >> 20) & 0xfff; + if (xsize > screen->mode.xres) + xsize = screen->mode.xres; + if (ysize > screen->mode.yres) + ysize = screen->mode.yres; } else { /*ohterwise full screen display */ xsize = screen->mode.xres; ysize = screen->mode.yres; @@ -2861,14 +2997,13 @@ static int rk_fb_set_par(struct fb_info *info) } } - rk_fb_get_prmry_screen(&screen_primary); win->format = fb_data_fmt; win->area[0].y_vir_stride = stride >> 2; win->area[0].uv_vir_stride = uv_stride >> 2; - win->area[0].xpos = xpos*screen->mode.xres/screen_primary.mode.xres; - win->area[0].ypos = ypos*screen->mode.yres/screen_primary.mode.yres; - win->area[0].xsize = screen->mode.xres*xsize/screen_primary.mode.xres; - win->area[0].ysize = screen->mode.yres*ysize/screen_primary.mode.yres; + win->area[0].xpos = xpos; + win->area[0].ypos = ypos; + win->area[0].xsize = xsize; + win->area[0].ysize = ysize; win->area[0].xact = var->xres; /* winx active window height,is a wint of vir */ win->area[0].yact = var->yres; win->area[0].xvir = var->xres_virtual; /* virtual resolution stride --->LCDC_WINx_VIR */ @@ -2881,7 +3016,7 @@ static int rk_fb_set_par(struct fb_info *info) win->g_alpha_val = 0; if (rk_fb->disp_mode == DUAL) { - if (extend_win->state && (hdmi_switch_complete)) { + if (extend_win->state && (hdmi_switch_complete == 0xff)) { if (info != extend_info) { if (win->area[0].xact < win->area[0].yact) { extend_win->area[0].xact = @@ -3199,8 +3334,12 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) printk(KERN_ERR "%s driver not found!", name); return -ENODEV; } - printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from", - dev_drv->id); + if (screen->type == SCREEN_HDMI) + printk("hdmi %s lcdc%d\n", enable ? "connect to" : "remove from", + dev_drv->id); + else if (screen->type == SCREEN_TVOUT) + printk("cvbs %s lcdc%d\n", enable ? "connect to" : "remove from", + dev_drv->id); if (enable == 2 /*&& dev_drv->enable*/) return 0; @@ -3223,8 +3362,9 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) dev_drv->ops->load_screen(dev_drv, 1); if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) dev_drv->trsm_ops->enable(); - } else { - /* disable the layer which attached to this device */ + } else if (rk_fb->num_lcdc > 1) { + /* If there is more than one lcdc device, we disable + the layer which attached to this device */ 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); @@ -3260,19 +3400,25 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) } } if (dev_drv->win[win_id]->logicalstate) { - dev_drv->ops->open(dev_drv, win_id, 1); + if (!dev_drv->win[win_id]->state) + dev_drv->ops->open(dev_drv, win_id, 1); if (!load_screen) { dev_drv->ops->load_screen(dev_drv, 1); load_screen = 1; } info->var.activate |= FB_ACTIVATE_FORCE; info->fbops->fb_set_par(info); - info->fbops->fb_pan_display(&info->var, info); + hdmi_switch_complete |= (1 << win_id); + if (rk_fb->disp_mode == DUAL) + pmy_info->fbops->fb_pan_display(&pmy_info->var, + pmy_info); + else + info->fbops->fb_pan_display(&info->var, info); } } } - hdmi_switch_complete = 1; + hdmi_switch_complete = 0xff; if (rk_fb->disp_mode == ONE_DUAL) { if (dev_drv->ops->set_screen_scaler) dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 1); @@ -3325,7 +3471,7 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id) screen_x = dev_drv->cur_screen->mode.xres; screen_y = dev_drv->cur_screen->mode.yres; - if (inf->disp_mode != DUAL) { + if (inf->disp_mode != DUAL && dev_drv->screen1) { dev_drv->cur_screen->xpos = (screen_x - screen_x * scale_x / 100) >> 1; dev_drv->cur_screen->ypos = @@ -3569,7 +3715,7 @@ 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); - dev_drv->ops->fb_win_remap(dev_drv, FB_DEFAULT_ORDER); + dev_drv->ops->fb_win_remap(dev_drv, dev_drv->fb_win_map); dev_drv->first_frame = 1; dev_drv->overscan.left = 100; dev_drv->overscan.top = 100; @@ -3580,9 +3726,12 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb, if (dev_drv->ops->set_dsp_cabc) dev_drv->ops->set_dsp_cabc(dev_drv, dev_drv->cabc_mode); rk_fb_set_prmry_screen(screen); + rk_fb_get_prmry_screen(screen); } - rk_fb_get_prmry_screen(screen); dev_drv->trsm_ops = rk_fb_trsm_ops_get(screen->type); + if (dev_drv->prop != PRMRY) + rk_fb_get_prmry_screen(screen); + dev_drv->output_color = screen->color_mode; return 0; } @@ -3741,22 +3890,15 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, if (dev_drv->prop == PRMRY) { struct fb_info *main_fbi = rk_fb->fb[0]; main_fbi->fbops->fb_open(main_fbi, 1); -/* + #if defined(CONFIG_ROCKCHIP_IOMMU) if (dev_drv->iommu_enabled) { - mmu_dev = - rk_fb_get_sysmmu_device_by_compatible(dev_drv->mmu_dts_name); - if (mmu_dev) { - rk_fb_platform_set_sysmmu(mmu_dev, dev_drv->dev); + if (dev_drv->mmu_dev) rockchip_iovmm_set_fault_handler(dev_drv->dev, - rk_fb_sysmmu_fault_handler); - rockchip_iovmm_activate(dev_drv->dev); - } else - dev_err(dev_drv->dev, - "failed to get rockchip iommu device\n"); + rk_fb_sysmmu_fault_handler); } #endif -*/ + rk_fb_alloc_buffer(main_fbi, 0); /* only alloc memory for main fb */ if (support_uboot_display()) { if (dev_drv->iommu_enabled) {