浅谈ARM9的LCD驱动(一)

2014-11-24 12:14:46 · 作者: · 浏览: 3

一.硬件基础

1.硬件框图

\

2.LCD控制浓ky"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vc8YnI+CjwvcD4KPHA+ICAgIMHLveLTsrz+1+7Wsb3TtcSw7Leovs3Kx7+0ytay4aOs1NrV4sDvztLWu7vhvPK1pb3pydzPwkxDRLXE07K8/qGjvt/M5bXEztK74dTaz8LD5r3hus+zzNDyvbK94qGjPC9wPgo8cD48aW1nIHNyYz0="https://www.cppentry.com/upload_files/article/49/1_x7s8o__.jpg" alt="\">

a.REGBANK是LCD控制器的寄存器,含17个寄存器以及一块256*16的调色内存,用来设置各项参数。

b.LCDCDMA是LCD控制器专用的DMA信道。

c.TIMEGEN和LPC3600负责产生LCD屏所需要的控制时序。

d.VIDPRCS需要与LCDCDMA中的数组合成特定的格式,然后从VD[23:0]发送给LCD屏幕。

3.时序理解

\

\

二.驱动框架

\

我们从上面这幅图看,帧缓冲设备在Linux中也可以看做是一个完整的子系统,大体由fbmem.c和xxxfb.c组成。向上给应用程序提供完善的设备文件操作接口(即对FrameBuffer设备进行read、write、ioctl等操作),接口在Linux提供的fbmem.c文件中实现;向下提供了硬件操作的接口,只是这些接口Linux并没有提供实现,因为这要根据具体的LCD控制器硬件进行设置,所以这就是我们要做的事情了(即xxxfb.c部分的实现)。


三.改写驱动

1.程序代码

#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         #include 
        
          #include 
         
           #include 
          
            #include 
           
             #include 
            
              #include 
             
               #include 
              
                #include 
               
                 #include 
                
                  #include 
                 
                   #include 
                  
                    #include 
                   
                     #include 
                    
                      #include 
                     
                       #include 
                      
                        #include 
                       
                         static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info); struct lcd_regs { unsigned long lcdcon1; unsigned long lcdcon2; unsigned long lcdcon3; unsigned long lcdcon4; unsigned long lcdcon5; unsigned long lcdsaddr1; unsigned long lcdsaddr2; unsigned long lcdsaddr3; unsigned long redlut; unsigned long greenlut; unsigned long bluelut; unsigned long reserved[9]; unsigned long dithmode; unsigned long tpal; unsigned long lcdintpnd; unsigned long lcdsrcpnd; unsigned long lcdintmsk; unsigned long lpcsel; }; static struct fb_ops s3c_lcdfb_ops = { .owner = THIS_MODULE, .fb_setcolreg = s3c_lcdfb_setcolreg, .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, }; static struct fb_info *s3c_lcd; static volatile unsigned long *gpbcon; static volatile unsigned long *gpbdat; static volatile unsigned long *gpccon; static volatile unsigned long *gpdcon; static volatile unsigned long *gpgcon; static volatile struct lcd_regs* lcd_regs; static u32 pseudo_palette[16]; /* from pxafb.c */ static inline unsigned int chan_to_field(unsigned int chan, struct fb_bitfield *bf) { chan &= 0xffff; //清零高16位 chan >>= 16 - bf->length; //保留高8位置 return chan << bf->offset; //左移起始地址(得到的值就是颜色了) } static int s3c_lcdfb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info) { unsigned int val; if (regno > 16) return 1; /* 用red,green,blue三原色构造出val */ val = chan_to_field(red, &info->var.red); val |= chan_to_field(green, &info->var.green); val |= chan_to_field(blue, &info->var.blue); //((u32 *)(info->pseudo_palette))[regno] = val; pseudo_palette[regno] = val; return 0; } /*入口函数*/ static int lcd_init(void) { /* 1. 分配一个fb_info */ s3c_lcd = framebuffer_alloc(0, NULL); /* 2. 设置 */ /* 2.1 设置固定的参数 */ strcpy(s3c_lcd->fix.id, "mylcd"); s3c_lcd->fix.smem_len = 320*240*32/8; /* MINI2440的LCD位宽是24,但是2440里会分配4字节即32位(浪费1字节) */ s3c_lcd->fix.type = FB_TYPE_PACKED_PIXELS; s3c_lcd->fix.visual = FB_VISUAL_TRUECOLOR; /* TFT */ s3c_lcd->fix.line_length = 240*4; /*一行240没个占4个字节*/ /* 2.2 设置可变的参数 */ s3c_lcd->var.xres = 240; s3c_lcd->var.yres = 320; s3c_lcd->var.xres_virtual = 240; s3c_lcd->var.yres_virtual = 320; s3c_lcd->var.bits_per_