X-Git-Url: http://plrg.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Frockchip%2Frk_fb.c;h=9ba1230d55285f60cfdab57ce68a098c0593f9bb;hb=f93e3bcf22f3afe97b66728872be13a89f15a02d;hp=1fe662f43978fc017d29d847b7919abc9b549d3a;hpb=c96d41ae848c8b5c703f2ef1773e6d37db68e7ed;p=firefly-linux-kernel-4.4.55.git diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c old mode 100755 new mode 100644 index 1fe662f43978..9ba1230d5528 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -24,11 +24,15 @@ #include #include #include +#include #include #include #include #include #include +#include + +#include "bmp_helper.h" #if defined(CONFIG_RK_HDMI) #include "hdmi/rk_hdmi.h" @@ -64,9 +68,9 @@ 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; +extern phys_addr_t uboot_logo_base; +extern phys_addr_t uboot_logo_size; +extern phys_addr_t uboot_logo_offset; 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; @@ -76,6 +80,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) { @@ -131,12 +147,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: @@ -195,6 +214,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); @@ -205,6 +233,9 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel) case 32: fb_data_fmt = ARGB888; break; + case 24: + fb_data_fmt = RGB888; + break; case 16: fb_data_fmt = RGB565; break; @@ -264,11 +295,22 @@ int rk_disp_pwr_ctr_parse_dt(struct rk_lcdc_driver *dev_drv) } else { pwr_ctr->pwr_ctr.type = REGULATOR; - + pwr_ctr->pwr_ctr.rgl_name = NULL; + ret = of_property_read_string(child, "rockchip,regulator_name", + &(pwr_ctr->pwr_ctr.rgl_name)); + if (ret || IS_ERR_OR_NULL(pwr_ctr->pwr_ctr.rgl_name)) + dev_err(dev_drv->dev, "get regulator name failed!\n"); + if (!of_property_read_u32(child, "rockchip,regulator_voltage", &val)) + pwr_ctr->pwr_ctr.volt = val; + else + 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); } @@ -300,6 +342,9 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv) struct list_head *pos; struct rk_disp_pwr_ctr_list *pwr_ctr_list; struct pwr_ctr *pwr_ctr; + struct regulator *regulator_lcd = NULL; + int count = 10; + if (list_empty(&dev_drv->pwrlist_head)) return 0; list_for_each(pos, &dev_drv->pwrlist_head) { @@ -309,6 +354,27 @@ int rk_disp_pwr_enable(struct rk_lcdc_driver *dev_drv) if (pwr_ctr->type == GPIO) { gpio_direction_output(pwr_ctr->gpio, pwr_ctr->atv_val); mdelay(pwr_ctr->delay); + } else if (pwr_ctr->type == REGULATOR) { + 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); + continue; + } + regulator_set_voltage(regulator_lcd, pwr_ctr->volt, pwr_ctr->volt); + while (!regulator_is_enabled(regulator_lcd)) { + if (regulator_enable(regulator_lcd) == 0 || count == 0) + break; + else + dev_err(dev_drv->dev, + "regulator_enable failed,count=%d\n", + count); + count--; + } + regulator_put(regulator_lcd); + msleep(pwr_ctr->delay); } } @@ -320,14 +386,37 @@ int rk_disp_pwr_disable(struct rk_lcdc_driver *dev_drv) struct list_head *pos; struct rk_disp_pwr_ctr_list *pwr_ctr_list; struct pwr_ctr *pwr_ctr; + struct regulator *regulator_lcd = NULL; + int count = 10; + if (list_empty(&dev_drv->pwrlist_head)) return 0; list_for_each(pos, &dev_drv->pwrlist_head) { pwr_ctr_list = list_entry(pos, struct rk_disp_pwr_ctr_list, list); pwr_ctr = &pwr_ctr_list->pwr_ctr; - if (pwr_ctr->type == GPIO) + if (pwr_ctr->type == GPIO) { gpio_set_value(pwr_ctr->gpio, !pwr_ctr->atv_val); + } else if (pwr_ctr->type == REGULATOR) { + 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); + continue; + } + while (regulator_is_enabled(regulator_lcd) > 0) { + if (regulator_disable(regulator_lcd) == 0 || count == 0) + break; + else + dev_err(dev_drv->dev, + "regulator_disable failed,count=%d\n", + count); + count--; + } + regulator_put(regulator_lcd); + } } return 0; } @@ -449,7 +538,16 @@ char *get_format_string(enum data_format format, char *fmt) strcpy(fmt, "XBGR888"); break; case ABGR888: - strcpy(fmt, "XBGR888"); + 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"); @@ -733,11 +831,12 @@ void rk_fb_platform_set_sysmmu(struct device *sysmmu, struct device *dev) static int rk_fb_open(struct fb_info *info, int user) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; int win_id; win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); - dev_drv->win[win_id]->logicalstate++; + fb_par->state++; /* if this win aready opened ,no need to reopen */ if (dev_drv->win[win_id]->state) return 0; @@ -750,7 +849,8 @@ static int get_extend_fb_id(struct fb_info *info) { int fb_id = 0; char *id = info->fix.id; - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; if (!strcmp(id, "fb0")) fb_id = 0; @@ -758,20 +858,26 @@ static int get_extend_fb_id(struct fb_info *info) fb_id = 1; else if (!strcmp(id, "fb2") && (dev_drv->lcdc_win_num > 2)) fb_id = 2; + else if (!strcmp(id, "fb3") && (dev_drv->lcdc_win_num > 3)) + fb_id = 3; + else if (!strcmp(id, "fb4") && (dev_drv->lcdc_win_num > 4)) + fb_id = 4; return fb_id; } static int rk_fb_close(struct fb_info *info, int user) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_lcdc_win *win = NULL; int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); if (win_id >= 0) { - dev_drv->win[win_id]->logicalstate--; - if (!dev_drv->win[win_id]->logicalstate) { - win = dev_drv->win[win_id]; - info->fix.smem_start = win->reserved; + win = dev_drv->win[win_id]; + fb_par->state--; + if (!fb_par->state) { + if (fb_par->fb_phy_base > 0) + info->fix.smem_start = fb_par->fb_phy_base; info->var.xres = dev_drv->screen0->mode.xres; info->var.yres = dev_drv->screen0->mode.yres; /* @@ -873,15 +979,15 @@ static void ipp_win_check(int *dst_w, int *dst_h, int *dst_vir_w, } static void fb_copy_by_ipp(struct fb_info *dst_info, - struct fb_info *src_info, int offset) + struct fb_info *src_info) { struct rk29_ipp_req ipp_req; uint32_t rotation = 0; int dst_w, dst_h, dst_vir_w; int ipp_fmt; u8 data_format = (dst_info->var.nonstd) & 0xff; - struct rk_lcdc_driver *ext_dev_drv = - (struct rk_lcdc_driver *)dst_info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)dst_info->par; + struct rk_lcdc_driver *ext_dev_drv = fb_par->lcdc_drv; u16 orientation = ext_dev_drv->rotate_mode; memset(&ipp_req, 0, sizeof(struct rk29_ipp_req)); @@ -966,27 +1072,30 @@ static int get_rga_format(int fmt) static void rga_win_check(struct rk_lcdc_win *dst_win, struct rk_lcdc_win *src_win) { - int align32 = 4; - - align32 -= 1; - /*width and height must be aligned by 32 bit */ - if ((src_win->area[0].xact & align32) != 0) - src_win->area[0].xact = - (src_win->area[0].xact + align32) & (~align32); - if ((src_win->area[0].yact & align32) != 0) - src_win->area[0].yact = - (src_win->area[0].yact + align32) & (~align32); + int format = 0; + + format = get_rga_format(src_win->area[0].format); + /* width and height must be even number */ + if (format >= RK_FORMAT_YCbCr_422_SP && + format <= RK_FORMAT_YCrCb_420_P) { + if ((src_win->area[0].xact % 2) != 0) + src_win->area[0].xact += 1; + if ((src_win->area[0].yact % 2) != 0) + src_win->area[0].yact += 1; + } if (src_win->area[0].xvir < src_win->area[0].xact) src_win->area[0].xvir = src_win->area[0].xact; if (src_win->area[0].yvir < src_win->area[0].yact) src_win->area[0].yvir = src_win->area[0].yact; - if ((dst_win->area[0].xact & align32) != 0) - dst_win->area[0].xact = - (dst_win->area[0].xact + align32) & (~align32); - if ((dst_win->area[0].yact & align32) != 0) - dst_win->area[0].yact = - (dst_win->area[0].yact + align32) & (~align32); + format = get_rga_format(dst_win->area[0].format); + if (format >= RK_FORMAT_YCbCr_422_SP && + format <= RK_FORMAT_YCrCb_420_P) { + if ((dst_win->area[0].xact % 2) != 0) + dst_win->area[0].xact += 1; + if ((dst_win->area[0].yact % 2) != 0) + dst_win->area[0].yact += 1; + } if (dst_win->area[0].xvir < dst_win->area[0].xact) dst_win->area[0].xvir = dst_win->area[0].xact; if (dst_win->area[0].yvir < dst_win->area[0].yact) @@ -1059,7 +1168,7 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, Rga_Request.src.vir_w = src_win->area[0].xvir; Rga_Request.src.vir_h = src_win->area[0].yvir; - Rga_Request.src.format = get_rga_format(src_win->format); + Rga_Request.src.format = get_rga_format(src_win->area[0].format); Rga_Request.src.act_w = src_win->area[0].xact; Rga_Request.src.act_h = src_win->area[0].yact; Rga_Request.src.x_offset = 0; @@ -1067,7 +1176,7 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, Rga_Request.dst.vir_w = dst_win->area[0].xvir; Rga_Request.dst.vir_h = dst_win->area[0].yvir; - Rga_Request.dst.format = get_rga_format(dst_win->format); + Rga_Request.dst.format = get_rga_format(dst_win->area[0].format); Rga_Request.clip.xmin = 0; Rga_Request.clip.xmax = dst_win->area[0].xact - 1; @@ -1095,12 +1204,13 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, * RGA only support copy RGB to RGB * RGA2 support copy RGB to RGB and YUV to YUV */ -static void fb_copy_by_rga(struct fb_info *dst_info, struct fb_info *src_info, - int yrgb_offset) +static void fb_copy_by_rga(struct fb_info *dst_info, + struct fb_info *src_info) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)src_info->par; - struct rk_lcdc_driver *ext_dev_drv = - (struct rk_lcdc_driver *)dst_info->par; + struct rk_fb_par *src_fb_par = (struct rk_fb_par *)src_info->par; + struct rk_fb_par *dst_fb_par = (struct rk_fb_par *)dst_info->par; + struct rk_lcdc_driver *dev_drv = src_fb_par->lcdc_drv; + struct rk_lcdc_driver *ext_dev_drv = dst_fb_par->lcdc_drv; int win_id = 0, ext_win_id; struct rk_lcdc_win *src_win, *dst_win; @@ -1118,21 +1228,22 @@ static void fb_copy_by_rga(struct fb_info *dst_info, struct fb_info *src_info, #endif static int rk_fb_rotate(struct fb_info *dst_info, - struct fb_info *src_info, int offset) + struct fb_info *src_info) { + #if defined(CONFIG_RK29_IPP) - fb_copy_by_ipp(dst_info, src_info, offset); + fb_copy_by_ipp(dst_info, src_info); #elif defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) - fb_copy_by_rga(dst_info, src_info, offset); + fb_copy_by_rga(dst_info, src_info); #else return -1; #endif return 0; } -static int rk_fb_win_rotate(struct rk_lcdc_win *dst_win, - struct rk_lcdc_win *src_win, - u16 rotate, int iommu_en) +static int __maybe_unused rk_fb_win_rotate(struct rk_lcdc_win *dst_win, + 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, iommu_en); @@ -1142,12 +1253,122 @@ static int rk_fb_win_rotate(struct rk_lcdc_win *dst_win, return 0; } +static int rk_fb_set_ext_win_buffer(struct rk_lcdc_win *ext_win, + struct rk_lcdc_win *win, + u16 rotate, int iommu_en) +{ + struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); + struct fb_info *ext_info = rk_fb->fb[(rk_fb->num_fb >> 1)]; + struct rk_fb_par *ext_fb_par = (struct rk_fb_par *)ext_info->par; + struct rk_lcdc_driver *ext_dev_drv = rk_get_extend_lcdc_drv(); + struct rk_lcdc_win *last_win; + static u8 fb_index = 0; + ion_phys_addr_t phy_addr; + size_t len = 0; + int ret = 0; + bool is_yuv = false; + + if (unlikely(!ext_win) || unlikely(!win)) + return -1; + + if (rk_fb->disp_mode != DUAL || ext_info == NULL) + return 0; + + switch (ext_win->area[0].format) { + case YUV422: + case YUV420: + case YUV444: + case YUV422_A: + case YUV420_A: + case YUV444_A: + is_yuv = true; + break; + default: + is_yuv = false; + break; + } + + /* no rotate mode */ + if (rotate <= X_Y_MIRROR) { + if (iommu_en) { + 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; + ext_win->area[0].y_offset = win->area[0].y_offset; + if (is_yuv) { + ext_win->area[0].cbr_start = win->area[0].cbr_start; + ext_win->area[0].c_offset = win->area[0].c_offset; + } else { + ext_win->area[0].cbr_start = 0; + ext_win->area[0].c_offset = 0; + } + } else { + ext_win->area[0].smem_start = win->area[0].smem_start; + ext_win->area[0].y_offset = win->area[0].y_offset; + if (is_yuv) { + ext_win->area[0].cbr_start = win->area[0].cbr_start; + ext_win->area[0].c_offset = win->area[0].c_offset; + } else { + ext_win->area[0].cbr_start = 0; + ext_win->area[0].c_offset = 0; + } + } + + return 0; + } + + /* rotate mode */ + if (!iommu_en) { + if (ext_win->id == 0) { + ext_win->area[0].smem_start = ext_fb_par->fb_phy_base; + ext_win->area[0].y_offset = (get_rotate_fb_size() >> 1) * fb_index; + if ((++fb_index) > 1) + fb_index = 0; + } else { + ext_win->area[0].y_offset = 0; + last_win = ext_dev_drv->win[ext_win->id - 1]; + if (last_win->area[0].cbr_start) + ext_win->area[0].smem_start = + last_win->area[0].cbr_start + + last_win->area[0].c_offset + + last_win->area[0].xvir * last_win->area[0].yvir; + else + ext_win->area[0].smem_start = + last_win->area[0].smem_start + + last_win->area[0].y_offset + + last_win->area[0].xvir * last_win->area[0].yvir; + } + + if (is_yuv) { + 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; + ext_win->area[0].c_offset = win->area[0].c_offset; + } else { + ext_win->area[0].cbr_start = 0; + ext_win->area[0].c_offset = 0; + } + } + + return 0; +} static int rk_fb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { struct rk_fb *rk_fb = dev_get_drvdata(info->device); - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_fb_par *extend_fb_par = NULL; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct fb_fix_screeninfo *fix = &info->fix; struct fb_info *extend_info = NULL; struct rk_lcdc_driver *extend_dev_drv = NULL; @@ -1170,11 +1391,6 @@ 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) @@ -1185,19 +1401,20 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, if (rk_fb->disp_mode == DUAL) { fb_id = get_extend_fb_id(info); extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id]; - extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par; + extend_fb_par = (struct rk_fb_par *)extend_info->par; + extend_dev_drv = extend_fb_par->lcdc_drv; extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv, extend_info->fix.id); extend_win = extend_dev_drv->win[extend_win_id]; } - pixel_width = rk_fb_pixel_width(win->format); + pixel_width = rk_fb_pixel_width(win->area[0].format); vir_width_bit = pixel_width * xvir; /* pixel_width = byte_num * 8 */ stride_32bit_1 = ALIGN_N_TIMES(vir_width_bit, 32) / 8; stride_32bit_2 = ALIGN_N_TIMES(vir_width_bit * 2, 32) / 8; - switch (win->format) { + switch (win->area[0].format) { case YUV422: case YUV422_A: is_pic_yuv = 1; @@ -1235,7 +1452,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 + @@ -1255,7 +1473,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 + @@ -1283,47 +1502,21 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, win->area[0].cbr_start = fix->mmio_start; win->area[0].state = 1; win->area_num = 1; - win->state = 1; dev_drv->ops->pan_display(dev_drv, win_id); + if (rk_fb->disp_mode == DUAL) { - 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 - } + if (extend_info != info && extend_win->state && + hdmi_switch_complete) { + rk_fb_set_ext_win_buffer(extend_win, win, + extend_dev_drv->rotate_mode, + extend_dev_drv->iommu_enabled); + if (extend_dev_drv->rotate_mode > X_Y_MIRROR) + rk_fb_rotate(extend_info, info); + extend_dev_drv->ops->pan_display(extend_dev_drv, extend_win_id); + extend_dev_drv->ops->cfg_done(extend_dev_drv); } } #ifdef CONFIG_FB_MIRRORING @@ -1331,6 +1524,9 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, video_data_to_mirroring(info, NULL); #endif dev_drv->ops->cfg_done(dev_drv); + /*msleep(1000); + dev_drv->ops->dump_reg(dev_drv); + while(1);*/ return 0; } @@ -1356,18 +1552,23 @@ void rk_fd_fence_wait(struct rk_lcdc_driver *dev_drv, struct sync_fence *fence) if (err < 0) printk("error waiting on fence\n"); } - +#if 0 static int rk_fb_copy_from_loader(struct fb_info *info) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; void *dst = info->screen_base; u32 dsp_addr[4]; u32 src; - u32 i; - struct rk_lcdc_win *win = dev_drv->win[0]; - u32 size = (win->area[0].xact) * (win->area[0].yact) << 2; + u32 i,size; + int win_id; + struct rk_lcdc_win *win; + + win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); + win = dev_drv->win[win_id]; + size = (win->area[0].xact) * (win->area[0].yact) << 2; dev_drv->ops->get_dsp_addr(dev_drv, dsp_addr); - src = dsp_addr[0]; + src = dsp_addr[win_id]; dev_info(info->dev, "copy fb data %d x %d from dst_addr:%08x\n", win->area[0].xact, win->area[0].yact, src); for (i = 0; i < size; i += PAGE_SIZE) { @@ -1376,9 +1577,11 @@ static int rk_fb_copy_from_loader(struct fb_info *info) void *to_virt = dst + i; memcpy(to_virt, from_virt, PAGE_SIZE); } + dev_drv->ops->direct_set_addr(dev_drv, win_id, + info->fix.smem_start); return 0; } - +#endif #ifdef CONFIG_ROCKCHIP_IOMMU static int g_last_addr[4]; int g_last_timeout; @@ -1440,11 +1643,12 @@ void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv, index_buf = area_data->index_buf; #if defined(CONFIG_ROCKCHIP_IOMMU) if (dev_drv->iommu_enabled) { + if (rk_fb->disp_policy != DISPLAY_POLICY_BOX) ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client, area_data->ion_handle); freed_addr[freed_index++] = area_data->smem_start; } - if (rk_fb->disp_mode == DUAL && hdmi_switch_complete == 0xff) { + if (rk_fb->disp_mode == DUAL && hdmi_switch_complete) { if (ext_dev_drv->iommu_enabled) ion_unmap_iommu(ext_dev_drv->dev, rk_fb->ion_client, @@ -1462,7 +1666,151 @@ void rk_fb_free_dma_buf(struct rk_lcdc_driver *dev_drv, memset(reg_win_data, 0, sizeof(struct rk_fb_reg_win_data)); } -static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, +/* + * function: update extend win info acorrding to primary win info, + the function is only used for dual display mode + * @ext_dev_drv: the extend lcdc driver + * @dev_drv: the primary lcdc driver + * @ext_win: the lcdc win info of extend screen + * @win: the lcdc win info of primary screen + */ +static int rk_fb_update_ext_win(struct rk_lcdc_driver *ext_dev_drv, + struct rk_lcdc_driver *dev_drv, + struct rk_lcdc_win *ext_win, + struct rk_lcdc_win *win) +{ + struct rk_screen *screen = dev_drv->cur_screen; + struct rk_screen *ext_screen = ext_dev_drv->cur_screen; + int hdmi_xsize = ext_screen->xsize; + int hdmi_ysize = ext_screen->ysize; + int pixel_width, vir_width_bit, y_stride; + bool is_yuv = false; + int rotate_mode = 0; + + if (unlikely(!dev_drv) || unlikely(!ext_dev_drv) || + unlikely(!ext_win) || unlikely(!win)) + return -1; + + rotate_mode = ext_dev_drv->rotate_mode; + + if (ext_win->state == 0) { + dev_info(ext_dev_drv->dev, "extend lcdc win is closed\n"); + return 0; + } + + ext_win->area[0].state = win->area[0].state; + ext_win->area[0].format = win->area[0].format; + ext_win->area_num = win->area_num; + ext_win->fmt_10 = win->fmt_10; + ext_win->z_order = win->z_order; + ext_win->alpha_en = win->alpha_en; + ext_win->alpha_mode = win->alpha_mode; + ext_win->g_alpha_val = win->g_alpha_val; + ext_win->mirror_en = win->mirror_en; + ext_win->area[0].fbdc_en = win->area[0].fbdc_en; + ext_win->area[0].fbdc_cor_en = win->area[0].fbdc_cor_en; + ext_win->area[0].fbdc_data_format = win->area[0].fbdc_data_format; + + switch (ext_win->area[0].format) { + case YUV422: + case YUV420: + case YUV444: + case YUV422_A: + case YUV420_A: + case YUV444_A: + is_yuv = true; + break; + default: + is_yuv = false; + break; + } + + if (rotate_mode == ROTATE_90 || rotate_mode == ROTATE_270) { + ext_win->area[0].xact = win->area[0].yact; + ext_win->area[0].yact = win->area[0].xact; + ext_win->area[0].xvir = win->area[0].yact; + ext_win->area[0].yvir = win->area[0].xact; + + pixel_width = rk_fb_pixel_width(ext_win->area[0].format); + vir_width_bit = pixel_width * ext_win->area[0].xvir; + y_stride = ALIGN_N_TIMES(vir_width_bit, 32) / 8; + ext_win->area[0].y_vir_stride = y_stride >> 2; + if (is_yuv) + ext_win->area[0].uv_vir_stride = ext_win->area[0].y_vir_stride; + else + ext_win->area[0].uv_vir_stride = 0; + } else { + ext_win->area[0].xact = win->area[0].xact; + ext_win->area[0].yact = win->area[0].yact; + if (win->area[0].xvir == 0) + ext_win->area[0].xvir = win->area[0].xact; + else + ext_win->area[0].xvir = win->area[0].xvir; + if (win->area[0].yvir == 0) + ext_win->area[0].yvir = win->area[0].yact; + else + ext_win->area[0].yvir = win->area[0].yvir; + ext_win->area[0].y_vir_stride = win->area[0].y_vir_stride; + if (is_yuv) + ext_win->area[0].uv_vir_stride = win->area[0].uv_vir_stride; + else + ext_win->area[0].uv_vir_stride = 0; + } + + if (win->area[0].xpos != 0 || win->area[0].ypos != 0) { + if (rotate_mode == ROTATE_270) { + int xbom_pos = 0, ybom_pos = 0; + int xtop_pos = 0, ytop_pos = 0; + + ext_win->area[0].xsize = + hdmi_xsize * win->area[0].ysize / screen->mode.yres; + ext_win->area[0].ysize = + hdmi_ysize * win->area[0].xsize / screen->mode.xres; + xbom_pos = + hdmi_xsize * win->area[0].ypos / screen->mode.yres; + ybom_pos = hdmi_ysize * win->area[0].xpos / screen->mode.xres; + xtop_pos = hdmi_xsize - ext_win->area[0].xsize - xbom_pos; + ytop_pos = hdmi_ysize - ext_win->area[0].ysize - ybom_pos; + ext_win->area[0].xpos = + ((ext_screen->mode.xres - hdmi_xsize) >> 1) + xtop_pos; + ext_win->area[0].ypos = + ((ext_screen->mode.yres - hdmi_ysize) >> 1) + ytop_pos; + } else if (rotate_mode == ROTATE_90) { + ext_win->area[0].xsize = + hdmi_xsize * win->area[0].ysize / screen->mode.yres; + ext_win->area[0].ysize = + hdmi_ysize * win->area[0].xsize / screen->mode.xres; + ext_win->area[0].xpos = + ((ext_screen->mode.xres - hdmi_xsize) >> 1) + + hdmi_xsize * win->area[0].ypos / screen->mode.yres; + ext_win->area[0].ypos = + ((ext_screen->mode.yres - hdmi_ysize) >> 1) + + hdmi_ysize * win->area[0].xpos / screen->mode.xres; + } else { + ext_win->area[0].xsize = + hdmi_xsize * win->area[0].xsize / screen->mode.xres; + ext_win->area[0].ysize = + hdmi_ysize * win->area[0].ysize / screen->mode.yres; + ext_win->area[0].xpos = + ((ext_screen->mode.xres - hdmi_xsize) >> 1) + + hdmi_xsize * win->area[0].xpos / screen->mode.xres; + ext_win->area[0].ypos = + ((ext_screen->mode.yres - hdmi_ysize) >> 1) + + hdmi_ysize * win->area[0].ypos / screen->mode.yres; + } + } else { + ext_win->area[0].xsize = hdmi_xsize; + ext_win->area[0].ysize = hdmi_ysize; + ext_win->area[0].xpos = + (ext_screen->mode.xres - hdmi_xsize) >> 1; + ext_win->area[0].ypos = + (ext_screen->mode.yres - hdmi_ysize) >> 1; + } + + return 0; +} + +static void rk_fb_update_win(struct rk_lcdc_driver *dev_drv, struct rk_lcdc_win *win, struct rk_fb_reg_win_data *reg_win_data) { @@ -1479,14 +1827,12 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, rk_fb_get_prmry_screen(&primary_screen); win->area_num = reg_win_data->area_num; - win->format = reg_win_data->data_format; win->id = reg_win_data->win_id; win->z_order = reg_win_data->z_order; if (reg_win_data->reg_area_data[0].smem_start > 0) { win->state = 1; win->area_num = reg_win_data->area_num; - win->format = reg_win_data->data_format; win->id = reg_win_data->win_id; win->z_order = reg_win_data->z_order; win->area[0].uv_vir_stride = @@ -1497,13 +1843,24 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, win->alpha_en = reg_win_data->alpha_en; win->alpha_mode = reg_win_data->alpha_mode; win->g_alpha_val = reg_win_data->g_alpha_val; + win->mirror_en = reg_win_data->mirror_en; + win->area[0].fbdc_en = + reg_win_data->reg_area_data[0].fbdc_en; + win->area[0].fbdc_cor_en = + reg_win_data->reg_area_data[0].fbdc_cor_en; + win->area[0].fbdc_data_format = + reg_win_data->reg_area_data[0].fbdc_data_format; 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 = + win->area[i].format = + reg_win_data->reg_area_data[i].data_format; + if (inf->disp_policy != DISPLAY_POLICY_BOX) + 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; - if (inf->disp_mode == DUAL) { + if (inf->disp_mode == DUAL || + inf->disp_policy == DISPLAY_POLICY_BOX) { win->area[i].xpos = reg_win_data->reg_area_data[i].xpos; win->area[i].ypos = @@ -1529,6 +1886,25 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, reg_win_data->reg_area_data[i].ysize * cur_screen->mode.yres / primary_screen.mode.yres; + + /* recalc display size if set hdmi scaler when at ONE_DUAL mode */ + if (inf->disp_mode == ONE_DUAL && hdmi_switch_complete) { + if (cur_screen->xsize > 0 && + cur_screen->xsize <= cur_screen->mode.xres) { + win->area[i].xpos = + ((cur_screen->mode.xres - cur_screen->xsize) >> 1) + + cur_screen->xsize * win->area[i].xpos / cur_screen->mode.xres; + win->area[i].xsize = + win->area[i].xsize * cur_screen->xsize / cur_screen->mode.xres; + } + if (cur_screen->ysize > 0 && cur_screen->ysize <= cur_screen->mode.yres) { + win->area[i].ypos = + ((cur_screen->mode.yres - cur_screen->ysize) >> 1) + + cur_screen->ysize * win->area[i].ypos / cur_screen->mode.yres; + win->area[i].ysize = + win->area[i].ysize * cur_screen->ysize / cur_screen->mode.yres; + } + } } win->area[i].xact = reg_win_data->reg_area_data[i].xact; @@ -1538,6 +1914,10 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, reg_win_data->reg_area_data[i].xvir; win->area[i].yvir = reg_win_data->reg_area_data[i].yvir; + win->area[i].xoff = + reg_win_data->reg_area_data[i].xoff; + win->area[i].yoff = + reg_win_data->reg_area_data[i].yoff; win->area[i].y_offset = reg_win_data->reg_area_data[i].y_offset; win->area[i].y_vir_stride = @@ -1555,221 +1935,6 @@ static void rk_fb_update_driver(struct rk_lcdc_driver *dev_drv, } } -static int rk_fb_update_hdmi_win(struct rk_lcdc_win *ext_win, - struct rk_lcdc_win *win) -{ - struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); - struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv(); - struct rk_lcdc_driver *ext_dev_drv = rk_get_extend_lcdc_drv(); - struct rk_screen *screen; - struct rk_screen *ext_screen; - int hdmi_xsize; - int hdmi_ysize; - int pixel_width, vir_width_bit, y_stride; - 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 != 0xff)) { - printk(KERN_INFO "%s: hdmi is disconnect!\n", __func__); - return -1; - } - - if (unlikely(!dev_drv) || unlikely(!ext_dev_drv)) - return -1; - - screen = dev_drv->cur_screen; - ext_screen = ext_dev_drv->cur_screen; - hdmi_xsize = ext_screen->xsize; - hdmi_ysize = ext_screen->ysize; - - ext_win->state = win->state; - ext_win->id = win->id; - if (win->area[0].smem_start == 0) - ext_win->state = 0; - if (ext_win->state == 0) - return 0; - - ext_win->area_num = win->area_num; - ext_win->format = win->format; - ext_win->z_order = win->z_order; - ext_win->alpha_en = win->alpha_en; - ext_win->alpha_mode = win->alpha_mode; - ext_win->g_alpha_val = win->g_alpha_val; - - /* win0 and win1 have only one area and support scale - * but win2 and win3 don't support scale - * so hdmi only use win0 or win1 - */ - ext_win->area[0].state = win->area[0].state; - - switch (ext_win->format) { - case YUV422: - case YUV420: - case YUV444: - case YUV422_A: - case YUV420_A: - case YUV444_A: - is_yuv = true; - break; - default: - is_yuv = false; - break; - } - - if (ext_dev_drv->rotate_mode == ROTATE_90 || - ext_dev_drv->rotate_mode == ROTATE_270) { - if (ext_win->id == 0) { - ext_win->area[0].smem_start = - rk_fb->fb[rk_fb->num_fb >> 1]->fix.smem_start; - ext_win->area[0].y_offset = (get_rotate_fb_size() >> 1) * fb_index; - if ((++fb_index) > 1) - fb_index = 0; - } else { - ext_win->area[0].y_offset = 0; - last_win = ext_dev_drv->win[ext_win->id - 1]; - if (last_win->area[0].cbr_start) - ext_win->area[0].smem_start = - last_win->area[0].cbr_start + - last_win->area[0].c_offset + - last_win->area[0].xvir * last_win->area[0].yvir; - else - ext_win->area[0].smem_start = - last_win->area[0].smem_start + - last_win->area[0].y_offset + - last_win->area[0].xvir * last_win->area[0].yvir; - } - - ext_win->area[0].xact = win->area[0].yact; - ext_win->area[0].yact = win->area[0].xact; - ext_win->area[0].xvir = win->area[0].yact; - ext_win->area[0].yvir = win->area[0].xact; - pixel_width = rk_fb_pixel_width(ext_win->format); - vir_width_bit = pixel_width * ext_win->area[0].xvir; - 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; - ext_win->area[0].xvir = win->area[0].xvir; - ext_win->area[0].yvir = win->area[0].yvir; - ext_win->area[0].y_vir_stride = win->area[0].y_vir_stride; - } - - if (win->area[0].xpos != 0 || win->area[0].ypos != 0) { - if (ext_dev_drv->rotate_mode == ROTATE_270) { - int xbom_pos = 0, ybom_pos = 0; - int xtop_pos = 0, ytop_pos = 0; - - ext_win->area[0].xsize = hdmi_xsize * - win->area[0].ysize / - screen->mode.yres; - ext_win->area[0].ysize = hdmi_ysize * - win->area[0].xsize / - screen->mode.xres; - xbom_pos = hdmi_xsize * win->area[0].ypos / screen->mode.yres; - ybom_pos = hdmi_ysize * win->area[0].xpos / screen->mode.xres; - xtop_pos = hdmi_xsize - ext_win->area[0].xsize - xbom_pos; - ytop_pos = hdmi_ysize - ext_win->area[0].ysize - ybom_pos; - ext_win->area[0].xpos = - ((ext_screen->mode.xres - hdmi_xsize) >> 1) + xtop_pos; - ext_win->area[0].ypos = - ((ext_screen->mode.yres - hdmi_ysize) >> 1) + ytop_pos; - } else if (ext_dev_drv->rotate_mode == ROTATE_90) { - ext_win->area[0].xsize = hdmi_xsize * - win->area[0].ysize / - screen->mode.yres; - ext_win->area[0].ysize = hdmi_ysize * - win->area[0].xsize / - screen->mode.xres; - ext_win->area[0].xpos = - ((ext_screen->mode.xres - hdmi_xsize) >> 1) + - hdmi_xsize * win->area[0].ypos / screen->mode.yres; - ext_win->area[0].ypos = - ((ext_screen->mode.yres - hdmi_ysize) >> 1) + - hdmi_ysize * win->area[0].xpos / screen->mode.xres; - } else { - ext_win->area[0].xsize = hdmi_xsize * - win->area[0].xsize / - screen->mode.xres; - ext_win->area[0].ysize = hdmi_ysize * - win->area[0].ysize / - screen->mode.yres; - ext_win->area[0].xpos = - ((ext_screen->mode.xres - hdmi_xsize) >> 1) + - hdmi_xsize * win->area[0].xpos / screen->mode.xres; - ext_win->area[0].ypos = - ((ext_screen->mode.yres - hdmi_ysize) >> 1) + - hdmi_ysize * win->area[0].ypos / screen->mode.yres; - } - } else { - ext_win->area[0].xsize = hdmi_xsize; - ext_win->area[0].ysize = hdmi_ysize; - ext_win->area[0].xpos = - (ext_screen->mode.xres - hdmi_xsize) >> 1; - ext_win->area[0].ypos = - (ext_screen->mode.yres - hdmi_ysize) >> 1; - } - - if (!is_yuv) { - ext_win->area[0].uv_vir_stride = 0; - ext_win->area[0].cbr_start = 0; - ext_win->area[0].c_offset = 0; - return 0; - } - - if (ext_dev_drv->rotate_mode == ROTATE_90 || - ext_dev_drv->rotate_mode == ROTATE_270) { - ext_win->area[0].uv_vir_stride = ext_win->area[0].y_vir_stride; - 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; - 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; - } - - return 0; -} - static struct rk_fb_reg_win_data *rk_fb_get_win_data(struct rk_fb_reg_data *regs, int win_id) { @@ -1792,8 +1957,10 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, struct rk_lcdc_win *win; ktime_t timestamp = dev_drv->vsync_info.timestamp; struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); +#if defined(CONFIG_RK_HDMI) struct rk_lcdc_driver *ext_dev_drv; struct rk_lcdc_win *ext_win; +#endif struct rk_fb_reg_win_data *win_data; bool wait_for_vsync; int count = 100; @@ -1815,10 +1982,16 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, win = dev_drv->win[i]; win_data = rk_fb_get_win_data(regs, i); if (win_data) { - rk_fb_update_driver(dev_drv, win, win_data); + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && + (win_data->reg_area_data[0].data_format == YUV420 || + win_data->reg_area_data[0].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 + @@ -1831,28 +2004,34 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, } } dev_drv->ops->ovl_mgr(dev_drv, 0, 1); - + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX) + dev_drv->ops->cfg_done(dev_drv); +#if defined(CONFIG_RK_HDMI) if ((rk_fb->disp_mode == DUAL) && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED) - && (hdmi_switch_complete == 0xff)) { + && hdmi_switch_complete) { ext_dev_drv = rk_get_extend_lcdc_drv(); if (!ext_dev_drv) { printk(KERN_ERR "hdmi lcdc driver not found!\n"); goto ext_win_exit; } - /* win0 and win1 have only one area and support scale - * but win2 and win3 don't support scale - * so hdmi only use win0 or win1 - */ + /* + * For RK3288: win0 and win1 have only one area and support scale + * but win2 and win3 don't support scale + * so hdmi only use win0 or win1 + */ for (i = 0; i < 2; i++) { win = dev_drv->win[i]; ext_win = ext_dev_drv->win[i]; - ext_win->state = win->state; - if (!ext_win->state) - continue; - - rk_fb_update_hdmi_win(ext_win, win); + ext_win->state = win->state; + ext_win->id = win->id; + if (!ext_win->state) + continue; + rk_fb_update_ext_win(ext_dev_drv, dev_drv, ext_win, win); + rk_fb_set_ext_win_buffer(ext_win, win, + ext_dev_drv->rotate_mode, + ext_dev_drv->iommu_enabled); if (ext_dev_drv->rotate_mode > X_Y_MIRROR) rk_fb_win_rotate(ext_win, win, @@ -1866,6 +2045,7 @@ static void rk_fb_update_reg(struct rk_lcdc_driver *dev_drv, ext_dev_drv->ops->cfg_done(ext_dev_drv); } ext_win_exit: +#endif dev_drv->ops->cfg_done(dev_drv); do { @@ -1873,21 +2053,47 @@ 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 defined(CONFIG_RK_HDMI) + 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)); + } +#endif 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) { - u32 new_start = - dev_drv->win[i]->area[0].smem_start + - dev_drv->win[i]->area[0].y_offset; - u32 reg_start = dsp_addr[i]; - - if (unlikely(new_start != reg_start)) { - wait_for_vsync = true; - dev_info(dev_drv->dev, - "win%d:new_addr:0x%08x cur_addr:0x%08x--%d\n", - i, new_start, reg_start, 101 - count); - break; + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && + (dev_drv->win[i]->area[0].format == YUV420 || + dev_drv->win[i]->area[0].format == YUV420_A || + !strcmp(dev_drv->win[i]->name, "hwc"))) { + continue; + } else { + u32 new_start = + dev_drv->win[i]->area[0].smem_start + + dev_drv->win[i]->area[0].y_offset; + u32 reg_start = dsp_addr[i]; + + if ((rk_fb->disp_policy == + DISPLAY_POLICY_BOX) && + (new_start == 0x0 || + dev_drv->suspend_flag)) + continue; + if (unlikely(new_start != reg_start)) { + wait_for_vsync = true; + dev_info(dev_drv->dev, + "win%d:new_addr:0x%08x cur_addr:0x%08x--%d\n", + i, new_start, reg_start, 101 - count); + break; + } } } } @@ -1895,27 +2101,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) @@ -1933,7 +2149,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)) @@ -1971,10 +2186,11 @@ static int rk_fb_set_win_buffer(struct fb_info *info, { struct rk_fb *rk_fb = dev_get_drvdata(info->device); struct fb_fix_screeninfo *fix = &info->fix; - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + 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; struct rk_screen primary_screen; - struct fb_info *fbi = rk_fb->fb[0]; + struct fb_info *fbi; int i, ion_fd, acq_fence_fd; u32 xvir, yvir; u32 xoffset, yoffset; @@ -2005,9 +2221,8 @@ 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: %d\n", - __func__, (int)hdl); + pr_info("%s: Could not import handle:" + " %ld\n", __func__, (long)hdl); /*return -EINVAL; */ break; } @@ -2057,16 +2272,6 @@ static int rk_fb_set_win_buffer(struct fb_info *info, sync_fence_fdget(win_par->area_par[i].acq_fence_fd); } } - fb_data_fmt = rk_fb_data_fmt(win_par->data_format, 0); - reg_win_data->data_format = fb_data_fmt; - pixel_width = rk_fb_pixel_width(fb_data_fmt); - - ppixel_a = ((fb_data_fmt == ARGB888) || - (fb_data_fmt == ABGR888)) ? 1 : 0; - global_a = (win_par->g_alpha_val == 0) ? 0 : 1; - reg_win_data->alpha_en = ppixel_a | global_a; - reg_win_data->g_alpha_val = win_par->g_alpha_val; - reg_win_data->alpha_mode = win_par->alpha_mode; if (reg_win_data->reg_area_data[0].smem_start > 0) { reg_win_data->z_order = win_par->z_order; reg_win_data->win_id = win_par->win_id; @@ -2075,9 +2280,28 @@ static int rk_fb_set_win_buffer(struct fb_info *info, reg_win_data->win_id = -1; } - rk_fb_get_prmry_screen(&primary_screen); + rk_fb_get_prmry_screen(&primary_screen); + reg_win_data->mirror_en = win_par->mirror_en; for (i = 0; i < reg_win_data->area_num; i++) { - rk_fb_check_config_var(&win_par->area_par[i], &primary_screen); + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX) + rk_fb_check_config_var(&win_par->area_par[i], screen); + else + rk_fb_check_config_var(&win_par->area_par[i], &primary_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; reg_win_data->reg_area_data[i].ypos = win_par->area_par[i].ypos; @@ -2092,6 +2316,9 @@ static int rk_fb_set_win_buffer(struct fb_info *info, xoffset = win_par->area_par[i].x_offset; /* buf offset */ yoffset = win_par->area_par[i].y_offset; + reg_win_data->reg_area_data[i].xoff = xoffset; + reg_win_data->reg_area_data[i].yoff = yoffset; + xvir = win_par->area_par[i].xvir; reg_win_data->reg_area_data[i].xvir = xvir; yvir = win_par->area_par[i].yvir; @@ -2110,7 +2337,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info, * reg_win_data->reg_area_data[i].y_offset = * yoffset*stride+xoffset*pixel_width/8; */ - if (screen->y_mirror == 1) { + if ((screen->y_mirror == 1) || (reg_win_data->mirror_en)) { if (screen->interlace == 1) { reg_win_data->reg_area_data[i].y_offset = yoffset * stride * 2 + @@ -2134,6 +2361,12 @@ static int rk_fb_set_win_buffer(struct fb_info *info, } } } + + global_a = (win_par->g_alpha_val == 0) ? 0 : 1; + reg_win_data->alpha_en = ppixel_a | global_a; + reg_win_data->g_alpha_val = win_par->g_alpha_val; + reg_win_data->alpha_mode = win_par->alpha_mode; + switch (fb_data_fmt) { case YUV422: case YUV422_A: @@ -2172,7 +2405,7 @@ static int rk_fb_set_win_buffer(struct fb_info *info, reg_win_data->reg_area_data[0].cbr_start = reg_win_data->reg_area_data[0].smem_start + xvir * yvir; reg_win_data->reg_area_data[0].uv_vir_stride = uv_stride >> 2; - if (screen->y_mirror == 1) { + if ((screen->y_mirror == 1) || (reg_win_data->mirror_en)) { if (screen->interlace == 1) { reg_win_data->reg_area_data[0].c_offset = uv_y_off * uv_stride * 2 + @@ -2196,13 +2429,20 @@ 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); + */ + info->var.yoffset = yoffset; + info->var.xoffset = xoffset; return 0; } static int rk_fb_set_win_config(struct fb_info *info, struct rk_fb_win_cfg_data *win_data) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_fb_reg_data *regs; #ifdef H_USE_FENCE struct sync_fence *release_fence[RK_MAX_BUF_NUM]; @@ -2249,7 +2489,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; } @@ -2316,7 +2555,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: @@ -2394,12 +2632,15 @@ 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) { struct rk_fb *rk_fb = dev_get_drvdata(info->device); - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_fb_par *extend_fb_par = NULL; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct fb_fix_screeninfo *fix = &info->fix; int fb_id = 0, extend_win_id = 0; struct fb_info *extend_info = NULL; @@ -2421,13 +2662,63 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, if (rk_fb->disp_mode == DUAL) { fb_id = get_extend_fb_id(info); extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id]; - extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par; + extend_fb_par = (struct rk_fb_par *)extend_info->par; + extend_dev_drv = extend_fb_par->lcdc_drv; extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv, extend_info->fix.id); extend_win = extend_dev_drv->win[extend_win_id]; } switch (cmd) { + case RK_FBIOSET_HWC_ADDR: + { + u32 hwc_phy[1]; + if (copy_from_user(hwc_phy, argp, 4)) + return -EFAULT; +#ifdef CONFIG_ROCKCHIP_IOMMU + if (!dev_drv->iommu_enabled) { +#endif + fix->smem_start = hwc_phy[0]; +#ifdef CONFIG_ROCKCHIP_IOMMU + } 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; + } +#endif + break; + } case RK_FBIOSET_YUV_ADDR: { u32 yuv_phy[2]; @@ -2493,6 +2784,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: @@ -2553,9 +2848,15 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, } case RK_FBIOGET_DMABUF_FD: { - int fd = - ion_share_dma_buf_fd(rk_fb->ion_client, - win->area[0].ion_hdl); + int fd = -1; + + if (IS_ERR_OR_NULL(fb_par->ion_hdl)) { + dev_err(info->dev, + "get dma_buf fd failed,ion handle is err\n"); + return PTR_ERR(fb_par->ion_hdl); + } + fd = ion_share_dma_buf_fd(rk_fb->ion_client, + fb_par->ion_hdl); if (fd < 0) { dev_err(info->dev, "ion_share_dma_buf_fd failed\n"); @@ -2567,7 +2868,7 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, } #endif case RK_FBIOSET_CLEAR_FB: - memset(info->screen_base, 0, get_fb_size()); + memset(fb_par->fb_virt_base, 0, fb_par->fb_size); break; case RK_FBIOSET_CONFIG_DONE: { @@ -2612,7 +2913,8 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, static int rk_fb_blank(int blank_mode, struct fb_info *info) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct fb_fix_screeninfo *fix = &info->fix; int win_id; #if defined(CONFIG_RK_HDMI) @@ -2676,7 +2978,8 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf, u8 __iomem *src; int c, cnt = 0, err = 0; unsigned long total_size; - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_lcdc_win *win = NULL; int win_id = 0; @@ -2687,9 +2990,9 @@ static ssize_t rk_fb_read(struct fb_info *info, char __user *buf, win = dev_drv->win[win_id]; /* only read the current frame buffer */ - if (win->format == RGB565) { + if (win->area[0].format == RGB565) { total_size = win->area[0].y_vir_stride * win->area[0].yact << 1; - } else if (win->format == YUV420) { + } else if (win->area[0].format == YUV420) { total_size = (win->area[0].y_vir_stride * win->area[0].yact * 6); } else { @@ -2740,7 +3043,8 @@ static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf, u8 __iomem *dst; int c, cnt = 0, err = 0; unsigned long total_size; - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_lcdc_win *win = NULL; int win_id = 0; @@ -2751,7 +3055,7 @@ static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf, win = dev_drv->win[win_id]; /* write the current frame buffer */ - if (win->format == RGB565) + if (win->area[0].format == RGB565) total_size = win->area[0].xact * win->area[0].yact << 1; else total_size = win->area[0].xact * win->area[0].yact << 2; @@ -2800,11 +3104,83 @@ static ssize_t rk_fb_write(struct fb_info *info, const char __user *buf, return (cnt) ? cnt : err; } +/* + * function: update extend info acorrding to primary info that only used for dual display mode + * @ext_info: the fb_info of extend screen + * @info: the fb_info of primary screen + * @update_buffer: whether to update extend info buffer, 0: no;1: yes + */ +static int rk_fb_update_ext_info(struct fb_info *ext_info, + struct fb_info *info, int update_buffer) +{ + struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); + struct rk_fb_par *fb_par = NULL; + struct rk_fb_par *ext_fb_par = NULL; + struct rk_lcdc_driver *dev_drv = NULL; + struct rk_lcdc_driver *ext_dev_drv = NULL; + struct rk_lcdc_win *win = NULL; + struct rk_lcdc_win *ext_win = NULL; + int win_id = 0, ext_win_id = 0; + + if (rk_fb->disp_mode != DUAL || info == ext_info) + return 0; + if (unlikely(!info) || unlikely(!ext_info)) + return -1; + + fb_par = (struct rk_fb_par *)info->par; + ext_fb_par = (struct rk_fb_par *)ext_info->par; + dev_drv = fb_par->lcdc_drv; + ext_dev_drv = ext_fb_par->lcdc_drv; + if (unlikely(!dev_drv) || unlikely(!ext_dev_drv)) + return -1; + + win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); + win = dev_drv->win[win_id]; + ext_win_id = ext_dev_drv->ops->fb_get_win_id(ext_dev_drv, + ext_info->fix.id); + ext_win = ext_dev_drv->win[ext_win_id]; + + rk_fb_update_ext_win(ext_dev_drv, dev_drv, ext_win, win); + if (update_buffer) { + rk_fb_set_ext_win_buffer(ext_win, win, ext_dev_drv->rotate_mode, + ext_dev_drv->iommu_enabled); + + /* update extend info display address */ + ext_info->fix.smem_start = ext_win->area[0].smem_start; + ext_info->fix.mmio_start = ext_win->area[0].cbr_start; + + if (ext_dev_drv->rotate_mode > X_Y_MIRROR) + rk_fb_rotate(ext_info, info); + } + + /* update extend info */ + ext_info->var.xres = ext_win->area[0].xact; + ext_info->var.yres = ext_win->area[0].yact; + ext_info->var.xres_virtual = ext_win->area[0].xvir; + ext_info->var.yres_virtual = ext_win->area[0].yvir; + + /* config same data format */ + ext_info->var.nonstd &= 0xffffff00; + ext_info->var.nonstd |= (info->var.nonstd & 0xff); + + ext_info->var.nonstd &= 0xff; + ext_info->var.nonstd |= + (ext_win->area[0].xpos << 8) + (ext_win->area[0].ypos << 20); + + ext_info->var.grayscale &= 0xff; + ext_info->var.grayscale |= + (ext_win->area[0].xsize << 8) + (ext_win->area[0].ysize << 20); + + return 0; +} + static int rk_fb_set_par(struct fb_info *info) { struct fb_var_screeninfo *var = &info->var; struct fb_fix_screeninfo *fix = &info->fix; - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct rk_fb_par *extend_fb_par = NULL; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_fb *rk_fb = dev_get_drvdata(info->device); int fb_id, extend_win_id = 0; struct fb_info *extend_info = NULL; @@ -2837,15 +3213,17 @@ static int rk_fb_set_par(struct fb_info *info) return -ENODEV; else win = dev_drv->win[win_id]; + if (rk_fb->disp_mode == DUAL) { fb_id = get_extend_fb_id(info); extend_info = rk_fb->fb[(rk_fb->num_fb >> 1) + fb_id]; - extend_dev_drv = (struct rk_lcdc_driver *)extend_info->par; + extend_fb_par = (struct rk_fb_par *)extend_info->par; + extend_dev_drv = extend_fb_par->lcdc_drv; extend_win_id = dev_drv->ops->fb_get_win_id(extend_dev_drv, - extend_info->fix. - id); + extend_info->fix.id); extend_win = extend_dev_drv->win[extend_win_id]; } + /* if the application has specific the horizontal and vertical display size */ if (var->grayscale >> 8) { xsize = (var->grayscale >> 8) & 0xfff; @@ -2860,6 +3238,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 */ @@ -2906,52 +3291,7 @@ 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->format = fb_data_fmt; + win->area[0].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; @@ -2962,72 +3302,24 @@ static int rk_fb_set_par(struct fb_info *info) win->area[0].yact = var->yres; win->area[0].xvir = var->xres_virtual; /* virtual resolution stride --->LCDC_WINx_VIR */ win->area[0].yvir = var->yres_virtual; + win->area[0].xoff = xoffset; + win->area[0].yoff = yoffset; win->area_num = 1; win->alpha_mode = 4; /* AB_SRC_OVER; */ - win->alpha_en = ((win->format == ARGB888) || - (win->format == ABGR888)) ? 1 : 0; + 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; + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && + (win->area[0].format == YUV420 || win->area[0].format == YUV420_A)) + win->state = 1; if (rk_fb->disp_mode == DUAL) { - if (extend_win->state && (hdmi_switch_complete == 0xff)) { + if (extend_win->state && hdmi_switch_complete) { if (info != extend_info) { - if (win->area[0].xact < win->area[0].yact) { - extend_win->area[0].xact = - win->area[0].yact; - extend_win->area[0].yact = - win->area[0].xact; - extend_win->area[0].xvir = - win->area[0].yact; - extend_info->var.xres = var->yres; - extend_info->var.yres = var->xres; - extend_info->var.xres_virtual = - var->yres; - } else { - extend_win->area[0].xact = - win->area[0].xact; - extend_win->area[0].yact = - win->area[0].yact; - extend_win->area[0].xvir = - win->area[0].xvir; - extend_info->var.xres = var->xres; - extend_info->var.yres = var->yres; - extend_info->var.xres_virtual = - var->xres_virtual; - } - extend_win->area[0].y_vir_stride = - win->area[0].y_vir_stride; - extend_win->area[0].uv_vir_stride = - win->area[0].uv_vir_stride; - if (win->area[0].xpos != 0 || - win->area[0].ypos != 0) { - extend_win->area[0].xsize = - (extend_dev_drv->cur_screen->xsize * win->area[0].xsize) / screen->mode.xres; - extend_win->area[0].ysize = - (extend_dev_drv->cur_screen->ysize * win->area[0].ysize) / screen->mode.yres; - extend_win->area[0].xpos = - ((extend_dev_drv->cur_screen->mode.xres - extend_dev_drv->cur_screen->xsize) >> 1) + - extend_dev_drv->cur_screen->xsize * win->area[0].xpos / screen->mode.xres; - extend_win->area[0].ypos = - ((extend_dev_drv->cur_screen->mode.yres - extend_dev_drv->cur_screen->ysize) >> 1) + - extend_dev_drv->cur_screen->ysize * win->area[0].ypos / screen->mode.yres; - } else { /* the display image of the primary screen is full screen size */ - extend_win->area[0].xpos = - (extend_dev_drv->cur_screen->mode.xres - extend_dev_drv->cur_screen->xsize) >> 1; - extend_win->area[0].ypos = - (extend_dev_drv->cur_screen->mode.yres - extend_dev_drv->cur_screen->ysize) >> 1; - extend_win->area[0].xsize = - extend_dev_drv->cur_screen->xsize; - extend_win->area[0].ysize = - extend_dev_drv->cur_screen->ysize; - } - - extend_win->area[0].state = 1; - extend_win->area_num = 1; - extend_win->alpha_en = 0; - extend_win->format = win->format; - extend_info->var.nonstd &= 0xffffff00; - extend_info->var.nonstd |= data_format; + rk_fb_update_ext_win(extend_dev_drv, dev_drv, + extend_win, win); extend_dev_drv->ops->set_par(extend_dev_drv, extend_win_id); } @@ -3072,14 +3364,25 @@ static int fb_setcolreg(unsigned regno, static int rk_fb_mmap(struct fb_info *info, struct vm_area_struct *vma) { - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)info->par; - int win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); - struct rk_lcdc_win *win; - win = dev_drv->win[win_id]; + struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); + struct rk_fb_par *fb_par = (struct rk_fb_par *)info->par; + struct ion_handle *handle = fb_par->ion_hdl; + struct dma_buf *dma_buf = NULL; + + if (IS_ERR_OR_NULL(handle)) { + dev_err(info->dev, "failed to get ion handle:%ld\n", + PTR_ERR(handle)); + return -ENOMEM; + } + dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle); + if (IS_ERR_OR_NULL(dma_buf)) { + printk("get ion share dma buf failed\n"); + return -ENOMEM; + } vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); - return dma_buf_mmap(win->area[0].dma_buf, vma, 0); + return dma_buf_mmap(dma_buf, vma, 0); } static struct fb_ops fb_ops = { @@ -3090,6 +3393,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, @@ -3153,7 +3457,8 @@ static ssize_t rk_fb_vsync_show(struct device *dev, struct device_attribute *attr, char *buf) { struct fb_info *fbi = dev_get_drvdata(dev); - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)fbi->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; return scnprintf(buf, PAGE_SIZE, "%llu\n", ktime_to_ns(dev_drv->vsync_info.timestamp)); } @@ -3212,52 +3517,6 @@ int rk_fb_dpi_status(void) return ret; } -/* - * function: this function will be called to modify hdmi info according to - * pmy info for DUAL disp_mode when HDMI is used as EXTEND - * @pmy_info: primary screen fb_info - * @hdmi_info: hdmi screen fb_info - * @screen: the hdmi screen info - */ -static int rk_fb_hdmi_info_align(struct fb_info *pmy_info, - struct fb_info *hdmi_info, - struct rk_screen *screen) -{ - struct rk_fb *inf = platform_get_drvdata(fb_pdev); - struct fb_var_screeninfo *hdmi_var = NULL; - struct fb_var_screeninfo *pmy_var = NULL; - - if(unlikely(!pmy_info) || unlikely(!hdmi_info)) - return -1; - - if (inf->disp_mode != DUAL || pmy_info == hdmi_info) - return 0; - - pmy_var = &pmy_info->var; - hdmi_var = &hdmi_info->var; - if (pmy_var->xres < pmy_var->yres) { /* vertical lcd screen */ - hdmi_var->xres = pmy_var->yres; - hdmi_var->yres = pmy_var->xres; - hdmi_var->xres_virtual = pmy_var->yres; - } else { - hdmi_var->xres = pmy_var->xres; - hdmi_var->yres = pmy_var->yres; - hdmi_var->xres_virtual = pmy_var->xres_virtual; - } - - /* use the same format as primary screen */ - hdmi_var->nonstd &= 0xffffff00; - hdmi_var->nonstd |= (pmy_var->nonstd & 0xff); - - if (screen) { - hdmi_var->grayscale &= 0xff; - hdmi_var->grayscale |= (screen->mode.xres << 8) + - (screen->mode.yres << 20); - } - - return 0; -} - /* * function: this function will be called by display device, enable/disable lcdc * @screen: screen timing to be set to lcdc @@ -3269,14 +3528,16 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); struct fb_info *info = NULL; struct fb_info *pmy_info = NULL; + struct rk_fb_par *fb_par = NULL; + struct rk_fb_par *pmy_fb_par = NULL; struct rk_lcdc_driver *dev_drv = NULL; - struct rk_lcdc_driver *pmy_dev_drv = rk_get_prmry_lcdc_drv(); char name[6] = {0}; int i, win_id, load_screen = 0; - if (unlikely(!rk_fb) || unlikely(!pmy_dev_drv) || unlikely(!screen)) + if (unlikely(!rk_fb) || unlikely(!screen)) return -ENODEV; + hdmi_switch_complete = 0; /* get lcdc driver */ sprintf(name, "lcdc%d", lcdc_id); if (rk_fb->disp_mode != DUAL) @@ -3291,18 +3552,24 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_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) + else if (screen->type == SCREEN_TVOUT || + screen->type == SCREEN_TVOUT_TEST ) printk("cvbs %s lcdc%d\n", enable ? "connect to" : "remove from", dev_drv->id); - if (enable == 2 /*&& dev_drv->enable*/) return 0; - if (rk_fb->disp_mode == ONE_DUAL) { - if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable) - dev_drv->trsm_ops->disable(); - if (dev_drv->ops->set_screen_scaler) - dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 0); + 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) && + (rk_fb->disp_policy != DISPLAY_POLICY_BOX)) + dev_drv->ops->set_screen_scaler(dev_drv, + dev_drv->screen0, 0); } if (!enable) { @@ -3311,11 +3578,27 @@ 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); - if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) - dev_drv->trsm_ops->enable(); + + /* force modify dsp size */ + info = rk_fb->fb[dev_drv->fb_index_base]; + info->var.grayscale &= 0xff; + 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); + 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 */ @@ -3331,53 +3614,64 @@ int rk_fb_switch_screen(struct rk_screen *screen, int enable, int lcdc_id) 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; dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR; dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR; } - - for (i = 0; i < dev_drv->lcdc_win_num; i++) { - info = rk_fb->fb[dev_drv->fb_index_base + i]; - if (rk_fb->disp_mode == DUAL && - dev_drv != pmy_dev_drv) { - pmy_info = rk_fb->fb[pmy_dev_drv->fb_index_base + i]; - rk_fb_hdmi_info_align(pmy_info, info, - dev_drv->cur_screen); - } - - win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); - if (dev_drv->win[win_id]) { - if (rk_fb->disp_mode == DUAL) { - if (dev_drv != pmy_dev_drv && - pmy_dev_drv->win[win_id]) { - dev_drv->win[win_id]->logicalstate = - pmy_dev_drv->win[win_id]->logicalstate; - } - } - if (dev_drv->win[win_id]->logicalstate) { - 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; + if ((!dev_drv->uboot_logo) || + (rk_fb->disp_policy != DISPLAY_POLICY_BOX)) { + for (i = 0; i < dev_drv->lcdc_win_num; i++) { + info = rk_fb->fb[dev_drv->fb_index_base + i]; + fb_par = (struct rk_fb_par *)info->par; + win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); + if (dev_drv->win[win_id]) { + if (rk_fb->disp_mode == DUAL) { + pmy_info = rk_fb->fb[i]; + if (pmy_info != info) { + pmy_fb_par = + (struct rk_fb_par *)pmy_info->par; + fb_par->state = pmy_fb_par->state; + } } - info->var.activate |= FB_ACTIVATE_FORCE; - info->fbops->fb_set_par(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 + if (fb_par->state) { + 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; + if (rk_fb->disp_mode == DUAL) { + rk_fb_update_ext_info(info, pmy_info, 1); + } else if (rk_fb->disp_mode == ONE_DUAL) { + info->var.grayscale &= 0xff; + info->var.grayscale |= + (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); + } } } + }else { + dev_drv->uboot_logo = 0; } - - hdmi_switch_complete = 0xff; - if (rk_fb->disp_mode == ONE_DUAL) { - if (dev_drv->ops->set_screen_scaler) + hdmi_switch_complete = 1; + 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->trsm_ops && dev_drv->trsm_ops->enable) - dev_drv->trsm_ops->enable(); + 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; } @@ -3393,6 +3687,7 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id) { struct rk_fb *inf = platform_get_drvdata(fb_pdev); struct fb_info *info = NULL; + struct fb_info *pmy_info = NULL; struct fb_var_screeninfo *var = NULL; struct rk_lcdc_driver *dev_drv = NULL; u16 screen_x, screen_y; @@ -3416,10 +3711,12 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id) dev_drv = inf->lcdc_dev_drv[0]; } - if (inf->num_lcdc == 1) + if (inf->num_lcdc == 1) { info = inf->fb[0]; - else if (inf->num_lcdc == 2) + } else if (inf->num_lcdc == 2) { info = inf->fb[dev_drv->lcdc_win_num]; + pmy_info = inf->fb[0]; + } var = &info->var; screen_x = dev_drv->cur_screen->mode.xres; @@ -3437,16 +3734,23 @@ int rk_fb_disp_scale(u8 scale_x, u8 scale_y, u8 lcdc_id) ypos = (screen_y - screen_y * scale_y / 100) >> 1; dev_drv->cur_screen->xsize = screen_x * scale_x / 100; dev_drv->cur_screen->ysize = screen_y * scale_y / 100; - var->nonstd &= 0xff; - var->nonstd |= (xpos << 8) + (ypos << 20); - var->grayscale &= 0xff; - var->grayscale |= - (dev_drv->cur_screen->xsize << 8) + (dev_drv->cur_screen->ysize << 20); + if (inf->disp_mode == DUAL) { + rk_fb_update_ext_info(info, pmy_info, 0); + } else { + var->nonstd &= 0xff; + var->nonstd |= (xpos << 8) + (ypos << 20); + var->grayscale &= 0xff; + var->grayscale |= + (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_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0); */ dev_drv->ops->cfg_done(dev_drv); + mutex_unlock(&dev_drv->win_config); + return 0; } @@ -3456,7 +3760,8 @@ static int rk_fb_alloc_buffer_by_ion(struct fb_info *fbi, unsigned long fb_mem_size) { struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)fbi->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct ion_handle *handle; ion_phys_addr_t phy_addr; size_t len; @@ -3473,6 +3778,8 @@ static int rk_fb_alloc_buffer_by_ion(struct fb_info *fbi, PTR_ERR(handle)); return -ENOMEM; } + + fb_par->ion_hdl = handle; win->area[0].dma_buf = ion_share_dma_buf(rk_fb->ion_client, handle); if (IS_ERR_OR_NULL(win->area[0].dma_buf)) { printk("ion_share_dma_buf() failed\n"); @@ -3482,7 +3789,7 @@ static int rk_fb_alloc_buffer_by_ion(struct fb_info *fbi, if (dev_drv->prop == PRMRY) fbi->screen_base = ion_map_kernel(rk_fb->ion_client, handle); #ifdef CONFIG_ROCKCHIP_IOMMU - if (dev_drv->iommu_enabled) + if (dev_drv->iommu_enabled && dev_drv->mmu_dev) ret = ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle, (unsigned long *)&phy_addr, (unsigned long *)&len); @@ -3509,7 +3816,8 @@ err_share_dma_buf: static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) { struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); - struct rk_lcdc_driver *dev_drv = (struct rk_lcdc_driver *)fbi->par; + struct rk_fb_par *fb_par = (struct rk_fb_par *)fbi->par; + struct rk_lcdc_driver *dev_drv = fb_par->lcdc_drv; struct rk_lcdc_win *win = NULL; int win_id; int ret = 0; @@ -3579,11 +3887,9 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) } fbi->screen_size = fbi->fix.smem_len; - win_id = dev_drv->ops->fb_get_win_id(dev_drv, fbi->fix.id); - if (win_id >= 0) { - win = dev_drv->win[win_id]; - win->reserved = fbi->fix.smem_start; - } + fb_par->fb_phy_base = fbi->fix.smem_start; + fb_par->fb_virt_base = fbi->screen_base; + fb_par->fb_size = fbi->fix.smem_len; return ret; } @@ -3669,6 +3975,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; @@ -3685,6 +3993,7 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb, 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; } @@ -3734,12 +4043,9 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, { struct rk_fb *rk_fb = platform_get_drvdata(fb_pdev); struct fb_info *fbi; + struct rk_fb_par *fb_par = NULL; int i = 0, ret = 0, index = 0; -/* -#if defined(CONFIG_ROCKCHIP_IOMMU) - struct device *mmu_dev = NULL; -#endif -*/ + if (rk_fb->num_lcdc == RK30_MAX_LCDC_SUPPORT) return -ENXIO; @@ -3761,7 +4067,16 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, dev_err(&fb_pdev->dev, "fb framebuffer_alloc fail!"); ret = -ENOMEM; } - fbi->par = dev_drv; + fb_par = devm_kzalloc(&fb_pdev->dev, sizeof(struct rk_fb_par), + GFP_KERNEL); + if (!fb_par) { + dev_err(&fb_pdev->dev, "malloc fb_par for fb%d fail!", + rk_fb->num_fb); + return -ENOMEM; + } + fb_par->id = rk_fb->num_fb; + fb_par->lcdc_drv = dev_drv; + fbi->par = (void *)fb_par; fbi->var = def_var; fbi->fix = def_fix; sprintf(fbi->fix.id, "fb%d", rk_fb->num_fb); @@ -3839,7 +4154,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); @@ -3853,14 +4168,75 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, #endif rk_fb_alloc_buffer(main_fbi, 0); /* only alloc memory for main fb */ - if (support_uboot_display()) { - if (dev_drv->iommu_enabled) { - rk_fb_copy_from_loader(main_fbi); - dev_drv->ops->direct_set_addr(dev_drv, 0, - main_fbi->fix.smem_start); + dev_drv->uboot_logo = support_uboot_display(); + + if (uboot_logo_offset && uboot_logo_base) { + struct rk_lcdc_win *win = dev_drv->win[0]; + int width, height, bits; + phys_addr_t start = uboot_logo_base + uboot_logo_offset; + unsigned int size = uboot_logo_size - uboot_logo_offset; + unsigned int nr_pages; + struct page **pages; + char *vaddr; + int i = 0; + + nr_pages = size >> PAGE_SHIFT; + pages = kzalloc(sizeof(struct page) * nr_pages, + GFP_KERNEL); + while (i < nr_pages) { + pages[i] = phys_to_page(start); + start += PAGE_SIZE; + i++; + } + vaddr = vmap(pages, nr_pages, VM_MAP, + pgprot_writecombine(PAGE_KERNEL)); + if (!vaddr) { + pr_err("failed to vmap phy addr 0x%lx\n", + (long)(uboot_logo_base + + uboot_logo_offset)); + return -1; + } + + if(bmpdecoder(vaddr, main_fbi->screen_base, &width, + &height, &bits)) { + kfree(pages); + vunmap(vaddr); + return 0; + } + kfree(pages); + vunmap(vaddr); + if (width > main_fbi->var.xres || + height > main_fbi->var.yres) { + pr_err("ERROR: logo size out of screen range"); + return 0; } + + win->area[0].format = rk_fb_data_fmt(0, bits); + win->area[0].y_vir_stride = width * bits >> 5; + win->area[0].xpos = (main_fbi->var.xres - width) >> 1; + win->area[0].ypos = (main_fbi->var.yres - height) >> 1; + win->area[0].xsize = width; + win->area[0].ysize = height; + win->area[0].xact = width; + win->area[0].yact = height; + win->area[0].xvir = win->area[0].y_vir_stride; + win->area[0].yvir = height; + win->area[0].smem_start = main_fbi->fix.smem_start; + win->area[0].y_offset = 0; + + win->area_num = 1; + win->alpha_mode = 4; + win->alpha_en = 0; + win->g_alpha_val = 0; + + win->state = 1; + dev_drv->ops->set_par(dev_drv, 0); + dev_drv->ops->pan_display(dev_drv, 0); + dev_drv->ops->cfg_done(dev_drv); + return 0; } +#if defined(CONFIG_LOGO) main_fbi->fbops->fb_set_par(main_fbi); #if defined(CONFIG_LOGO_LINUX_BMP) if (fb_prewine_bmp_logo(main_fbi, FB_ROTATE_UR)) { @@ -3874,13 +4250,12 @@ int rk_fb_register(struct rk_lcdc_driver *dev_drv, } #endif main_fbi->fbops->fb_pan_display(&main_fbi->var, main_fbi); +#endif } else { -#if !defined(CONFIG_ROCKCHIP_IOMMU) struct fb_info *extend_fbi = rk_fb->fb[rk_fb->num_fb >> 1]; int extend_fb_id = get_extend_fb_id(extend_fbi); rk_fb_alloc_buffer(extend_fbi, extend_fb_id); -#endif } #endif return 0; @@ -3939,6 +4314,11 @@ static int rk_fb_probe(struct platform_device *pdev) dev_err(&pdev->dev, "no disp-mode node found!"); return -ENODEV; } + + if (!of_property_read_u32(np, "rockchip,disp-policy", &mode)) { + rk_fb->disp_policy = mode; + pr_info("fb disp policy is %s\n", rk_fb->disp_policy ? "box":"sdk"); + } if (!of_property_read_u32(np, "rockchip,uboot-logo-on", &uboot_logo_on)) printk(KERN_DEBUG "uboot-logo-on:%d\n", uboot_logo_on);