mini2440驱动分析之LCD


mini2440集成了lcd控制器的接口,板子上接的lcd硬件是统宝240*320,TFT型lcd。lcd驱动对应的文件为s3c2410fb.c。要读懂这个驱动必须了解linux platform子系统的知识。因为这个驱动是以platform驱动的形式注册到内核。而且还需要frambuffer驱动的知识,因为这个驱动还是frambuffer接口的。lcd驱动在模块初始化的时候,调用platform注册函数将自己注册到内核,利用linux设备模型核心的机制调用platform_bus总线的match函数找到相应的设备,然后由linux设备模型核心调用s3c2410fb.c中的s3c2410fb_probe ,进行硬件相关初始化,并初始化frambuffer结构。然后注册到frambuffer核心。lcd的功能实现通过frambuffer核心来完成。s3c2410fb.c的功能实现都是配合frambuffer核心的。下面详细分析lcd驱动的实现。
程序基本结构
 1.模块初始化-->向platform核心注册自己
 2.实现linux设备模型必须的probe函数-->向frambuffer核心注册自己(最重要)
                       resume函数-->系统在由挂起恢复的时候调用
                       suspand-->系统在挂起的时候调用 
                       remove--> 驱动程序注销自己的时候调用                  
 3.frambuffer驱动模型fb_ops各函数的实现-->实现fb驱动的ioctl命令需要的函数

 4.其他函数-->由2.3.中的函数调用,帮助其实现功能。

