From 237ef417c9ff2fe9e22d4c442494db791fe2c3d7 Mon Sep 17 00:00:00 2001 From: yxj Date: Tue, 17 Apr 2012 17:46:25 +0800 Subject: [PATCH] rk30fb: support dual display in kernel --- drivers/video/rockchip/chips/rk30_lcdc.c | 37 +-- drivers/video/rockchip/rk_fb.c | 297 +++++++++++++++-------- include/linux/rk_fb.h | 1 + 3 files changed, 216 insertions(+), 119 deletions(-) diff --git a/drivers/video/rockchip/chips/rk30_lcdc.c b/drivers/video/rockchip/chips/rk30_lcdc.c index d89c1f4a0e6d..080a9da510ab 100644 --- a/drivers/video/rockchip/chips/rk30_lcdc.c +++ b/drivers/video/rockchip/chips/rk30_lcdc.c @@ -347,8 +347,8 @@ static int win0_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, break; } - DBG("%s>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>ypos:%d>>\n", - __func__,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,ypos); + DBG("%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,ypos); spin_lock(&lcdc_dev->reg_lock); LcdMskReg(lcdc_dev, SYS_CTRL1, m_W0_FORMAT, v_W0_FORMAT(par->format)); //(inf->video_mode==0) LcdWrReg(lcdc_dev, WIN0_ACT_INFO,v_ACT_WIDTH(xact) | v_ACT_HEIGHT(yact)); @@ -403,8 +403,8 @@ static int win1_set_par(struct rk30_lcdc_device *lcdc_dev,rk_screen *screen, ScaleYrgbX = CalScale(xact, par->xsize); ScaleYrgbY = CalScale(yact, par->ysize); - DBG("%s>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>ypos:%d>>\n", - __func__,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,ypos); + DBG("%s for lcdc%d>>format:%d>>>xact:%d>>yact:%d>>xsize:%d>>ysize:%d>>xvir:%d>>yvir:%d>>ypos:%d>>\n", + __func__,lcdc_dev->id,par->format,xact,yact,par->xsize,par->ysize,xvir,yvir,ypos); spin_lock(&lcdc_dev->reg_lock); @@ -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) //this is the first frame of the system ,enable frame start interrupt + if((dev_drv->first_frame) && (dev_drv->id == 0)) //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 , @@ -530,19 +530,22 @@ int rk30_lcdc_pan_display(struct rk_lcdc_device_driver * dev_drv,int layer_id) LcdWrReg(lcdc_dev, REG_CFG_DONE, 0x01); // write any value to REG_CFG_DONE let config become effective } - - 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) + + if(!dev_drv->id) //only sync for lcdc0 { - return 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; + } } return 0; } diff --git a/drivers/video/rockchip/rk_fb.c b/drivers/video/rockchip/rk_fb.c index 145ddfc84524..ad6470203fbb 100644 --- a/drivers/video/rockchip/rk_fb.c +++ b/drivers/video/rockchip/rk_fb.c @@ -29,6 +29,7 @@ #include #include #include +#include "hdmi/rk_hdmi.h" #if 0 @@ -143,15 +144,29 @@ static int rk_fb_close(struct fb_info *info,int user) static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) { + struct rk_fb_inf *inf = dev_get_drvdata(info->device); struct fb_fix_screeninfo *fix = &info->fix; struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par; + struct fb_info * info2 = NULL; + struct rk_lcdc_device_driver * dev_drv1 = NULL; struct layer_par *par = NULL; + struct layer_par *par2 = NULL; int layer_id = 0; u32 xoffset = var->xoffset; // offset from virtual to visible 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); if(layer_id < 0) { @@ -160,6 +175,10 @@ 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) { @@ -188,9 +207,15 @@ static int rk_pan_display(struct fb_var_screeninfo *var, struct fb_info *info) printk("un supported format:0x%x\n",data_format); return -EINVAL; } - + + #if defined(CONFIG_HDMI_RK30) + if(hdmi_get_hotplug()) + { + par2->y_offset = par->y_offset; + dev_drv1->pan_display(dev_drv1,layer_id); + } + #endif dev_drv->pan_display(dev_drv,layer_id); - return 0; } static int rk_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg) @@ -337,88 +362,106 @@ static int rk_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 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_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par; - struct layer_par *par = NULL; - rk_screen *screen =dev_drv->screen; - int layer_id = 0; - u32 cblen = 0,crlen = 0; - u16 xsize =0,ysize = 0; //winx display window height/width --->LCDC_WINx_DSP_INFO - u32 xoffset = var->xoffset; // offset from virtual to visible - u32 yoffset = var->yoffset; //resolution - u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel - u16 ypos = (var->nonstd>>20) & 0xfff; - u32 xvir = var->xres_virtual; - u32 yvir = var->yres_virtual; - u8 data_format = var->nonstd&0xff; - var->pixclock = dev_drv->pixclock; - CHK_SUSPEND(dev_drv); - layer_id = get_fb_layer_id(fix); - if(layer_id < 0) - { - return -ENODEV; - } - else - { - par = dev_drv->layer_par[layer_id]; - } - if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2"))) //four ui - { - xsize = screen->x_res; - ysize = screen->y_res; - } - else if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3"))) - { - xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel ,for vide0 - ysize = (var->grayscale>>20) & 0xfff; - } - + struct rk_fb_inf *inf = dev_get_drvdata(info->device); + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct rk_lcdc_device_driver * dev_drv = (struct rk_lcdc_device_driver * )info->par; + struct layer_par *par = NULL; + rk_screen *screen =dev_drv->screen; + struct fb_info * info2 = NULL; + struct rk_lcdc_device_driver * dev_drv1 = NULL; + struct layer_par *par2 = NULL; + int layer_id = 0; + u32 cblen = 0,crlen = 0; + u16 xsize =0,ysize = 0; //winx display window height/width --->LCDC_WINx_DSP_INFO + u32 xoffset = var->xoffset; // offset from virtual to visible + u32 yoffset = var->yoffset; //resolution + u16 xpos = (var->nonstd>>8) & 0xfff; //visiable pos in panel + u16 ypos = (var->nonstd>>20) & 0xfff; + u32 xvir = var->xres_virtual; + u32 yvir = var->yres_virtual; + u8 data_format = var->nonstd&0xff; + var->pixclock = dev_drv->pixclock; + CHK_SUSPEND(dev_drv); + #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 + layer_id = get_fb_layer_id(fix); + if(layer_id < 0) + { + return -ENODEV; + } + else + { + par = dev_drv->layer_par[layer_id]; + if(dev_drv1) + { + par2 = dev_drv1->layer_par[layer_id]; + } + } + if((!strcmp(fix->id,"fb0"))||(!strcmp(fix->id,"fb2"))) //four ui + { + xsize = screen->x_res; + ysize = screen->y_res; + } + else if((!strcmp(fix->id,"fb1"))||(!strcmp(fix->id,"fb3"))) + { + xsize = (var->grayscale>>8) & 0xfff; //visiable size in panel ,for vide0 + ysize = (var->grayscale>>20) & 0xfff; + } + /* calculate y_offset,c_offset,line_length,cblen and crlen */ #if 1 - switch (data_format) - { - case HAL_PIXEL_FORMAT_RGBA_8888 : // rgb - case HAL_PIXEL_FORMAT_RGBX_8888: - par->format = ARGB888; - fix->line_length = 4 * xvir; - par->y_offset = (yoffset*xvir + xoffset)*4; - break; - case HAL_PIXEL_FORMAT_RGB_888 : - par->format = RGB888; - fix->line_length = 3 * xvir; - par->y_offset = (yoffset*xvir + xoffset)*3; - break; - case HAL_PIXEL_FORMAT_RGB_565: //RGB565 - par->format = RGB565; - fix->line_length = 2 * xvir; - par->y_offset = (yoffset*xvir + xoffset)*2; - break; - case HAL_PIXEL_FORMAT_YCbCr_422_SP : // yuv422 - par->format = YUV422; - fix->line_length = xvir; - cblen = crlen = (xvir*yvir)>>1; - par->y_offset = yoffset*xvir + xoffset; - par->c_offset = par->y_offset; - break; - case HAL_PIXEL_FORMAT_YCrCb_NV12 : // YUV420---uvuvuv - par->format = YUV420; - fix->line_length = xvir; - cblen = crlen = (xvir*yvir)>>2; - par->y_offset = yoffset*xvir + xoffset; - par->c_offset = (yoffset>>1)*xvir + xoffset; - break; - case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444 - par->format = 5; - fix->line_length = xvir<<2; - par->y_offset = yoffset*xvir + xoffset; - par->c_offset = yoffset*2*xvir +(xoffset<<1); - cblen = crlen = (xvir*yvir); - break; - default: - printk("un supported format:0x%x\n",data_format); - return -EINVAL; - } + switch (data_format) + { + case HAL_PIXEL_FORMAT_RGBA_8888 : // rgb + case HAL_PIXEL_FORMAT_RGBX_8888: + par->format = ARGB888; + fix->line_length = 4 * xvir; + par->y_offset = (yoffset*xvir + xoffset)*4; + break; + case HAL_PIXEL_FORMAT_RGB_888 : + par->format = RGB888; + fix->line_length = 3 * xvir; + par->y_offset = (yoffset*xvir + xoffset)*3; + break; + case HAL_PIXEL_FORMAT_RGB_565: //RGB565 + par->format = RGB565; + fix->line_length = 2 * xvir; + par->y_offset = (yoffset*xvir + xoffset)*2; + break; + case HAL_PIXEL_FORMAT_YCbCr_422_SP : // yuv422 + par->format = YUV422; + fix->line_length = xvir; + cblen = crlen = (xvir*yvir)>>1; + par->y_offset = yoffset*xvir + xoffset; + par->c_offset = par->y_offset; + break; + case HAL_PIXEL_FORMAT_YCrCb_NV12 : // YUV420---uvuvuv + par->format = YUV420; + fix->line_length = xvir; + cblen = crlen = (xvir*yvir)>>2; + par->y_offset = yoffset*xvir + xoffset; + par->c_offset = (yoffset>>1)*xvir + xoffset; + break; + case HAL_PIXEL_FORMAT_YCrCb_444 : // yuv444 + par->format = 5; + fix->line_length = xvir<<2; + par->y_offset = yoffset*xvir + xoffset; + par->c_offset = yoffset*2*xvir +(xoffset<<1); + cblen = crlen = (xvir*yvir); + break; + default: + printk("un supported format:0x%x\n",data_format); + return -EINVAL; + } #else switch(var->bits_per_pixel) { @@ -431,23 +474,34 @@ static int rk_fb_set_par(struct fb_info *info) par->format = RGB565; fix->line_length = 2 * xvir; par->y_offset = (yoffset*xvir + xoffset)*2; - break; + break; } #endif - par->xpos = xpos; - par->ypos = ypos; - par->xsize = xsize; - par->ysize = ysize; - - par->smem_start =fix->smem_start; - par->cbr_start = fix->mmio_start; - par->xact = var->xres; //winx active window height,is a part of vir - par->yact = var->yres; - par->xvir = var->xres_virtual; // virtual resolution stride --->LCDC_WINx_VIR - par->yvir = var->yres_virtual; - dev_drv->set_par(dev_drv,layer_id); + par->xpos = xpos; + par->ypos = ypos; + par->xsize = xsize; + par->ysize = ysize; + + par->smem_start =fix->smem_start; + par->cbr_start = fix->mmio_start; + par->xact = var->xres; //winx active window height,is a part of vir + par->yact = var->yres; + par->xvir = var->xres_virtual; // virtual resolution stride --->LCDC_WINx_VIR + 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); + } + #endif + dev_drv->set_par(dev_drv,layer_id); + return 0; } @@ -545,6 +599,40 @@ void rk_direct_fb_show(struct fb_info * fbi) } EXPORT_SYMBOL(rk_direct_fb_show); + +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 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; + struct fb_fix_screeninfo *pmy_fix = NULL; + struct fb_fix_screeninfo *hdmi_fix = NULL; + int ret; + if(lcdc_id == 0) + { + info = inf->fb[0]; + } + else + { + info = inf->fb[2] ; + } + pmy_var = &inf->fb[0]->var; + pmy_fix = &inf->fb[0]->fix; + hdmi_var = &info->var; + hdmi_fix = &info->fix; + 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; + 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); + + +} static int rk_request_fb_buffer(struct fb_info *fbi,int fb_id) { struct resource *res; @@ -655,6 +743,7 @@ static int init_lcdc_device_driver(struct rk_lcdc_device_driver *dev_drv, return -EINVAL; } sprintf(dev_drv->name, "lcdc%d",id); + dev_drv->id = id; dev_drv->open = def_drv->open; dev_drv->init_lcdc = def_drv->init_lcdc; dev_drv->ioctl = def_drv->ioctl; @@ -753,13 +842,17 @@ int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, fb_inf->num_fb++; } #if !defined(CONFIG_FRAMEBUFFER_CONSOLE) && defined(CONFIG_LOGO) - fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_open(fb_inf->fb[fb_inf->num_fb-2],1); - fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]); - if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) { - /* Start display and show logo on boot */ - fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]); - fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR); - fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]); + + if(id == 0) + { + fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_open(fb_inf->fb[fb_inf->num_fb-2],1); + fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_set_par(fb_inf->fb[fb_inf->num_fb-2]); + if(fb_prepare_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR)) { + /* Start display and show logo on boot */ + fb_set_cmap(&fb_inf->fb[fb_inf->num_fb-2]->cmap, fb_inf->fb[fb_inf->num_fb-2]); + fb_show_logo(fb_inf->fb[fb_inf->num_fb-2], FB_ROTATE_UR); + fb_inf->fb[fb_inf->num_fb-2]->fbops->fb_pan_display(&(fb_inf->fb[fb_inf->num_fb-2]->var), fb_inf->fb[fb_inf->num_fb-2]); + } } #endif return 0; diff --git a/include/linux/rk_fb.h b/include/linux/rk_fb.h index c68ae6dab0d3..0c344c35bdc9 100644 --- a/include/linux/rk_fb.h +++ b/include/linux/rk_fb.h @@ -229,5 +229,6 @@ extern int rk_fb_register(struct rk_lcdc_device_driver *dev_drv, extern int rk_fb_unregister(struct rk_lcdc_device_driver *dev_drv); extern int get_fb_layer_id(struct fb_fix_screeninfo *fix); extern struct rk_lcdc_device_driver * rk_get_lcdc_drv(char *name); +extern void rk_fb_switch_screen(rk_screen *screen ,int enable ,int lcdc_id); extern int rkfb_create_sysfs(struct fb_info *fbi); #endif -- 2.34.1