S3C2440 Linux驱动移植——LCD
扫描二维码
随时随地手机看文章
PC主机:Ubuntu 10.4 和redhat 9.0
目标板:TQ2440开发板 Linux内核:2.6.30
屏幕型号:WXCAT35-TG3#001F 分辨率: 320X240
本文将介绍如何移植LCD设备。
在移植前,先配置下内核,将LCD设备编译进内核。
移植LCD设置只须修改位于arch/arm/mach-s3c2440/mach-smdk2440.c中的两个结构体的数据。
修改后的内容如下:
/*LCDdriverinfo*/
staticstructs3c2410fb_displaysmdk2440_lcd_cfg__initdata={
.lcdcon5=S3C2410_LCDCON5_FRM565|
S3C2410_LCDCON5_INVVLINE|
S3C2410_LCDCON5_INVVFRAME|
S3C2410_LCDCON5_PWREN|
S3C2410_LCDCON5_HWSWP,
.type=S3C2410_LCDCON1_TFT,
.width=320,//240,
.height=240,//320,
.pixclock=156250,//166667,/*HCLK60MHz,divisor10*/
.xres=320,//240,
.yres=240,//320,
.bpp=16,
.left_margin=20,
.right_margin=38,//8,
.hsync_len=30,//4,
.upper_margin=15,//8,
.lower_margin=12,//7,
.vsync_len=3,//4,
};
上面的参数是如何修改的呢?我们来看下。
type表示显示模式,这里为TFT模式。
width和height表示屏幕的分辨率,我的分辨率是320X240。
xres和yres分别等于width和height。
bpp表示所每个像素点位数,这里使用16位。
left_margin,right_margin,hsync_len,upper_margin,lower_margin,vsync_len这六个参数的值由LCD的手册给出。下图为LCD中的参数:
在这里,我给出上面6个参数和LCD手册中数据的对应关系:
.left_margin = Hsync front porch = 20
.right_margin = Hsync back porch = 38
.hsync_len = Hsync pulse width = 30
.upper_margin = Vsyncbackporch = 15
.lower_margin = Vsync front porch = 12
.vsync_len = Vsync pulse width = 3
pixclock的值是用来计算CLKVAL的。在S3C2440的datasheet中,CLKVAL的计算公式为:
CLKVAL = HCLK / VCLK / 2 -1,而VCLK即为上面图中的Dclk,值为6.4MHz。
/*s3c2410fb_activate_var
*
*activate(set)thecontrollerfromthegivenframebuffer
*information
*/
staticvoids3c2410fb_activate_var(structfb_info*info)
{
structs3c2410fb_info*fbi=info->par;
void__iomem*regs=fbi->io;
inttype=fbi->regs.lcdcon1&S3C2410_LCDCON1_TFT;/*regs.lcdcon1在s3c2410fb_check_var设置*/
structfb_var_screeninfo*var=&info->var;
intclkdiv=s3c2410fb_calc_pixclk(fbi,var->pixclock)/2;
dprintk("%s:var->xres=%dn",__func__,var->xres);
dprintk("%s:var->yres=%dn",__func__,var->yres);
dprintk("%s:var->bpp=%dn",__func__,var->bits_per_pixel);
if(type==S3C2410_LCDCON1_TFT){
s3c2410fb_calculate_tft_lcd_regs(info,&fbi->regs);/*根据var,计算出控制寄存器需要设置的值*/
--clkdiv;
if(clkdiv<0)
clkdiv=0;
}else{
s3c2410fb_calculate_stn_lcd_regs(info,&fbi->regs);
if(clkdiv<2)
clkdiv=2;
}
fbi->regs.lcdcon1|=S3C2410_LCDCON1_CLKVAL(clkdiv);/*设置CLKVAL*/
/*writenewregisters*/
dprintk("newregisterset:n");
dprintk("lcdcon[1]=0x%08lxn",fbi->regs.lcdcon1);
dprintk("lcdcon[2]=0x%08lxn",fbi->regs.lcdcon2);
dprintk("lcdcon[3]=0x%08lxn",fbi->regs.lcdcon3);
dprintk("lcdcon[4]=0x%08lxn",fbi->regs.lcdcon4);
dprintk("lcdcon[5]=0x%08lxn",fbi->regs.lcdcon5);
/*把计算好的值填入LCD控制器中*/
writel(fbi->regs.lcdcon1&~S3C2410_LCDCON1_ENVID,
regs+S3C2410_LCDCON1);/*仍然禁止LCD*/
writel(fbi->regs.lcdcon2,regs+S3C2410_LCDCON2);
writel(fbi->regs.lcdcon3,regs+S3C2410_LCDCON3);
writel(fbi->regs.lcdcon4,regs+S3C2410_LCDCON4);
writel(fbi->regs.lcdcon5,regs+S3C2410_LCDCON5);
/*setlcdaddresspointers*/
s3c2410fb_set_lcdaddr(info);/*设置LCD帧缓冲起始地址*/
fbi->regs.lcdcon1|=S3C2410_LCDCON1_ENVID,
writel(fbi->regs.lcdcon1,regs+S3C2410_LCDCON1);/*使能LCD*/
}
staticunsignedints3c2410fb_calc_pixclk(structs3c2410fb_info*fbi,
unsignedlongpixclk)
{
unsignedlongclk=clk_get_rate(fbi->clk);/*获取当前时钟频率(Hz)*/
unsignedlonglongdiv;
/*pixclkisinpicoseconds,ourclockisinHz
*
*Hz->picosecondsis/10^-12
*/
div = (unsigned long long)clk * pixclk;