一. 相关数据结构
  1. struct fb_info 结构
 
  1. struct fb_info {  
  2.     int node;  
  3.     int flags;  
  4.     struct mutex lock;      /* Lock for open/release/ioctl funcs */  
  5.     struct mutex mm_lock;       /* Lock for fb_mmap and smem_* fields */  
  6.     struct fb_var_screeninfo var;   /* Current var */  
  7.     struct fb_fix_screeninfo fix;   /* Current fix */  
  8.     struct fb_monspecs monspecs;    /* Current Monitor specs */  
  9.     struct work_struct queue;   /* Framebuffer event queue */  
  10.     struct fb_pixmap pixmap;    /* Image hardware mapper */  
  11.     struct fb_pixmap sprite;    /* Cursor hardware mapper */  
  12.     struct fb_cmap cmap;        /* Current cmap */  
  13.     struct list_head modelist;      /* mode list */  
  14.     struct fb_videomode *mode;  /* current mode */  
  15.   
  16. #ifdef CONFIG_FB_BACKLIGHT   
  17.     /* assigned backlight device */  
  18.     /* set before framebuffer registration,  
  19.        remove after unregister */  
  20.     struct backlight_device *bl_dev;  
  21.   
  22.     /* Backlight level curve */  
  23.     struct mutex bl_curve_mutex;      
  24.     u8 bl_curve[FB_BACKLIGHT_LEVELS];  
  25. #endif   
  26. #ifdef CONFIG_FB_DEFERRED_IO   
  27.     struct delayed_work deferred_work;  
  28.     struct fb_deferred_io *fbdefio;  
  29. #endif   
  30.   
  31.     struct fb_ops *fbops;  
  32.     struct device *device;      /* This is the parent */  
  33.     struct device *dev;     /* This is this fb device */     
  34.     int class_flag;                    /* private sysfs flags */  
  35. #ifdef CONFIG_FB_TILEBLITTING   
  36.     struct fb_tile_ops *tileops;    /* Tile Blitting */  
  37. #endif   
  38.     char __iomem *screen_base;  /* Virtual address */  
  39.     unsigned long screen_size;  /* Amount of ioremapped VRAM or 0 */   
  40.     void *pseudo_palette;       /* Fake palette of 16 colors */   
  41. #define FBINFO_STATE_RUNNING    0   
  42. #define FBINFO_STATE_SUSPENDED  1   
  43.     u32 state;          /* Hardware state i.e suspend */  
  44.     void *fbcon_par;                /* fbcon use-only private area */  
  45.     /* From here on everything is device dependent */  
  46.     void *par;  
  47.     /* we need the PCI or similiar aperture base/size not 
  48.        smem_start/size as smem_start may just be an object 
  49.        allocated inside the aperture so may not actually overlap */  
  50.     resource_size_t aperture_base;  
  51.     resource_size_t aperture_size;  
  52. };  
    这个结构是frambuffer驱动的基本数据结构,里面包含了帧缓存设备的所有信息,每一个注册成frambuffer接口的设备都应该声明并初始化这样一个结构。register_framebuffer 函数的参数就是这样一个结构,fb_info在mini2440lcd驱动中是在s3c24xxfb_probe函数中分配并初始化的。其中struct fb_var_screeninfo结构包含了lcd显示中可以改变的信息,结构如下:
 
  1. struct fb_var_screeninfo {  
  2.     __u32 xres;         /* 视口水平分辨率      */  
  3.     __u32 yres;  
  4.     __u32 xres_virtual;     /* 虚拟屏幕水平分辨率        */  
  5.     __u32 yres_virtual;  
  6.     __u32 xoffset;          /* 视口与虚拟屏幕水平分辨率偏移 */  
  7.     __u32 yoffset;            
  8.   
  9.   
  10.     __u32 bits_per_pixel;       /* 像素的位数            */  
  11.     __u32 grayscale;        /* 灰度标志,如果为1代表是灰度 */  
  12.   
  13.   
  14.     struct fb_bitfield red;     /* 如果是真彩色,这个是颜色位,如果不是那么只有结构的大小重要,其他表示的信息无关紧要 */  
  15.     struct fb_bitfield green;     
  16.     struct fb_bitfield blue;  
  17.     struct fb_bitfield transp;  /* 透明度      */    
  18.   
  19.   
  20.     __u32 nonstd;           /* 非标准颜色表示标志位 */  
  21.     __u32 activate;         /* 参照 FB_ACTIVATE_*     */  
  22.     __u32 height;           /* 在内存地址空间的长度    */  
  23.     __u32 width;            /* 在内存地址空间的宽度     */  
  24.   
  25.   
  26.     __u32 accel_flags;      /* (不用了) 参照 fb_info.flags */  
  27.   
  28.   
  29.     /* 时序: 以下所有的值单位都是pixclock, 当然除了pixclock */  
  30.     __u32 pixclock;         /* 每秒像素值 */  
  31.     __u32 left_margin;      /* 从sync信号到显示真正的像素的时钟个数 */  
  32.     __u32 right_margin;     /* 从真正显示像素到sync信号的时钟个数  */  
  33.     __u32 upper_margin;     /* 上面两个是针对列像素的,这个针对行的   */  
  34.     __u32 lower_margin;  
  35.     __u32 hsync_len;        /* 水平sync信号的长度  */  
  36.     __u32 vsync_len;        /* 垂直sync信号的长度  */  
  37.     __u32 sync;         /* 参照 FB_SYNC_*     */  
  38.     __u32 vmode;            /* 参照 FB_VMODE_*        */  
  39.     __u32 rotate;           /* angle we rotate counter clockwise */   
  40.     __u32 reserved[5];      /* 保留 */  
  41. };  
fb_fix_screeninfo包含了lcd显示中不可改变的信息,结构如下:
  1. struct fb_fix_screeninfo {  
  2.     char id[16];            /* 身份表示符,例如 "TT Builtin" */  
  3.     unsigned long smem_start;   /* frame buffer内存的开始地址 */  
  4.                     /* (物理地址) */  
  5.     __u32 smem_len;         /* frame buffer内存地址的长度 */  
  6.     __u32 type;         /* 参照 FB_TYPE_*     */  
  7.     __u32 type_aux;         /* Interleave for interleaved Planes */  
  8.     __u32 visual;           /* 参照 FB_VISUAL_*       */   
  9.     __u16 xpanstep;         /* zero if no hardware panning  */  
  10.     __u16 ypanstep;         /* zero if no hardware panning  */  
  11.     __u16 ywrapstep;        /* zero if no hardware ywrap    */  
  12.     __u32 line_length;      /* 每行的长度,单位字节    */  
  13.     unsigned long mmio_start;   /* I/O 内存的开始地址   */  
  14.                     /* (物理地址) */  
  15.     __u32 mmio_len;         /* I/O内存的长度  */  
  16.     __u32 accel;            /* 对驱动程序的标示:是哪个设备*/  
  17.     __u16 reserved[3];      /* 保留 */  
  18. };  
