S3C2440 Linux驅(qū)動(dòng)移植——LCD
掃描二維碼
隨時(shí)隨地手機(jī)看文章
PC主機(jī):Ubuntu 10.4 和redhat 9.0
目標(biāo)板:TQ2440開發(fā)板 Linux內(nèi)核:2.6.30
屏幕型號(hào):WXCAT35-TG3#001F 分辨率: 320X240
本文將介紹如何移植LCD設(shè)備。
在移植前,先配置下內(nèi)核,將LCD設(shè)備編譯進(jìn)內(nèi)核。
移植LCD設(shè)置只須修改位于arch/arm/mach-s3c2440/mach-smdk2440.c中的兩個(gè)結(jié)構(gòu)體的數(shù)據(jù)。
修改后的內(nèi)容如下:
/*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,
};
上面的參數(shù)是如何修改的呢?我們來看下。
type表示顯示模式,這里為TFT模式。
width和height表示屏幕的分辨率,我的分辨率是320X240。
xres和yres分別等于width和height。
bpp表示所每個(gè)像素點(diǎn)位數(shù),這里使用16位。
left_margin,right_margin,hsync_len,upper_margin,lower_margin,vsync_len這六個(gè)參數(shù)的值由LCD的手冊(cè)給出。下圖為LCD中的參數(shù):
在這里,我給出上面6個(gè)參數(shù)和LCD手冊(cè)中數(shù)據(jù)的對(duì)應(yīng)關(guān)系:
.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的值是用來計(jì)算CLKVAL的。在S3C2440的datasheet中,CLKVAL的計(jì)算公式為:
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設(shè)置*/
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);/*根據(jù)var,計(jì)算出控制寄存器需要設(shè)置的值*/
--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);/*設(shè)置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);
/*把計(jì)算好的值填入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);/*設(shè)置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);/*獲取當(dāng)前時(shí)鐘頻率(Hz)*/
unsignedlonglongdiv;
/*pixclkisinpicoseconds,ourclockisinHz
*
*Hz->picosecondsis/10^-12
*/
div = (unsigned long long)clk * pixclk;