X-Git-Url: http://demsky.eecs.uci.edu/git/?a=blobdiff_plain;f=drivers%2Fvideo%2Frockchip%2Frk_fb.c;h=5ae5a4c113a383c550a9c07fc91daa899920d876;hb=63005410975b5edd621e807d5b0a021c59de26fd;hp=8fecb9d729567345a7dfea77926ce8192f4cfd1c;hpb=68fe6924d38d1df6042a59acb04d6bfc8669e0d8;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 8fecb9d72956..5ae5a4c113a3 100755 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -24,14 +24,18 @@ #include #include #include +#include #include #include #include #include #include +#include + +#include "bmp_helper.h" #if defined(CONFIG_RK_HDMI) -#include "hdmi/rk_hdmi.h" +#include "hdmi/rockchip-hdmi.h" #endif #if defined(CONFIG_ROCKCHIP_RGA) || defined(CONFIG_ROCKCHIP_RGA2) @@ -55,18 +59,19 @@ #endif #define H_USE_FENCE 1 +/* #define FB_ROATE_BY_KERNEL 1 */ + static int hdmi_switch_complete; static struct platform_device *fb_pdev; -struct list_head saved_list; #if defined(CONFIG_FB_MIRRORING) 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,12 +81,26 @@ 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) { case SCREEN_RGB: case SCREEN_LVDS: case SCREEN_DUAL_LVDS: + case SCREEN_LVDS_10BIT: + case SCREEN_DUAL_LVDS_10BIT: trsm_lvds_ops = ops; break; case SCREEN_EDP: @@ -106,6 +125,8 @@ struct rk_fb_trsm_ops *rk_fb_trsm_ops_get(int type) case SCREEN_RGB: case SCREEN_LVDS: case SCREEN_DUAL_LVDS: + case SCREEN_LVDS_10BIT: + case SCREEN_DUAL_LVDS_10BIT: ops = trsm_lvds_ops; break; case SCREEN_EDP: @@ -131,16 +152,21 @@ int rk_fb_pixel_width(int data_format) case XBGR888: case ABGR888: case ARGB888: + case FBDC_ARGB_888: + case FBDC_ABGR_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: case YUV420: + case YUV420_NV21: case YUV444: pixel_width = 1 * 8; break; @@ -180,6 +206,9 @@ static int rk_fb_data_fmt(int data_format, int bits_per_pixel) case HAL_PIXEL_FORMAT_YCbCr_422_SP: /* yuv422 */ fb_data_fmt = YUV422; break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: /* YUV420---vuvuvu */ + fb_data_fmt = YUV420_NV21; + break; case HAL_PIXEL_FORMAT_YCrCb_NV12: /* YUV420---uvuvuv */ fb_data_fmt = YUV420; break; @@ -195,6 +224,18 @@ 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_RGBA888: /* fbdc abgr888 */ + fb_data_fmt = FBDC_ABGR_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 +246,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 +308,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 +355,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 +367,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 +399,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; } @@ -347,6 +449,8 @@ int rk_fb_video_mode_from_timing(const struct display_timing *dt, screen->type = dt->screen_type; 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; @@ -423,6 +527,7 @@ char *get_format_string(enum data_format format, char *fmt) strcpy(fmt, "RGB565"); break; case YUV420: + case YUV420_NV21: strcpy(fmt, "YUV420"); break; case YUV422: @@ -447,7 +552,17 @@ 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: + case FBDC_ABGR_888: + strcpy(fmt, "FBDC_ARGB_888"); + break; + case FBDC_RGBX_888: + strcpy(fmt, "FBDC_RGBX_888"); break; default: strcpy(fmt, "invalid"); @@ -464,14 +579,23 @@ char *get_format_string(enum data_format format, char *fmt) */ struct rk_lcdc_driver *rk_get_lcdc_drv(char *name) { - struct rk_fb *inf = platform_get_drvdata(fb_pdev); + struct rk_fb *inf = NULL; + struct rk_lcdc_driver *dev_drv = NULL; int i = 0; + + if (likely(fb_pdev)) + inf = platform_get_drvdata(fb_pdev); + else + return NULL; + for (i = 0; i < inf->num_lcdc; i++) { - if (!strcmp(inf->lcdc_dev_drv[i]->name, name)) + if (!strcmp(inf->lcdc_dev_drv[i]->name, name)) { + dev_drv = inf->lcdc_dev_drv[i]; break; + } } - return inf->lcdc_dev_drv[i]; + return dev_drv; } static struct rk_lcdc_driver *rk_get_prmry_lcdc_drv(void) @@ -495,6 +619,27 @@ static struct rk_lcdc_driver *rk_get_prmry_lcdc_drv(void) return dev_drv; } +static __maybe_unused struct rk_lcdc_driver *rk_get_extend_lcdc_drv(void) +{ + struct rk_fb *inf = NULL; + struct rk_lcdc_driver *dev_drv = NULL; + int i = 0; + + if (likely(fb_pdev)) + inf = platform_get_drvdata(fb_pdev); + else + return NULL; + + for (i = 0; i < inf->num_lcdc; i++) { + if (inf->lcdc_dev_drv[i]->prop == EXTEND) { + dev_drv = inf->lcdc_dev_drv[i]; + break; + } + } + + return dev_drv; +} + /* * get one frame time of the prmry screen, unit: us */ @@ -606,43 +751,6 @@ int rk_fb_set_prmry_screen_status(int status) return 0; } -static int rk_fb_set_screen_scaler(struct rk_screen *screen, bool enable) -{ - struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv(); - - if(unlikely(!dev_drv) || unlikely(!screen)) - return -1; - if (!enable) - return 0; - - rk_fb_set_prmry_screen_status(SCREEN_PREPARE_DDR_CHANGE); - if (dev_drv->ops->set_screen_scaler) - dev_drv->ops->set_screen_scaler(dev_drv, screen, enable); - rk_fb_set_prmry_screen_status(SCREEN_UNPREPARE_DDR_CHANGE); - return 0; -} - -static struct rk_lcdc_driver *rk_get_extend_lcdc_drv(void) -{ - struct rk_fb *inf = NULL; - struct rk_lcdc_driver *dev_drv = NULL; - int i = 0; - - if (likely(fb_pdev)) - inf = platform_get_drvdata(fb_pdev); - else - return NULL; - - for (i = 0; i < inf->num_lcdc; i++) { - if (inf->lcdc_dev_drv[i]->prop == EXTEND) { - dev_drv = inf->lcdc_dev_drv[i]; - break; - } - } - - return dev_drv; -} - u32 rk_fb_get_prmry_screen_pixclock(void) { struct rk_lcdc_driver *dev_drv = rk_get_prmry_lcdc_drv(); @@ -697,33 +805,31 @@ bool rk_fb_poll_wait_frame_complete(void) } -/**** -1,success : pointer to the device inside of platform device -2,fail : NULL -****/ +/* rk_fb_get_sysmmu_device_by_compatible() + * @compt: dts device compatible name + * return value: success: pointer to the device inside of platform device + * fail: NULL + */ struct device *rk_fb_get_sysmmu_device_by_compatible(const char *compt) { struct device_node *dn = NULL; struct platform_device *pd = NULL; struct device *ret = NULL ; - dn = of_find_compatible_node(NULL,NULL,compt); - if(!dn) - { - printk("can't find device node %s \r\n",compt); + dn = of_find_compatible_node(NULL, NULL, compt); + if (!dn) { + printk("can't find device node %s \r\n", compt); return NULL; } pd = of_find_device_by_node(dn); - if(!pd) - { - printk("can't find platform device in device node %s \r\n",compt); + if (!pd) { + printk("can't find platform device in device node %s \r\n", compt); return NULL; } ret = &pd->dev; return ret; - } #ifdef CONFIG_IOMMU_API @@ -734,17 +840,18 @@ void rk_fb_platform_set_sysmmu(struct device *sysmmu, struct device *dev) #else void rk_fb_platform_set_sysmmu(struct device *sysmmu, struct device *dev) { - + } #endif 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; @@ -753,32 +860,19 @@ static int rk_fb_open(struct fb_info *info, int user) return 0; } -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; - - if (!strcmp(id, "fb0")) - fb_id = 0; - else if (!strcmp(id, "fb1")) - fb_id = 1; - else if (!strcmp(id, "fb2") && (dev_drv->lcdc_win_num > 2)) - fb_id = 2; - 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; /* @@ -809,6 +903,7 @@ static int rk_fb_close(struct fb_info *info, int user) return 0; } +#if defined(FB_ROATE_BY_KERNEL) #if defined(CONFIG_RK29_IPP) static int get_ipp_format(int fmt) @@ -880,15 +975,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)); @@ -973,27 +1068,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; + int format = 0; - 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); + 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) @@ -1001,7 +1099,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; @@ -1047,17 +1146,6 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, break; } -#if defined(CONFIG_ROCKCHIP_RGA) - Rga_Request.src.yrgb_addr = - src_win->area[0].smem_start + src_win->area[0].y_offset; - Rga_Request.src.uv_addr = 0; - Rga_Request.src.v_addr = 0; - - Rga_Request.dst.yrgb_addr = - dst_win->area[0].smem_start + dst_win->area[0].y_offset; - Rga_Request.dst.uv_addr = 0; - Rga_Request.dst.v_addr = 0; -#elif defined(CONFIG_ROCKCHIP_RGA2) /* fd = ion_share_dma_buf_fd(rk_fb->ion_client, src_win->area[0].ion_hdl); Rga_Request.src.yrgb_addr = fd; @@ -1073,11 +1161,10 @@ static void win_copy_by_rga(struct rk_lcdc_win *dst_win, Rga_Request.dst.uv_addr = dst_win->area[0].smem_start + dst_win->area[0].y_offset; Rga_Request.dst.v_addr = 0; -#endif 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; @@ -1085,7 +1172,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; @@ -1093,8 +1180,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; @@ -1108,12 +1200,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; @@ -1124,56 +1217,51 @@ 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 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) +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); + win_copy_by_rga(dst_win, src_win, rotate, iommu_en); #else return -1; #endif return 0; } +#endif 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_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; - int win_id = 0, extend_win_id = 0; - struct rk_lcdc_win *extend_win = NULL; + int win_id = 0; struct rk_lcdc_win *win = NULL; struct rk_screen *screen = dev_drv->cur_screen; - int fb_id = 0; - u32 xoffset = var->xoffset; u32 yoffset = var->yoffset; u32 xvir = var->xres_virtual; - /* u32 yvir = var->yres_virtual; */ - /* u8 data_format = var->nonstd&0xff; */ - u8 pixel_width; u32 vir_width_bit; u32 stride, uv_stride; @@ -1188,22 +1276,12 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, 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_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; @@ -1214,7 +1292,8 @@ static int rk_fb_pan_display(struct fb_var_screeninfo *var, fix->line_length = stride; uv_y_act = win->area[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -1289,30 +1368,15 @@ 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)) { - 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 { - extend_win->area[0].smem_start = - win->area[0].smem_start; - extend_win->area[0].cbr_start = - win->area[0].cbr_start; - } - extend_dev_drv->ops->pan_display(extend_dev_drv, - extend_win_id); - } - } + #ifdef CONFIG_FB_MIRRORING if (video_data_to_mirroring) video_data_to_mirroring(info, NULL); #endif dev_drv->ops->cfg_done(dev_drv); + return 0; } @@ -1321,7 +1385,7 @@ static int rk_fb_get_list_stat(struct rk_lcdc_driver *dev_drv) int i, j; i = list_empty(&dev_drv->update_regs_list); - j = list_empty(&saved_list); + j = list_empty(&dev_drv->saved_list); return i == j ? 0 : 1; } @@ -1338,18 +1402,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) { @@ -1358,9 +1427,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; @@ -1419,36 +1490,45 @@ 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) { - ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client, - area_data->ion_handle); + if ((rk_fb->disp_policy != DISPLAY_POLICY_BOX) && + (area_data->ion_handle != NULL)) + ion_unmap_iommu(dev_drv->dev, rk_fb->ion_client, + area_data->ion_handle); freed_addr[freed_index++] = area_data->smem_start; } #endif - if (area_data->ion_handle != NULL) { - ion_unmap_kernel(rk_fb->ion_client, - area_data->ion_handle); + if (area_data->ion_handle != NULL) ion_free(rk_fb->ion_client, area_data->ion_handle); - } + if (area_data->acq_fence) sync_fence_put(area_data->acq_fence); } memset(reg_win_data, 0, sizeof(struct rk_fb_reg_win_data)); } -static void rk_fb_update_driver(struct rk_lcdc_win *win, +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) { int i = 0; + struct rk_fb *inf = platform_get_drvdata(fb_pdev); + struct rk_screen *cur_screen; + struct rk_screen primary_screen; + + if (unlikely(!inf) || unlikely(!dev_drv) || + unlikely(!win) || unlikely(!reg_win_data)) + return; + + cur_screen = dev_drv->cur_screen; + 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 = @@ -1459,18 +1539,69 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win, 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].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; - win->area[i].xpos = - reg_win_data->reg_area_data[i].xpos; - win->area[i].ypos = - reg_win_data->reg_area_data[i].ypos; - win->area[i].xsize = - reg_win_data->reg_area_data[i].xsize; - win->area[i].ysize = - reg_win_data->reg_area_data[i].ysize; + reg_win_data->reg_area_data[i].smem_start; + 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 = + reg_win_data->reg_area_data[i].ypos; + win->area[i].xsize = + reg_win_data->reg_area_data[i].xsize; + win->area[i].ysize = + reg_win_data->reg_area_data[i].ysize; + } else { + win->area[i].xpos = + reg_win_data->reg_area_data[i].xpos * + cur_screen->mode.xres / + primary_screen.mode.xres; + win->area[i].ypos = + reg_win_data->reg_area_data[i].ypos * + cur_screen->mode.yres / + primary_screen.mode.yres; + win->area[i].xsize = + reg_win_data->reg_area_data[i].xsize * + cur_screen->mode.xres / + primary_screen.mode.xres; + win->area[i].ysize = + 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; win->area[i].yact = @@ -1479,6 +1610,10 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win, 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 = @@ -1496,189 +1631,6 @@ static void rk_fb_update_driver(struct rk_lcdc_win *win, } } -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; - - if ((rk_fb->disp_mode != DUAL) || - (hdmi_get_hotplug() != HDMI_HPD_ACTIVED) || - (!hdmi_switch_complete)) { - 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 { - ext_win->area[0].smem_start = win->area[0].smem_start; - 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; - ext_win->area[0].cbr_start = win->area[0].cbr_start; - 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) { @@ -1701,13 +1653,12 @@ 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); - struct rk_lcdc_driver *ext_dev_drv; - struct rk_lcdc_win *ext_win; struct rk_fb_reg_win_data *win_data; bool wait_for_vsync; int count = 100; unsigned int dsp_addr[4]; long timeout; + int win_status = 0; /* acq_fence wait */ for (i = 0; i < regs->win_num; i++) { @@ -1724,10 +1675,17 @@ 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(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_NV21 || + 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 + @@ -1740,40 +1698,6 @@ 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_mode == DUAL) - && (hdmi_get_hotplug() == HDMI_HPD_ACTIVED) - && 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 (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); - - if (ext_dev_drv->rotate_mode > X_Y_MIRROR) - rk_fb_win_rotate(ext_win, win, - ext_dev_drv->rotate_mode); - - ext_dev_drv->ops->set_par(ext_dev_drv, i); - ext_dev_drv->ops->pan_display(ext_dev_drv, i); - } - - ext_dev_drv->ops->cfg_done(ext_dev_drv); - } -ext_win_exit: dev_drv->ops->cfg_done(dev_drv); do { @@ -1781,15 +1705,23 @@ 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)); + 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 (rk_fb->disp_policy == DISPLAY_POLICY_BOX && + (!strcmp(dev_drv->win[i]->name, "hwc"))) + continue; 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 ((rk_fb->disp_policy == + DISPLAY_POLICY_BOX) && + (dev_drv->suspend_flag)) + continue; if (unlikely(new_start != reg_start)) { wait_for_vsync = true; dev_info(dev_drv->dev, @@ -1797,33 +1729,53 @@ ext_win_exit: i, new_start, reg_start, 101 - count); break; } + } else if (dev_drv->win[i]->state == 0) { + if (dev_drv->ops->get_win_state) { + win_status = + dev_drv->ops->get_win_state(dev_drv, i); + if (win_status) + wait_for_vsync = true; + } + } else { + pr_err("!!!win[%d]state:%d,error!!!\n", + i, dev_drv->win[i]->state); } } } while (wait_for_vsync && count--); #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) @@ -1831,17 +1783,15 @@ static void rk_fb_update_regs_handler(struct kthread_work *work) struct rk_lcdc_driver *dev_drv = container_of(work, struct rk_lcdc_driver, update_regs_work); struct rk_fb_reg_data *data, *next; - /* struct list_head saved_list; */ mutex_lock(&dev_drv->update_regs_list_lock); - saved_list = dev_drv->update_regs_list; - list_replace_init(&dev_drv->update_regs_list, &saved_list); + dev_drv->saved_list = dev_drv->update_regs_list; + list_replace_init(&dev_drv->update_regs_list, &dev_drv->saved_list); mutex_unlock(&dev_drv->update_regs_list_lock); - list_for_each_entry_safe(data, next, &saved_list, list) { + list_for_each_entry_safe(data, next, &dev_drv->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)) @@ -1863,7 +1813,7 @@ static int rk_fb_check_config_var(struct rk_fb_area_par *area_par, if ((area_par->xpos + area_par->xsize > screen->mode.xres) || (area_par->ypos + area_par->ysize > screen->mode.yres) || (area_par->xsize <= 0) || (area_par->ysize <= 0)) { - pr_err("check config var fail 1:\n" + pr_warn("check config var fail 1:\n" "xpos=%d,xsize=%d,xres=%d\n" "ypos=%d,ysize=%d,yres=%d\n", area_par->xpos, area_par->xsize, screen->mode.xres, @@ -1879,9 +1829,10 @@ 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 fb_info *fbi = rk_fb->fb[0]; + struct fb_info *fbi; int i, ion_fd, acq_fence_fd; u32 xvir, yvir; u32 xoffset, yoffset; @@ -1899,6 +1850,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info, u8 is_pic_yuv = 0; u8 ppixel_a = 0, global_a = 0; ion_phys_addr_t phy_addr; + int ret = 0; + int buff_len; reg_win_data->reg_area_data[0].smem_start = -1; reg_win_data->area_num = 0; @@ -1911,39 +1864,43 @@ 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; } - fbi->screen_base = - ion_map_kernel(rk_fb->ion_client, hdl); reg_win_data->area_num++; reg_win_data->reg_area_data[i].ion_handle = hdl; #ifndef CONFIG_ROCKCHIP_IOMMU - ion_phys(rk_fb->ion_client, hdl, &phy_addr, - &len); + ret = ion_phys(rk_fb->ion_client, hdl, &phy_addr, + &len); #else if (dev_drv->iommu_enabled) - ion_map_iommu(dev_drv->dev, - rk_fb->ion_client, - hdl, - (unsigned long *)&phy_addr, - (unsigned long *)&len); + ret = ion_map_iommu(dev_drv->dev, + rk_fb->ion_client, + hdl, + (unsigned long *)&phy_addr, + (unsigned long *)&len); else - ion_phys(rk_fb->ion_client, hdl, - &phy_addr, &len); + ret = ion_phys(rk_fb->ion_client, hdl, + &phy_addr, &len); #endif + if (ret < 0) { + dev_err(fbi->dev, "ion map to get phy addr failed\n"); + ion_free(rk_fb->ion_client, hdl); + return -ENOMEM; + } reg_win_data->reg_area_data[i].smem_start = phy_addr; reg_win_data->area_buf_num++; reg_win_data->reg_area_data[i].index_buf = 1; + reg_win_data->reg_area_data[i].buff_len = len; } } } else { reg_win_data->reg_area_data[0].smem_start = win_par->area_par[0].phy_addr; reg_win_data->area_num = 1; + reg_win_data->area_buf_num++; fbi->screen_base = phys_to_virt(win_par->area_par[0].phy_addr); } @@ -1958,16 +1915,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; @@ -1975,8 +1922,26 @@ static int rk_fb_set_win_buffer(struct fb_info *info, reg_win_data->z_order = -1; reg_win_data->win_id = -1; } + + 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], 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 == FBDC_ABGR_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; @@ -1991,6 +1956,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; @@ -2009,7 +1977,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 + @@ -2032,7 +2000,33 @@ static int rk_fb_set_win_buffer(struct fb_info *info, xoffset * pixel_width / 8; } } + if ((fb_data_fmt != YUV420) && + (fb_data_fmt != YUV420_NV21) && + (fb_data_fmt != YUV422) && + (fb_data_fmt != YUV444)) { + buff_len = reg_win_data->reg_area_data[i].y_offset + + reg_win_data->reg_area_data[i].xvir * + reg_win_data->reg_area_data[i].yact * + pixel_width / 8 - + reg_win_data->reg_area_data[i].xoff* + pixel_width / 8; + if (buff_len > reg_win_data->reg_area_data[i].buff_len) + pr_err("\n!!!!!!error: fmt=%d,xvir[%d]*" + "yact[%d]*bpp[%d]" + "=buff_len[0x%x]>>mmu len=0x%x\n", + fb_data_fmt, + reg_win_data->reg_area_data[i].xvir, + reg_win_data->reg_area_data[i].yact, + pixel_width, buff_len, + reg_win_data->reg_area_data[i].buff_len); + } } + + 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: @@ -2044,7 +2038,8 @@ static int rk_fb_set_win_buffer(struct fb_info *info, fix->line_length = stride; uv_y_act = win_par->area_par[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -2071,7 +2066,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 + @@ -2094,14 +2089,38 @@ static int rk_fb_set_win_buffer(struct fb_info *info, uv_x_off * pixel_width / 8; } } - } + buff_len = reg_win_data->reg_area_data[0].cbr_start + + reg_win_data->reg_area_data[0].c_offset + + reg_win_data->reg_area_data[0].xvir * + reg_win_data->reg_area_data[0].yact * + pixel_width / 16 - + reg_win_data->reg_area_data[0].smem_start - + reg_win_data->reg_area_data[0].xoff* + pixel_width / 16 ; + if (buff_len > reg_win_data->reg_area_data[0].buff_len) + pr_err("\n!!!!!!error: fmt=%d,xvir[%d]*" + "yact[%d]*bpp[%d]" + "=buff_len[0x%x]>>mmu len=0x%x\n", + fb_data_fmt, + reg_win_data->reg_area_data[0].xvir, + reg_win_data->reg_area_data[0].yact, + pixel_width, buff_len, + reg_win_data->reg_area_data[0].buff_len); + } + + /* 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]; @@ -2113,6 +2132,12 @@ static int rk_fb_set_win_config(struct fb_info *info, int ret = 0, i, j = 0; int list_is_empty = 0; + if (dev_drv->suspend_flag) { + dev_drv->timeline_max++; + sw_sync_timeline_inc(dev_drv->timeline, 1); + return 0; + } + regs = kzalloc(sizeof(struct rk_fb_reg_data), GFP_KERNEL); if (!regs) { printk(KERN_INFO "could not allocate rk_fb_reg_data\n"); @@ -2129,8 +2154,9 @@ static int rk_fb_set_win_config(struct fb_info *info, for (i = 0; i < dev_drv->lcdc_win_num; i++) { if (win_data->win_par[i].win_id < dev_drv->lcdc_win_num) { - rk_fb_set_win_buffer(info, &win_data->win_par[i], - ®s->reg_win_data[j]); + if (rk_fb_set_win_buffer(info, &win_data->win_par[i], + ®s->reg_win_data[j])) + return -ENOMEM; if (regs->reg_win_data[j].area_num > 0) { regs->win_num++; regs->buf_num += @@ -2145,12 +2171,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; - } dev_drv->timeline_max++; #ifdef H_USE_FENCE @@ -2179,6 +2199,7 @@ static int rk_fb_set_win_config(struct fb_info *info, win_data->ret_fence_fd = get_unused_fd(); if (win_data->ret_fence_fd < 0) { printk("ret_fence_fd=%d\n", win_data->ret_fence_fd); + win_data->ret_fence_fd = -1; ret = -EFAULT; goto err; } @@ -2201,11 +2222,11 @@ static int rk_fb_set_win_config(struct fb_info *info, } else { mutex_lock(&dev_drv->update_regs_list_lock); list_is_empty = list_empty(&dev_drv->update_regs_list) && - list_empty(&saved_list); + list_empty(&dev_drv->saved_list); mutex_unlock(&dev_drv->update_regs_list_lock); if (!list_is_empty) { ret = wait_event_timeout(dev_drv->update_regs_wait, - list_empty(&dev_drv->update_regs_list) && list_empty(&saved_list), + list_empty(&dev_drv->update_regs_list) && list_empty(&dev_drv->saved_list), msecs_to_jiffies(60)); if (ret > 0) rk_fb_update_reg(dev_drv, regs); @@ -2214,7 +2235,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: @@ -2292,17 +2312,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_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; - struct rk_lcdc_driver *extend_dev_drv = NULL; - struct rk_lcdc_win *extend_win = NULL; struct rk_lcdc_win *win; int enable; /* enable fb:1 enable;0 disable */ int ovl; /* overlay:0 win1 on the top of win0;1,win0 on the top of win1 */ @@ -2316,16 +2334,58 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, void __user *argp = (void __user *)arg; 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_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; + dev_drv->ops->open(dev_drv, win_id, 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]; @@ -2346,26 +2406,40 @@ static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd, usr_fd = yuv_phy[0]; offset = yuv_phy[1] - yuv_phy[0]; - if (!usr_fd) { fix->smem_start = 0; fix->mmio_start = 0; 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); - ion_map_iommu(dev_drv->dev, rk_fb->ion_client, hdl, - (unsigned long *)&phy_addr, (unsigned long *)&len); + 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); + if (ret < 0) { + dev_err(info->dev, "ion map to get phy addr failed"); + ion_free(rk_fb->ion_client, hdl); + return -ENOMEM; + } 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; @@ -2376,6 +2450,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: @@ -2436,9 +2514,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"); @@ -2450,7 +2534,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: { @@ -2495,7 +2579,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) @@ -2559,7 +2644,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; @@ -2570,9 +2656,10 @@ 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) || + (win->area[0].format == YUV420_NV21)) { total_size = (win->area[0].y_vir_stride * win->area[0].yact * 6); } else { @@ -2623,7 +2710,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; @@ -2634,7 +2722,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; @@ -2687,15 +2775,11 @@ 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_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; - struct rk_lcdc_driver *extend_dev_drv = NULL; - 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 */ @@ -2721,41 +2805,28 @@ 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_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]; - } + /* if the application has specific the horizontal and vertical display size */ 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; } -/*this is for device like rk2928 ,whic have one lcdc but two display outputs*/ -/*save winameter set by android*/ - if (rk_fb->disp_mode != DUAL) { - if (screen->screen_id == 0) { - dev_drv->screen0->xsize = xsize; - dev_drv->screen0->ysize = ysize; - dev_drv->screen0->xpos = xpos; - dev_drv->screen0->ypos = ypos; - } else { - xsize = dev_drv->screen1->xsize; - ysize = dev_drv->screen1->ysize; - xpos = dev_drv->screen1->xpos; - ypos = dev_drv->screen1->ypos; - } - } - 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 */ @@ -2774,7 +2845,8 @@ static int rk_fb_set_par(struct fb_info *info) cblen = crlen = (xvir * yvir) >> 1; uv_y_act = win->area[0].yact >> 1; break; - case YUV420: /* 420sp */ + case YUV420: /* nv12 */ + case YUV420_NV21: /* nv21 */ case YUV420_A: is_pic_yuv = 1; stride = stride_32bit_1; @@ -2847,89 +2919,34 @@ 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].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 */ 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 == FBDC_ABGR_888) || + (win->area[0].format == ABGR888)) ? 1 : 0; win->g_alpha_val = 0; - if (rk_fb->disp_mode == DUAL) { - 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; - } + if (rk_fb->disp_policy == DISPLAY_POLICY_BOX && + (win->area[0].format == YUV420 || + win->area[0].format == YUV420_NV21 || + win->area[0].format == YUV420_A)) + win->state = 1; - 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; - extend_dev_drv->ops->set_par(extend_dev_drv, - extend_win_id); - } - } - } dev_drv->ops->set_par(dev_drv, win_id); return 0; @@ -2969,14 +2986,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 = { @@ -3050,7 +3078,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)); } @@ -3076,23 +3105,7 @@ void rk_direct_fb_show(struct fb_info *fbi) rk_fb_pan_display(&fbi->var, fbi); } EXPORT_SYMBOL(rk_direct_fb_show); -#if 0 -static int set_xact_yact_for_hdmi(struct fb_var_screeninfo *pmy_var, - struct fb_var_screeninfo *hdmi_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; - } - return 0; -} -#endif int rk_fb_dpi_open(bool open) { struct rk_lcdc_driver *dev_drv = NULL; @@ -3124,242 +3137,144 @@ int rk_fb_dpi_status(void) return ret; } -#if 1 + /* - *function:this function will be called by display device, enable/disable lcdc - *screen: screen timing to be set to lcdc - *enable: 0 disable lcdc; 1 enable change lcdc timing; 2 just enable dclk - *lcdc_id: the lcdc id the display device attached ,0 or 1 + * function: this function will be called by display device, enable/disable lcdc + * @screen: screen timing to be set to lcdc + * @enable: 0 disable lcdc; 1 enable change lcdc timing; 2 just enable dclk + * @lcdc_id: the lcdc id the display device attached ,0 or 1 */ 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 rk_fb_par *fb_par = NULL; struct rk_lcdc_driver *dev_drv = NULL; - char name[6]; + char name[6] = {0}; int i, win_id, load_screen = 0; - if (screen == NULL) + if (unlikely(!rk_fb) || unlikely(!screen)) return -ENODEV; + hdmi_switch_complete = 0; + /* get lcdc driver */ sprintf(name, "lcdc%d", lcdc_id); - for (i = 0; i < rk_fb->num_lcdc; i++) { - if (!strcmp(rk_fb->lcdc_dev_drv[i]->name, name)) { - dev_drv = rk_fb->lcdc_dev_drv[i]; - break; - } - } - if (i == rk_fb->num_lcdc) { + if (rk_fb->disp_mode != DUAL) + dev_drv = rk_fb->lcdc_dev_drv[0]; + else + dev_drv = rk_get_lcdc_drv(name); + + if (dev_drv == NULL) { printk(KERN_ERR "%s driver not found!", name); return -ENODEV; } - + 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 || + 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->ops->dsp_black) + dev_drv->ops->dsp_black(dev_drv, 1); + if (dev_drv->ops->set_screen_scaler) + dev_drv->ops->set_screen_scaler(dev_drv, dev_drv->screen0, 0); + } + if (dev_drv->uboot_logo && (screen->type != dev_drv->cur_screen->type)) + dev_drv->uboot_logo = 0; if (!enable) { /* if screen type is different, we do not disable lcdc. */ if (dev_drv->cur_screen->type != screen->type) return 0; - for (i = 0; i < dev_drv->lcdc_win_num; i++) { - /* disable the layer which attached to this device */ - if (dev_drv->win[i] && dev_drv->win[i]->state) - dev_drv->ops->open(dev_drv, i, 0); - } - return 0; - } else { - memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen)); - } - for (i = 0; i < dev_drv->lcdc_win_num; i++) { - #ifdef DUAL_LCDC_MAP_TO_SAME_FB - info = rk_fb->fb[i]; - dev_drv1 = (struct rk_lcdc_driver *)info->par; - if (dev_drv1 != dev_drv) { - info->par = dev_drv; - dev_drv->overscan = dev_drv1->overscan; - dev_drv->vsync_info.active = dev_drv1->vsync_info.active; - } - memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen)); - #else - info = rk_fb->fb[dev_drv->fb_index_base + i]; - #endif - win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); - if (dev_drv->win[win_id]) { - #ifdef DUAL_LCDC_MAP_TO_SAME_FB - if (dev_drv1 && dev_drv1->win[win_id]) { - dev_drv->win[win_id]->logicalstate = dev_drv1->win[win_id]->logicalstate; - memcpy(dev_drv->win[win_id]->area, dev_drv1->win[win_id]->area, RK_WIN_MAX_AREA * sizeof(struct rk_lcdc_win_area)); - } - #endif - if (dev_drv->win[win_id]->logicalstate) { - 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); - } - } - } - return 0; -} -#else -/* - * function:this function will be called by hdmi,when - * hdmi plug in/out - * screen: the screen attached to hdmi - * enable: 1,hdmi plug in,0,hdmi plug out - * lcdc_id: the lcdc id the hdmi attached ,0 or 1 - */ -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 rk_lcdc_driver *dev_drv = NULL; - struct fb_var_screeninfo *hdmi_var = NULL; - struct fb_var_screeninfo *pmy_var = NULL; /* var for primary screen */ - int i; - struct fb_fix_screeninfo *hdmi_fix = NULL; - char name[6]; - int ret; - int win_id; -/* - if (rk_fb->disp_mode != DUAL) - rk29_backlight_set(0); -*/ - sprintf(name, "lcdc%d", lcdc_id); - - if (rk_fb->disp_mode != DUAL) { - dev_drv = rk_fb->lcdc_dev_drv[0]; - if (dev_drv->trsm_ops && dev_drv->trsm_ops->disable) - dev_drv->trsm_ops->disable(); - rk_disp_pwr_disable(dev_drv); - } else { - for (i = 0; i < rk_fb->num_lcdc; i++) { - if (rk_fb->lcdc_dev_drv[i]->prop == EXTEND) { - dev_drv = rk_fb->lcdc_dev_drv[i]; - break; - } - } + /* if used one lcdc to dual disp, no need to close win */ + if (rk_fb->disp_mode == ONE_DUAL) { + dev_drv->cur_screen = dev_drv->screen0; + dev_drv->ops->load_screen(dev_drv, 1); - if (i == rk_fb->num_lcdc) { - 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 (rk_fb->num_lcdc == 1) - info = rk_fb->fb[0]; - else if (rk_fb->num_lcdc == 2) - info = rk_fb->fb[dev_drv->lcdc_win_num]; /* the main fb of lcdc1 */ - - if (dev_drv->screen1) { /* device like rk2928 ,have only one lcdc but two outputs */ - if (enable) { - memcpy(dev_drv->screen1, screen, - sizeof(struct rk_screen)); - dev_drv->screen1->lcdc_id = 0; /* connect screen1 to output interface 0 */ - dev_drv->screen1->screen_id = 1; - dev_drv->screen0->lcdc_id = 1; /* connect screen0 to output interface 1 */ - dev_drv->cur_screen = dev_drv->screen1; - dev_drv->screen0->ext_screen = dev_drv->screen1; - if (dev_drv->screen0->sscreen_get) { - dev_drv->screen0->sscreen_get(dev_drv->screen0, - dev_drv->cur_screen->hdmi_resolution); + /* 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); + } else if (rk_fb->num_lcdc > 1) { + /* If there is more than one lcdc device, we disable + the layer which attached to this device */ + dev_drv->suspend_flag = 1; + flush_kthread_worker(&dev_drv->update_regs_worker); + for (i = 0; i < dev_drv->lcdc_win_num; i++) { + if (dev_drv->win[i] && dev_drv->win[i]->state) + dev_drv->ops->open(dev_drv, i, 0); } - - } else { - dev_drv->screen1->lcdc_id = 1; /* connect screen1 to output interface 1 */ - dev_drv->screen0->lcdc_id = 0; /* connect screen0 to output interface 0 */ - dev_drv->cur_screen = dev_drv->screen0; - dev_drv->screen_ctr_info->set_screen_info(dev_drv->cur_screen, - dev_drv->screen_ctr_info->lcd_info); } - } else { - if (enable) - memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen)); - } - dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR; - dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR; - - win_id = dev_drv->ops->fb_get_win_id(dev_drv, info->fix.id); - - if (!enable && !dev_drv->screen1) { /* only double lcdc device need to close */ - if (dev_drv->win[win_id]->state) - dev_drv->ops->open(dev_drv, win_id, enable); /* disable the win which attached to this fb */ hdmi_switch_complete = 0; - return 0; + } else { + if (dev_drv->screen1) + dev_drv->cur_screen = dev_drv->screen1; + memcpy(dev_drv->cur_screen, screen, sizeof(struct rk_screen)); + dev_drv->cur_screen->xsize = dev_drv->cur_screen->mode.xres; + dev_drv->cur_screen->ysize = dev_drv->cur_screen->mode.yres; + dev_drv->cur_screen->x_mirror = dev_drv->rotate_mode & X_MIRROR; + dev_drv->cur_screen->y_mirror = dev_drv->rotate_mode & Y_MIRROR; } - - hdmi_var = &info->var; - hdmi_fix = &info->fix; - if (rk_fb->disp_mode == DUAL) { - if (likely(rk_fb->num_lcdc == 2)) { - pmy_var = &rk_fb->fb[0]->var; - set_xact_yact_for_hdmi(pmy_var, hdmi_var); - hdmi_var->nonstd &= 0xffffff00; - hdmi_var->nonstd |= (pmy_var->nonstd & 0xff); /* use the same format as primary screen */ - } else { - printk(KERN_WARNING - "%s>>only one lcdc,dual display no supported!", - __func__); - } - } - hdmi_var->grayscale &= 0xff; - hdmi_var->grayscale |= - (dev_drv->cur_screen->mode.xres << 8) + (dev_drv->cur_screen->mode.yres << 20); - if (dev_drv->screen1) { /* device like rk2928,whic have one lcdc but two outputs */ - /* - info->var.nonstd &= 0xff; - info->var.nonstd |= (dev_drv->cur_screen->mode.xpos<<8) + (dev_drv->cur_screen->mode.ypos<<20); - info->var.grayscale &= 0xff; - info->var.grayscale |= (dev_drv->cur_screen->mode.x_res<<8) + (dev_drv->cur_screen->mode.y_res<<20); - */ - dev_drv->screen1->xsize = dev_drv->cur_screen->mode.xres; - dev_drv->screen1->ysize = dev_drv->cur_screen->mode.yres; - dev_drv->screen1->xpos = 0; - dev_drv->screen1->ypos = 0; - } - - ret = info->fbops->fb_open(info, 1); - dev_drv->ops->load_screen(dev_drv, 1); - ret = info->fbops->fb_set_par(info); - if (dev_drv->ops->lcdc_hdmi_process) - dev_drv->ops->lcdc_hdmi_process(dev_drv, enable); - - hdmi_switch_complete = enable; - info->fbops->fb_pan_display(hdmi_var, info); - - if (dev_drv->screen1) { - if (dev_drv->screen0->sscreen_set) { - /* - dev_drv->ops->blank(dev_drv, 0, FB_BLANK_NORMAL); - msleep(100); - */ - dev_drv->screen0->sscreen_set(dev_drv->screen0, enable); - /* - dev_drv->ops->blank(dev_drv, 0, FB_BLANK_UNBLANK); - */ + 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 (fb_par->state) { + if (!dev_drv->win[win_id]->state) { + dev_drv->ops->open(dev_drv, win_id, 1); + dev_drv->suspend_flag = 0; + } + if (!load_screen) { + dev_drv->ops->load_screen(dev_drv, 1); + load_screen = 1; + } + info->var.activate |= FB_ACTIVATE_FORCE; + 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; } - - info->fbops->fb_ioctl(info, RK_FBIOSET_CONFIG_DONE, 0); - - if (rk_fb->disp_mode != DUAL) { - /* rk29_backlight_set(1); */ - rk_disp_pwr_enable(dev_drv); - if (dev_drv->trsm_ops && dev_drv->trsm_ops->enable) - dev_drv->trsm_ops->enable(); + hdmi_switch_complete = 1; + 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); + if (dev_drv->ops->dsp_black) + dev_drv->ops->dsp_black(dev_drv, 0); } return 0; } -#endif + /* * function:this function current only called by hdmi for * scale the display @@ -3371,63 +3286,68 @@ 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; u16 xpos, ypos; char name[6]; - int i = 0; + struct rk_screen primary_screen; + rk_fb_get_prmry_screen(&primary_screen); + if (primary_screen.type == SCREEN_HDMI) { + return 0; + } sprintf(name, "lcdc%d", lcdc_id); -#if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) - dev_drv = inf->lcdc_dev_drv[0]; -#else - for (i = 0; i < inf->num_lcdc; i++) { - if (inf->lcdc_dev_drv[i]->prop == EXTEND) { - dev_drv = inf->lcdc_dev_drv[i]; - break; + + if (inf->disp_mode == DUAL) { + dev_drv = rk_get_lcdc_drv(name); + if (dev_drv == NULL) { + printk(KERN_ERR "%s driver not found!", name); + return -ENODEV; } + } else { + dev_drv = inf->lcdc_dev_drv[0]; } - if (i == inf->num_lcdc) { - printk(KERN_ERR "%s driver not found!", name); - return -ENODEV; - } -#endif - 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; screen_y = dev_drv->cur_screen->mode.yres; -#if defined(CONFIG_ONE_LCDC_DUAL_OUTPUT_INF) || defined(CONFIG_NO_DUAL_DISP) - if (dev_drv->cur_screen->screen_id == 1) { + 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 = (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; - } else -#endif - { + } else { xpos = (screen_x - screen_x * scale_x / 100) >> 1; 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 == ONE_DUAL) { + 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; } @@ -3437,10 +3357,12 @@ 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; + int ret = 0; if (dev_drv->iommu_enabled) handle = ion_alloc(rk_fb->ion_client, (size_t) fb_mem_size, 0, @@ -3453,6 +3375,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"); @@ -3462,15 +3386,19 @@ 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) - ion_map_iommu(dev_drv->dev, rk_fb->ion_client, handle, - (unsigned long *)&phy_addr, - (unsigned long *)&len); + 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); else - ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); + ret = ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); #else - ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); + ret = ion_phys(rk_fb->ion_client, handle, &phy_addr, &len); #endif + if (ret < 0) { + dev_err(fbi->dev, "ion map to get phy addr failed\n"); + goto err_share_dma_buf; + } fbi->fix.smem_start = phy_addr; fbi->fix.smem_len = len; printk(KERN_INFO "alloc_buffer:ion_phy_addr=0x%lx\n", phy_addr); @@ -3482,10 +3410,11 @@ err_share_dma_buf: } #endif -static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) +static int rk_fb_alloc_buffer(struct fb_info *fbi) { 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; @@ -3519,48 +3448,20 @@ static int rk_fb_alloc_buffer(struct fb_info *fbi, int fb_id) fbi->screen_base = fb_mem_virt; #endif memset(fbi->screen_base, 0, fbi->fix.smem_len); - printk(KERN_INFO "fb%d:phy:%lx>>vir:%p>>len:0x%x\n", fb_id, - fbi->fix.smem_start, fbi->screen_base, - fbi->fix.smem_len); } else { - if (dev_drv->rotate_mode > X_Y_MIRROR) { - fb_mem_size = get_rotate_fb_size(); -#if defined(CONFIG_ION_ROCKCHIP) - if (rk_fb_alloc_buffer_by_ion(fbi, win, fb_mem_size) < 0) - return -ENOMEM; -#else - fb_mem_virt = - dma_alloc_writecombine(fbi->dev, - fb_mem_size, - &fb_mem_phys, - GFP_KERNEL); - if (!fb_mem_virt) { - pr_err("%s: Failed to allocate framebuffer\n", - __func__); - return -ENOMEM; - } - fbi->fix.smem_len = fb_mem_size; - fbi->fix.smem_start = fb_mem_phys; - fbi->screen_base = fb_mem_virt; -#endif - } else { - fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start; - fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len; - fbi->screen_base = rk_fb->fb[0]->screen_base; - } - - printk(KERN_INFO "fb%d:phy:%lx>>vir:%p>>len:0x%x\n", fb_id, - fbi->fix.smem_start, fbi->screen_base, - fbi->fix.smem_len); + fbi->fix.smem_start = rk_fb->fb[0]->fix.smem_start; + fbi->fix.smem_len = rk_fb->fb[0]->fix.smem_len; + fbi->screen_base = rk_fb->fb[0]->screen_base; } 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; + pr_info("%s:phy:%lx>>vir:%p>>len:0x%x\n", fbi->fix.id, + fbi->fix.smem_start, fbi->screen_base, + fbi->fix.smem_len); return ret; } @@ -3639,14 +3540,15 @@ static int init_lcdc_device_driver(struct rk_fb *rk_fb, screen1->screen_id = 1; screen1->lcdc_id = 1; dev_drv->screen1 = screen1; - dev_drv->screen0->sscreen_set = rk_fb_set_screen_scaler; } sprintf(dev_drv->name, "lcdc%d", dev_drv->id); init_lcdc_win(dev_drv, def_win); 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); + 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; dev_drv->overscan.top = 100; @@ -3657,9 +3559,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; } @@ -3709,12 +3614,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; @@ -3736,7 +3638,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); @@ -3814,35 +3725,134 @@ 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) { + u16 xact, yact; + int format; + u32 dsp_addr; 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()) { + + rk_fb_alloc_buffer(main_fbi); /* only alloc memory for main fb */ + dev_drv->uboot_logo = support_uboot_display(); + + if (dev_drv->uboot_logo && + uboot_logo_offset && uboot_logo_base) { + 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; + + if (dev_drv->ops->get_dspbuf_info) + dev_drv->ops->get_dspbuf_info(dev_drv, &xact, + &yact, &format, &dsp_addr); + 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 %x\n", + 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 (dev_drv->uboot_logo && + (width != xact || height != yact)) { + pr_err("can't support uboot kernel logo use different size [%dx%d] != [%dx%d]\n", + xact, yact, width, height); + return 0; + } + + if (dev_drv->ops->post_dspbuf) { + dev_drv->ops->post_dspbuf(dev_drv, + main_fbi->fix.smem_start, + rk_fb_data_fmt(0, bits), + width, height, width * bits >> 5); + } 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); + rk_fb_poll_wait_frame_complete(); + if (dev_drv->ops->mmu_en) + dev_drv->ops->mmu_en(dev_drv); + freed_index = 0; + } + + return 0; + } else if (dev_drv->uboot_logo && uboot_logo_base) { + phys_addr_t start = uboot_logo_base; + int logo_len, i=0; + unsigned int nr_pages; + struct page **pages; + char *vaddr; + + dev_drv->ops->get_dspbuf_info(dev_drv, &xact, + &yact, &format, + &start); + logo_len = rk_fb_pixel_width(format) * xact * yact >> 3; + if (logo_len > uboot_logo_size || + logo_len > main_fbi->fix.smem_len) { + pr_err("logo size > uboot reserve buffer size\n"); + return -1; + } + + nr_pages = uboot_logo_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 %x\n", + uboot_logo_base); + return -1; + } + + memcpy(main_fbi->screen_base, vaddr, logo_len); + + kfree(pages); + vunmap(vaddr); + + dev_drv->ops->post_dspbuf(dev_drv, + main_fbi->fix.smem_start, + format, xact, yact, + xact * rk_fb_pixel_width(format) >> 5); + if (dev_drv->iommu_enabled) { + rk_fb_poll_wait_frame_complete(); + if (dev_drv->ops->mmu_en) + dev_drv->ops->mmu_en(dev_drv); + freed_index = 0; } 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)) { @@ -3856,13 +3866,11 @@ 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 + rk_fb_alloc_buffer(extend_fbi); } #endif return 0; @@ -3921,6 +3929,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);