其中倒数第三个成员par是设备自定义数据结构。在mini2440lcd驱动中为s3c2410fb_info,结构如下:
  1. struct s3c2410fb_info {  
  2.     struct device       *dev;  
  3.     struct clk      *clk;  
  4.   
  5.     struct resource     *mem; //io内存物理地址也就是寄存器的地址   
  6.     void __iomem        *io;  //用ioremap映射的io虚拟地址   
  7.     void __iomem        *irq_base; //中断控制器寄存器对应的虚拟地址   
  8.   
  9.     enum s3c_drv_type   drv_type;  
  10.     struct s3c2410fb_hw regs;  
  11.   
  12.     unsigned long       clk_rate;  
  13.     unsigned int        palette_ready;  
  14.   
  15. #ifdef CONFIG_CPU_FREQ   
  16.     struct notifier_block   freq_transition;  
  17. #endif   
  18.   
  19.     /* keep these registers in case we need to re-write palette */  
  20.     u32         palette_buffer[256];  
  21.     u32         pseudo_pal[16];  
  22. };  
这个结构是和硬件相关的,包括寄存器的物理地址,虚拟地址和调色板的一些信息。这个结构也是在s3c24xxfb_probe中分配并初始化。
  2. static struct fb_ops 结构
  在mini2440lcd驱动中,fb_ops的初始化代码如下:  
  1. static struct fb_ops s3c2410fb_ops = {  
  2.     .owner      = THIS_MODULE,  
  3.     .fb_check_var   = s3c2410fb_check_var,  
  4.     .fb_set_par = s3c2410fb_set_par,  
  5.     .fb_blank   = s3c2410fb_blank,  
  6.     .fb_setcolreg   = s3c2410fb_setcolreg,  
  7.     .fb_fillrect    = cfb_fillrect,  
  8.     .fb_copyarea    = cfb_copyarea,  
  9.     .fb_imageblit   = cfb_imageblit,  
  10. };  
这些函数是驱动程序必须实现的,他们实现的功能对应frambuffer核心的Ioctl系统调用,当应用程序调用ioctl系统调用的时候,他们会被直接或间接的调用。其中:

s3c2410fb_check_var 和s3c2410fb_set_par会由fb_set_var调用,对应Ioctl的FBIOPUT_VSCREENINFO命令

s3c2410fb_blank ,对应ioctl的FBIOBLANK命令,其他几个函数也是类似。

  3. struct s3c2410fb_mach_info 结构
  1. struct s3c2410fb_mach_info {  
  2.     struct s3c2410fb_display *displays; /* attached diplays info */  
  3.     unsigned num_displays;          /* number of defined displays */  
  4.     unsigned default_display;  
  5.     /* GPIOs */  
  6.     unsigned long   gpcup;  
  7.     unsigned long   gpcup_mask;  
  8.     unsigned long   gpccon;  
  9.     unsigned long   gpccon_mask;  
  10.     unsigned long   gpdup;  
  11.     unsigned long   gpdup_mask;  
  12.     unsigned long   gpdcon;  
  13.     unsigned long   gpdcon_mask;  
  14.   
  15.     /* lpc3600 control register */  
  16.     unsigned long   lpcsel;  
  17. };  
