mini2440驱动分析之LCD


[日期:2011-10-04]来源:Linux社区  作者:yaozhenguo2006 

四. frambuffer驱动模型fb_ops各函数的实现
  由s3c2410fb_ops结构可以看出,mini2440lcd驱动主要实现了下面几个函数:
s3c2410fb_check_var
s3c2410fb_set_par
s3c2410fb_blank
s3c2410fb_setcolreg
cfb_fillrect
cfb_copyarea
cfb_imageblit
  其中最重要的是s3c2410fb_set_par,这个函数根据fbinfo的值初始化了底层的lcd控制器,重点分析这个函数。他由fb_set_var调用,对应则frambufer核心ioctl中的FBIOPUT_VSCREENINFO命令。其他的函数也是为了完成lcd的相关功能而编写的,与具体实现的功能有关。s3c2410fb_set_par函数定义如下:
  1. static int s3c2410fb_set_par(struct fb_info *info)  
  2. {  
  3.     struct fb_var_screeninfo *var = &info->var;  
  4.   
  5.     switch (var->bits_per_pixel) {  
  6.     case 32:  
  7.     case 16:  
  8.     case 12:  
  9.         info->fix.visual = FB_VISUAL_TRUECOLOR;  
  10.         break;  
  11.     case 1:  
  12.         info->fix.visual = FB_VISUAL_MONO01;  
  13.         break;  
  14.     default:  
  15.         info->fix.visual = FB_VISUAL_PSEUDOCOLOR;  
  16.         break;  
  17.     }  
  18.   
  19.     info->fix.line_length = (var->xres_virtual * var->bits_per_pixel) / 8;  
  20.     /* activate this new configuration */  
  21.     s3c2410fb_activate_var(info);  
  22.     return 0;  
  23. }  
可以看出,这个函数除了根据fbinfo的像素位来赋值fix.visual外,主要是调用了s3c2410fb_activate_var函数:
  1. static void s3c2410fb_activate_var(struct fb_info *info)  
  2. {  
  3.     struct s3c2410fb_info *fbi = info->par;  
  4.     void __iomem *regs = fbi->io;  
  5.     int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;  
  6.     struct fb_var_screeninfo *var = &info->var;  
  7.     int clkdiv;  
  8.   
  9.     clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);  
  10.   
  11.     dprintk("%s: var->xres  = %d\n", __func__, var->xres);  
  12.     dprintk("%s: var->yres  = %d\n", __func__, var->yres);  
  13.     dprintk("%s: var->bpp   = %d\n", __func__, var->bits_per_pixel);  
  14.   
  15.     if (type == S3C2410_LCDCON1_TFT) {  
  16.         //判断lcd型号,我们的lcd是TFT型lcd,所以下面语句执行   
  17.         s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);  
  18.                 //这个函数主要的功能就是将info中的lcd配置相关的值赋值给s3c2410fb_info结构的regs成员   
  19.                 //这个regs是一个s3c2410fb_hw结构,这个结构就是定义了5个lcd控制寄存器lcdcon1~5   
  20.         --clkdiv;  
  21.         if (clkdiv < 0)  
  22.             clkdiv = 0;  
  23.     } else {  
  24.         //如果是STN型的lcd,那么执行下面的函数。因为s3c2440的lcd控制器由有几个专门用于控制STN型lcd的寄存器,所以要单独设置   
  25.         s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);  
  26.         if (clkdiv < 2)  
  27.             clkdiv = 2;  
  28.     }  
  29.   
  30.     fbi->regs.lcdcon1 |=  S3C2410_LCDCON1_CLKVAL(clkdiv);  
  31.     /* write new registers */  
  32.     dprintk("new register set:\n");  
  33.     dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1);  
  34.     dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2);  
  35.     dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3);  
  36.     dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4);  
  37.     dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5);  
  38.   
  39.     writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,  
  40.         regs + S3C2410_LCDCON1);  
  41.     writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);  
  42.     writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);  
  43.     writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);  
  44.     writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);  
  45.         //将配置值写入五个寄存器   
  46.     /* set lcd address pointers */  
  47.     s3c2410fb_set_lcdaddr(info);  
  48.         //设置显存地址寄存器,设置为我们分配的那块内存,设置之后,lcd控制器就会在这块内存取数据送往lcd显示   
  49.   
  50.     fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,  
  51.         //打开视频显示,这样lcd就可以正确显示了   
  52.     writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);  
  53. }  
五. 总结
      mini2440lcd驱动分别涉及到了platform和frambuffer核心,利用这两个核心实现其功能。刚开始分析这个驱动的时候,总是感觉很乱没有重点。我想这个主要是和自己对frambuffer和lcd显示还不熟悉的原因。看了几天过后才逐渐有点眉目。最让人迷惑的就是如何设置lcd控制器的寄存器问题。我以前认为这个应该在probe函数中设置,一般来说这个函数检测设备状态,初始化设备,然后设备就绪,应用程序就可以操作了。但是在s3c2410fb_probe中只是设置了相关的GPIO接口寄存器,根本没有设置lcd控制寄存器。后来发现是在s3c2410fb_set_par函数中设置的。这个函数对应用户空间ioctl的FBIOPUT_VSCREENINFO。也就是说应用程序必须调用ioctl(fd,FBIOPUT_VSCREENINFO,struct fb_var_screeninfo *var)才能设置正确的lcd状态,但是这个命令有一个参数是fb_var_screeninfo结构,也就意味这应用程序必须填充这样一个结构,才可以调用ioctl。这样一来内核初始化的默认配置信息就没用了。唯一的办法是先调用ioctl(fd,FBIOGET_VSCREENINFO,struct fb_var_screeninfo *var)获得这个结构,然后修改之后在调用ioctl(fd,FBIOPUT_VSCREENINFO,struct fb_var_screeninfo *var)将修改的值写入。我在MiniGUI的源码中验证了这个推论,在MiniGUI的fbcon图形引擎中的FB_SetVideoMode函数中,有如下的调用
  1. if ( ioctl(console_fd, FBIOGET_VSCREENINFO, &vinfo) < 0 ) {  
  2.      GAL_SetError("NEWGAL>FBCON: Couldn't get console pixel format\n");  
  3.      FB_VideoQuit(this);  
  4.      return(-1);  
  5. }  
然后就是设置finfo中需要改变的值,最后有下面的代码来设置lcd控制寄存器器
  1. if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {  
  2.       vinfo.yres_virtual = height;  
  3.       if ( ioctl(console_fd, FBIOPUT_VSCREENINFO, &vinfo) < 0 ) {  
  4.            GAL_SetError("NEWGAL>FBCON: Couldn't set console screen info");  
  5.            return(NULL);  
  6.       }  
  7. }  
关于lcd驱动还有好多知识要学,比如mmap操作。mmap是一般lcd应用程序运行的模式,他将显存映射到用户空间,提高系统的性能。因为自己只是为了熟悉一下这个驱动,所以没有深入看下去。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值