From 481015e980bcf82972c4995b6fa09351365dd8b5 Mon Sep 17 00:00:00 2001 From: yxj Date: Fri, 20 Apr 2012 21:07:19 +0800 Subject: [PATCH] rk30fb: add MACRO CONFIG_DUAL_DISP_IN_KERNEL to enable/disable implement of dual screen display in kernel in dual screen display mode ,hdmi and lcd screen use their own frame buffer the display data of hdmi are copy from lcd screen frame buffer --- drivers/video/rockchip/Kconfig | 6 ++ drivers/video/rockchip/chips/rk30_lcdc.c | 33 +++---- drivers/video/rockchip/rk_fb.c | 117 +++++++++++++++-------- include/linux/rk_fb.h | 16 ++-- 4 files changed, 109 insertions(+), 63 deletions(-) diff --git a/drivers/video/rockchip/Kconfig b/drivers/video/rockchip/Kconfig index bd4490fd3c79..c2cd306b0190 100644 --- a/drivers/video/rockchip/Kconfig +++ b/drivers/video/rockchip/Kconfig @@ -27,5 +27,11 @@ config LCDC1_RK30 help Support rk30 lcdc1 if you say y here +config DUAL_DISP_IN_KERNEL + bool "implement dual display in kernel" + depends on FB_ROCKCHIP + default n + help + select y will implement dual screen display in kernel source "drivers/video/rockchip/hdmi/Kconfig" source "drivers/video/rockchip/rga/Kconfig" diff --git a/drivers/video/rockchip/chips/rk30_lcdc.c b/drivers/video/rockchip/chips/rk30_lcdc.c index c48bf4d1abf3..4ffee340894a 100644 --- a/drivers/video/rockchip/chips/rk30_lcdc.c +++ b/drivers/video/rockchip/chips/rk30_lcdc.c @@ -289,7 +289,7 @@ static int win0_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par u32 uv_addr; y_addr = par->smem_start + par->y_offset; uv_addr = par->cbr_start + par->c_offset; - DBG(2,KERN_INFO "%s:y_addr:0x%x>>uv_addr:0x%x\n",__func__,y_addr,uv_addr); + DBG(2,KERN_INFO "lcdc%d>>%s:y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); LcdWrReg(lcdc_dev, WIN0_YRGB_MST0, y_addr); LcdWrReg(lcdc_dev, WIN0_CBR_MST0, uv_addr); LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); @@ -303,7 +303,7 @@ static int win1_display(struct rk30_lcdc_device *lcdc_dev,struct layer_par *par u32 uv_addr; y_addr = par->smem_start + par->y_offset; uv_addr = par->cbr_start + par->c_offset; - DBG(2,KERN_INFO "%s>>y_addr:0x%x>>uv_addr:0x%x\n",__func__,y_addr,uv_addr); + DBG(2,KERN_INFO "lcdc%d>>%s>>y_addr:0x%x>>uv_addr:0x%x\n",lcdc_dev->id,__func__,y_addr,uv_addr); LcdWrReg(lcdc_dev, WIN1_YRGB_MST, y_addr); LcdWrReg(lcdc_dev, WIN1_CBR_MST, uv_addr); LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); @@ -522,7 +522,7 @@ int rk30_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) par = dev_drv->layer_par[1]; win1_display(lcdc_dev,par); } - if((dev_drv->first_frame) && (dev_drv->id == 0)) //this is the first frame of the system ,enable frame start interrupt + if((dev_drv->first_frame)) //this is the first frame of the system ,enable frame start interrupt { dev_drv->first_frame = 0; LcdMskReg(lcdc_dev,INT_STATUS,m_FRM_START_INT_CLEAR |m_FRM_START_INT_EN , @@ -531,22 +531,20 @@ int rk30_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) } - if(!dev_drv->id) //only sync for lcdc0 + spin_lock_irqsave(&dev_drv->cpl_lock,flags); + init_completion(&dev_drv->frame_done); + spin_unlock_irqrestore(&dev_drv->cpl_lock,flags); + timeout = wait_for_completion_interruptible_timeout(&dev_drv->frame_done,msecs_to_jiffies(25)); + if(!timeout) { - spin_lock_irqsave(&dev_drv->cpl_lock,flags); - init_completion(&dev_drv->frame_done); - spin_unlock_irqrestore(&dev_drv->cpl_lock,flags); - timeout = wait_for_completion_interruptible_timeout(&dev_drv->frame_done,msecs_to_jiffies(25)); - if(!timeout) - { - printk(KERN_ERR "wait for new frame start time out!\n"); - return -ETIMEDOUT; - } - else if(timeout < 0) - { - return timeout; - } + printk(KERN_ERR "wait for new frame start time out!\n"); + return -ETIMEDOUT; + } + else if(timeout < 0) + { + return timeout; } + return 0; } @@ -609,7 +607,6 @@ int rk30_lcdc_early_resume(struct rk_lcdc_device_driver *dev_drv) LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); return 0; } - static irqreturn_t rk30_lcdc_isr(int irq, void *dev_id) { struct rk30_lcdc_device *lcdc_dev = (struct rk30_lcdc_device *)dev_id; diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 1b290e9cf216..ccbdcc17745e 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "hdmi/rk_hdmi.h" @@ -40,7 +41,7 @@ #if 1 #define CHK_SUSPEND(drv) \ - if(atomic_dec_and_test(&drv->in_suspend)) { \ + if(atomic_read(&drv->in_suspend)) { \ printk(">>>>>> fb is in suspend! return! \n"); \ return -EPERM; \ } @@ -141,6 +142,34 @@ static int rk_fb_close(struct fb_info *info,int user) return 0; } +static void fb_copy_by_ipp(struct fb_info *dst_info, struct fb_info *src_info,int offset) +{ + struct rk29_ipp_req ipp_req; + u32 dstoffset = 0; + memset(&ipp_req, 0, sizeof(struct rk29_ipp_req)); + ipp_req.src0.YrgbMst = src_info->fix.smem_start + offset; + ipp_req.src0.w = src_info->var.xres; + ipp_req.src0.h = src_info->var.yres; + + ipp_req.dst0.YrgbMst = dst_info->fix.smem_start + offset; + ipp_req.dst0.w = src_info->var.xres; + ipp_req.dst0.h = src_info->var.yres; + + ipp_req.src_vir_w = src_info->var.xres_virtual; + ipp_req.dst_vir_w = src_info->var.xres_virtual; + ipp_req.timeout = 100; + ipp_req.flag = IPP_ROT_0; + ipp_blit_sync(&ipp_req); + +} +static void hdmi_post_work(struct work_struct *work) +{ + + struct rk_fb_inf *inf = container_of(to_delayed_work(work), struct rk_fb_inf, delay_work); + struct rk_lcdc_device_driver * dev_drv = inf->lcdc_dev_drv[1]; + dev_drv->pan_display(dev_drv,1); + +} static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { @@ -156,18 +185,8 @@ static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) u32 yoffset = var->yoffset; u32 xvir = var->xres_virtual; u8 data_format = var->nonstd&0xff; - layer_id = get_fb_layer_id(fix); - #if defined(CONFIG_HDMI_RK30) - if(hdmi_get_hotplug()) - { - if(inf->num_fb >= 2) - { - info2 = inf->fb[2]; - dev_drv1 = (struct rk_lcdc_device_driver * )info2->par; - } - } - #endif CHK_SUSPEND(dev_drv); + layer_id = get_fb_layer_id(fix); if(layer_id < 0) { return -ENODEV; @@ -175,10 +194,6 @@ static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) else { par = dev_drv->layer_par[layer_id]; - if(dev_drv1) - { - par2 = dev_drv1->layer_par[layer_id]; - } } switch (par->format) { @@ -209,11 +224,23 @@ static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) } #if defined(CONFIG_HDMI_RK30) - if(hdmi_get_hotplug()) - { - par2->y_offset = par->y_offset; - dev_drv1->pan_display(dev_drv1,layer_id); - } + #if defined(CONFIG_DUAL_DISP_IN_KERNEL) + if(hdmi_get_hotplug()) + { + if(inf->num_fb >= 2) + { + info2 = inf->fb[2]; + dev_drv1 = (struct rk_lcdc_device_driver * )info2->par; + par2 = dev_drv1->layer_par[layer_id]; + par2->y_offset = par->y_offset; + //memcpy(info2->screen_base+par2->y_offset,info->screen_base+par->y_offset, + // var->xres*var->yres*var->bits_per_pixel>>3); + fb_copy_by_ipp(info2,info,par->y_offset); + dev_drv1->pan_display(dev_drv1,layer_id); + //queue_delayed_work(inf->workqueue, &inf->delay_work,0); + } + } + #endif #endif dev_drv->pan_display(dev_drv,layer_id); return 0; @@ -284,8 +311,7 @@ static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) { struct rk_lcdc_device_driver *dev_drv = (struct rk_lcdc_device_driver * )info->par; CHK_SUSPEND(dev_drv); - - if( 0==var->xres_virtual || 0==var->yres_virtual || + if( 0==var->xres_virtual || 0==var->yres_virtual || 0==var->xres || 0==var->yres || var->xres<16 || ((16!=var->bits_per_pixel)&&(32!=var->bits_per_pixel)) ) { @@ -384,14 +410,16 @@ static int rk_fb_set_par(struct fb_info *info) var->pixclock = dev_drv->pixclock; CHK_SUSPEND(dev_drv); #if defined(CONFIG_HDMI_RK30) - if(hdmi_get_hotplug()) - { - if(inf->num_fb >= 2) + #if defined(CONFIG_DUAL_DISP_IN_KERNEL) + if(hdmi_get_hotplug()) { - info2 = inf->fb[2]; - dev_drv1 = (struct rk_lcdc_device_driver * )info2->par; + if(inf->num_fb >= 2) + { + info2 = inf->fb[2]; + dev_drv1 = (struct rk_lcdc_device_driver * )info2->par; + } } - } + #endif #endif layer_id = get_fb_layer_id(fix); if(layer_id < 0) @@ -492,13 +520,15 @@ static int rk_fb_set_par(struct fb_info *info) par->yvir = var->yres_virtual; #if defined(CONFIG_HDMI_RK30) - if(hdmi_get_hotplug()) - { - par2->xact = par->xact; - par2->yact = par->yact; - par2->format = par->format; - dev_drv1->set_par(dev_drv1,layer_id); - } + #if defined(CONFIG_DUAL_DISP_IN_KERNEL) + if(hdmi_get_hotplug()) + { + par2->xact = par->xact; + par2->yact = par->yact; + par2->format = par->format; + dev_drv1->set_par(dev_drv1,layer_id); + } + #endif #endif dev_drv->set_par(dev_drv,layer_id); @@ -604,6 +634,7 @@ void rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id) { struct rk_fb_inf *inf = platform_get_drvdata(g_fb_pdev); struct fb_info *info = NULL; + struct fb_info *pmy_info = NULL; struct rk_lcdc_device_driver * dev_drv = NULL; struct fb_var_screeninfo *pmy_var = NULL; //var for primary screen struct fb_var_screeninfo *hdmi_var = NULL; @@ -625,12 +656,15 @@ void rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id) hdmi_var->xres = pmy_var->xres; hdmi_var->yres = pmy_var->yres; hdmi_var->nonstd = pmy_var->nonstd; - hdmi_fix->smem_start = pmy_fix->smem_start; + //hdmi_fix->smem_start = pmy_fix->smem_start; dev_drv = (struct rk_lcdc_device_driver * )info->par; ret = dev_drv->load_screen(dev_drv,1); ret = info->fbops->fb_open(info,1); ret = info->fbops->fb_set_par(info); - + #if defined(CONFIG_DUAL_DISP_IN_KERNEL) + pmy_info = inf->fb[0]; + pmy_info->fbops->fb_pan_display(pmy_var,pmy_info); + #endif } static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id) @@ -969,6 +1003,13 @@ static int __devinit rk_fb_probe (struct platform_device *pdev) fb_inf->mach_info = mach_info; if(mach_info->io_init) mach_info->io_init(NULL); +#if defined(CONFIG_HDMI_RK30) + #if defined(CONFIG_DUAL_DISP_IN_KERNEL) + fb_inf->workqueue = create_singlethread_workqueue("hdmi_post"); + INIT_DELAYED_WORK(&(fb_inf->delay_work), hdmi_post_work); + #endif +#endif + #ifdef CONFIG_HAS_EARLYSUSPEND suspend_info.inf = fb_inf; register_early_suspend(&suspend_info.early_suspend); diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index 0c344c35bdc9..72d6c2a261bf 100644 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -215,14 +215,16 @@ struct rk_lcdc_device_driver{ }; struct rk_fb_inf { - struct rk29fb_info * mach_info; //lcd io control info - struct fb_info *fb[RK_MAX_FB_SUPPORT]; - int num_fb; - - struct rk_lcdc_device_driver *lcdc_dev_drv[RK30_MAX_LCDC_SUPPORT]; - int num_lcdc; + struct rk29fb_info * mach_info; //lcd io control info + struct fb_info *fb[RK_MAX_FB_SUPPORT]; + int num_fb; + + struct rk_lcdc_device_driver *lcdc_dev_drv[RK30_MAX_LCDC_SUPPORT]; + int num_lcdc; - int video_mode; //when play video set it to 1 + int video_mode; //when play video set it to 1 + struct workqueue_struct *workqueue; + struct delayed_work delay_work; }; extern int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, struct rk_lcdc_device_driver *def_drv,int id); -- 2.34.1