这个结构包括一个s3c2410fb_display结构体,其他的域是GPIO寄存器的信息。mini2440lcd驱动中定义并初始化了这样一个结构体:
  1. static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {  
  2.     .displays   = &mini2440_lcd_cfg,  
  3.     .num_displays   = 1,  
  4.     .default_display = 0,  
  5.   
  6.     .gpccon =       0xaa955699,  
  7.     .gpccon_mask =  0xffc003cc,  
  8.     .gpcup =        0x0000ffff,  
  9.     .gpcup_mask =   0xffffffff,  
  10.   
  11.     .gpdcon =       0xaa95aaa1,  
  12.     .gpdcon_mask =  0xffc0fff0,  
  13.     .gpdup =        0x0000faff,  
  14.     .gpdup_mask =   0xffffffff,  
  15.   
  16.     .lpcsel     = 0xf82,  
  17. };  
这里初始化了结构中的所有成员,s3c2410fb_display结构初始化成mini2440_lcd_cfg,这个结构的初始化是在/arch/arm/mach-s3c2440/mach-mini2440.c这个文件中。这里设置了s3c2440 lcd控制器对应的GPIO寄存器的初始值,在s3c2410fb_init_registers函数中将这些值写到相应的寄存器中。
  4. s3c2410fb_display 结构
  1. struct s3c2410fb_display {  
  2.     /* LCD type */  
  3.     unsigned type;  
  4.   
  5.     /* Screen size */  
  6.     unsigned short width;  
  7.     unsigned short height;  
  8.   
  9.     /* Screen info */  
  10.     unsigned short xres;  
  11.     unsigned short yres;  
  12.     unsigned short bpp;  
  13.   
  14.     unsigned pixclock;      /* pixclock in picoseconds */  
  15.     unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */  
  16.     unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */  
  17.     unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */  
  18.     unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */  
  19.     unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */  
  20.     unsigned short vsync_len;   /* value in lines (TFT) or 0 (STN) */  
  21.   
  22.     /* lcd configuration registers */  
  23.     unsigned long   lcdcon5;  
  24. };  
这个结构体非常重要,他包括了一个lcd显示的所有必须的配置信息。程序就是用这个结构体初始化fb_info结构中的fb_var_screeninfo相关成员的。最后这些值都会写进lcd控制器的相应寄存器中。如上分析,这个结构在mini2440lcd驱动中被初始化成了mini2440_lcd_cfg,他定义在/arch/arm/mach-s3c2440/mach-mini2440.c,如下所示:
  1. static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {  
  2.   
  3. #if !defined (LCD_CON5)   
  4.     .lcdcon5    = S3C2410_LCDCON5_FRM565 |  
  5.               S3C2410_LCDCON5_INVVLINE |  
  6.               S3C2410_LCDCON5_INVVFRAME |  
  7.               S3C2410_LCDCON5_PWREN |  
  8.               S3C2410_LCDCON5_HWSWP,  
  9. #else   
  10.     .lcdcon5    = LCD_CON5,  
  11. #endif   
  12.     .type       = S3C2410_LCDCON1_TFT,  
  13.     .width      = LCD_WIDTH,  
  14.     .height     = LCD_HEIGHT,  
  15.     .pixclock   = LCD_PIXCLOCK,  
  16.     .xres       = LCD_WIDTH,  
  17.     .yres       = LCD_HEIGHT,  
  18.     .bpp        = 16,  
  19.     .left_margin    = LCD_LEFT_MARGIN + 1,  
  20.     .right_margin   = LCD_RIGHT_MARGIN + 1,  
  21.     .hsync_len  = LCD_HSYNC_LEN + 1,  
  22.     .upper_margin   = LCD_UPPER_MARGIN + 1,  
  23.     .lower_margin   = LCD_LOWER_MARGIN + 1,  
  24.     .vsync_len  = LCD_VSYNC_LEN + 1,  
  25. };  
  • 1
  • 2
  • 3
  • 下一页

相关内容