rk30fb: add MACRO CONFIG_DUAL_DISP_IN_KERNEL to enable/disable implement of dual...
authoryxj <yxj@rock-chips.com>
Fri, 20 Apr 2012 13:07:19 +0000 (21:07 +0800)
committeryxj <yxj@rock-chips.com>
Fri, 20 Apr 2012 13:13:53 +0000 (21:13 +0800)
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
drivers/video/rockchip/chips/rk30_lcdc.c
drivers/video/rockchip/rk_fb.c
include/linux/rk_fb.h

index bd4490fd3c79ad3d9975570ad79d71dca6d6c0b7..c2cd306b0190bf9d509c806e486d310150f99c0e 100644 (file)
@@ -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"
index c48bf4d1abf32f288856cecfc03c55487b6bb8d4..4ffee340894af1d8a01fcf21a8c8592ee915850a 100644 (file)
@@ -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;
index 1b290e9cf216f2f5f4ef9b37bbd9fb906042a417..ccbdcc17745e39079c1316fcfc64fb987a23c94a 100644 (file)
@@ -29,6 +29,7 @@
 #include <asm/div64.h>
 #include <asm/uaccess.h>
 #include<linux/rk_fb.h>
+#include <plat/ipp.h>
 #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);
index 0c344c35bdc95c4f7499beadbae49a158f13be15..72d6c2a261bfa16eece1e209e44ba17afbdc155e 100644 (file)
@@ -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);