rk30fb: support dual display in kernel

This commit is contained in:
yxj
2012-04-17 17:46:25 +08:00
parent 3bf12dd0fa
commit 237ef417c9
3 changed files with 216 additions and 119 deletions

View File

@@ -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)
if(!dev_drv->id) //only sync for lcdc0
{
printk(KERN_ERR "wait for new frame start time out!\n");
return -ETIMEDOUT;
}
else if(timeout < 0)
{
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;
}

View File

@@ -29,6 +29,7 @@
#include <asm/div64.h>
#include <asm/uaccess.h>
#include<linux/rk_fb.h>
#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;

View File

@@ -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