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 結構
- struct fb_info {
- int node;
- int flags;
- struct mutex lock; /* Lock for open/release/ioctl funcs */
- struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
- struct fb_var_screeninfo var; /* Current var */
- struct fb_fix_screeninfo fix; /* Current fix */
- struct fb_monspecs monspecs; /* Current Monitor specs */
- struct work_struct queue; /* Framebuffer event queue */
- struct fb_pixmap pixmap; /* Image hardware mapper */
- struct fb_pixmap sprite; /* Cursor hardware mapper */
- struct fb_cmap cmap; /* Current cmap */
- struct list_head modelist; /* mode list */
- struct fb_videomode *mode; /* current mode */
-
- #ifdef CONFIG_FB_BACKLIGHT
- /* assigned backlight device */
- /* set before framebuffer registration,
- remove after unregister */
- struct backlight_device *bl_dev;
-
- /* Backlight level curve */
- struct mutex bl_curve_mutex;
- u8 bl_curve[FB_BACKLIGHT_LEVELS];
- #endif
- #ifdef CONFIG_FB_DEFERRED_IO
- struct delayed_work deferred_work;
- struct fb_deferred_io *fbdefio;
- #endif
-
- struct fb_ops *fbops;
- struct device *device; /* This is the parent */
- struct device *dev; /* This is this fb device */
- int class_flag; /* private sysfs flags */
- #ifdef CONFIG_FB_TILEBLITTING
- struct fb_tile_ops *tileops; /* Tile Blitting */
- #endif
- char __iomem *screen_base; /* Virtual address */
- unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
- void *pseudo_palette; /* Fake palette of 16 colors */
- #define FBINFO_STATE_RUNNING 0
- #define FBINFO_STATE_SUSPENDED 1
- u32 state; /* Hardware state i.e suspend */
- void *fbcon_par; /* fbcon use-only private area */
- /* From here on everything is device dependent */
- void *par;
- /* we need the PCI or similiar aperture base/size not
- smem_start/size as smem_start may just be an object
- allocated inside the aperture so may not actually overlap */
- resource_size_t aperture_base;
- resource_size_t aperture_size;
- };
這個結構是frambuffer驅動的基本數據結構,裡面包含了幀緩存設備的所有信息,每一個注冊成frambuffer接口的設備都應該聲明並初始化這樣一個結構。register_framebuffer 函數的參數就是這樣一個結構,fb_info在mini2440lcd驅動中是在s3c24xxfb_probe函數中分配並初始化的。其中struct fb_var_screeninfo結構包含了lcd顯示中可以改變的信息,結構如下:
- struct fb_var_screeninfo {
- __u32 xres; /* 視口水平分辨率 */
- __u32 yres;
- __u32 xres_virtual; /* 虛擬屏幕水平分辨率 */
- __u32 yres_virtual;
- __u32 xoffset; /* 視口與虛擬屏幕水平分辨率偏移 */
- __u32 yoffset;
-
-
- __u32 bits_per_pixel; /* 像素的位數 */
- __u32 grayscale; /* 灰度標志,如果為1代表是灰度 */
-
-
- struct fb_bitfield red; /* 如果是真彩色,這個是顏色位,如果不是那麼只有結構的大小重要,其他表示的信息無關緊要 */
- struct fb_bitfield green;
- struct fb_bitfield blue;
- struct fb_bitfield transp; /* 透明度 */
-
-
- __u32 nonstd; /* 非標准顏色表示標志位 */
- __u32 activate; /* 參照 FB_ACTIVATE_* */
- __u32 height; /* 在內存地址空間的長度 */
- __u32 width; /* 在內存地址空間的寬度 */
-
-
- __u32 accel_flags; /* (不用了) 參照 fb_info.flags */
-
-
- /* 時序: 以下所有的值單位都是pixclock, 當然除了pixclock */
- __u32 pixclock; /* 每秒像素值 */
- __u32 left_margin; /* 從sync信號到顯示真正的像素的時鐘個數 */
- __u32 right_margin; /* 從真正顯示像素到sync信號的時鐘個數 */
- __u32 upper_margin; /* 上面兩個是針對列像素的,這個針對行的 */
- __u32 lower_margin;
- __u32 hsync_len; /* 水平sync信號的長度 */
- __u32 vsync_len; /* 垂直sync信號的長度 */
- __u32 sync; /* 參照 FB_SYNC_* */
- __u32 vmode; /* 參照 FB_VMODE_* */
- __u32 rotate; /* angle we rotate counter clockwise */
- __u32 reserved[5]; /* 保留 */
- };
fb_fix_screeninfo包含了lcd顯示中不可改變的信息,結構如下:
- struct fb_fix_screeninfo {
- char id[16]; /* 身份表示符,例如 "TT Builtin" */
- unsigned long smem_start; /* frame buffer內存的開始地址 */
- /* (物理地址) */
- __u32 smem_len; /* frame buffer內存地址的長度 */
- __u32 type; /* 參照 FB_TYPE_* */
- __u32 type_aux; /* Interleave for interleaved Planes */
- __u32 visual; /* 參照 FB_VISUAL_* */
- __u16 xpanstep; /* zero if no hardware panning */
- __u16 ypanstep; /* zero if no hardware panning */
- __u16 ywrapstep; /* zero if no hardware ywrap */
- __u32 line_length; /* 每行的長度,單位字節 */
- unsigned long mmio_start; /* I/O 內存的開始地址 */
- /* (物理地址) */
- __u32 mmio_len; /* I/O內存的長度 */
- __u32 accel; /* 對驅動程序的標示:是哪個設備*/
- __u16 reserved[3]; /* 保留 */
- };
其中倒數第三個成員par是設備自定義數據結構。在mini2440lcd驅動中為s3c2410fb_info,結構如下:
- struct s3c2410fb_info {
- struct device *dev;
- struct clk *clk;
-
- struct resource *mem; //io內存物理地址也就是寄存器的地址
- void __iomem *io; //用ioremap映射的io虛擬地址
- void __iomem *irq_base; //中斷控制器寄存器對應的虛擬地址
-
- enum s3c_drv_type drv_type;
- struct s3c2410fb_hw regs;
-
- unsigned long clk_rate;
- unsigned int palette_ready;
-
- #ifdef CONFIG_CPU_FREQ
- struct notifier_block freq_transition;
- #endif
-
- /* keep these registers in case we need to re-write palette */
- u32 palette_buffer[256];
- u32 pseudo_pal[16];
- };
這個結構是和硬件相關的,包括寄存器的物理地址,虛擬地址和調色板的一些信息。這個結構也是在s3c24xxfb_probe中分配並初始化。
2. static struct fb_ops 結構
在mini2440lcd驅動中,fb_ops的初始化代碼如下:
- static struct fb_ops s3c2410fb_ops = {
- .owner = THIS_MODULE,
- .fb_check_var = s3c2410fb_check_var,
- .fb_set_par = s3c2410fb_set_par,
- .fb_blank = s3c2410fb_blank,
- .fb_setcolreg = s3c2410fb_setcolreg,
- .fb_fillrect = cfb_fillrect,
- .fb_copyarea = cfb_copyarea,
- .fb_imageblit = cfb_imageblit,
- };
這些函數是驅動程序必須實現的,他們實現的功能對應frambuffer核心的Ioctl系統調用,當應用程序調用ioctl系統調用的時候,他們會被直接或間接的調用。其中:
s3c2410fb_check_var 和s3c2410fb_set_par會由fb_set_var調用,對應Ioctl的FBIOPUT_VSCREENINFO命令
s3c2410fb_blank ,對應ioctl的FBIOBLANK命令,其他幾個函數也是類似。
3. struct s3c2410fb_mach_info 結構
- struct s3c2410fb_mach_info {
- struct s3c2410fb_display *displays; /* attached diplays info */
- unsigned num_displays; /* number of defined displays */
- unsigned default_display;
- /* GPIOs */
- unsigned long gpcup;
- unsigned long gpcup_mask;
- unsigned long gpccon;
- unsigned long gpccon_mask;
- unsigned long gpdup;
- unsigned long gpdup_mask;
- unsigned long gpdcon;
- unsigned long gpdcon_mask;
-
- /* lpc3600 control register */
- unsigned long lpcsel;
- };
這個結構包括一個s3c2410fb_display結構體,其他的域是GPIO寄存器的信息。mini2440lcd驅動中定義並初始化了這樣一個結構體:
- static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
- .displays = &mini2440_lcd_cfg,
- .num_displays = 1,
- .default_display = 0,
-
- .gpccon = 0xaa955699,
- .gpccon_mask = 0xffc003cc,
- .gpcup = 0x0000ffff,
- .gpcup_mask = 0xffffffff,
-
- .gpdcon = 0xaa95aaa1,
- .gpdcon_mask = 0xffc0fff0,
- .gpdup = 0x0000faff,
- .gpdup_mask = 0xffffffff,
-
- .lpcsel = 0xf82,
- };
這裡初始化了結構中的所有成員,s3c2410fb_display結構初始化成mini2440_lcd_cfg,這個結構的初始化是在/arch/arm/mach-s3c2440/mach-mini2440.c這個文件中。這裡設置了s3c2440 lcd控制器對應的GPIO寄存器的初始值,在s3c2410fb_init_registers函數中將這些值寫到相應的寄存器中。
4. s3c2410fb_display 結構
- struct s3c2410fb_display {
- /* LCD type */
- unsigned type;
-
- /* Screen size */
- unsigned short width;
- unsigned short height;
-
- /* Screen info */
- unsigned short xres;
- unsigned short yres;
- unsigned short bpp;
-
- unsigned pixclock; /* pixclock in picoseconds */
- unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */
- unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
- unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */
- unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
- unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
- unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */
-
- /* lcd configuration registers */
- unsigned long lcdcon5;
- };
這個結構體非常重要,他包括了一個lcd顯示的所有必須的配置信息。程序就是用這個結構體初始化fb_info結構中的fb_var_screeninfo相關成員的。最後這些值都會寫進lcd控制器的相應寄存器中。如上分析,這個結構在mini2440lcd驅動中被初始化成了mini2440_lcd_cfg,他定義在/arch/arm/mach-s3c2440/mach-mini2440.c,如下所示:
- static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {
-
- #if !defined (LCD_CON5)
- .lcdcon5 = S3C2410_LCDCON5_FRM565 |
- S3C2410_LCDCON5_INVVLINE |
- S3C2410_LCDCON5_INVVFRAME |
- S3C2410_LCDCON5_PWREN |
- S3C2410_LCDCON5_HWSWP,
- #else
- .lcdcon5 = LCD_CON5,
- #endif
- .type = S3C2410_LCDCON1_TFT,
- .width = LCD_WIDTH,
- .height = LCD_HEIGHT,
- .pixclock = LCD_PIXCLOCK,
- .xres = LCD_WIDTH,
- .yres = LCD_HEIGHT,
- .bpp = 16,
- .left_margin = LCD_LEFT_MARGIN + 1,
- .right_margin = LCD_RIGHT_MARGIN + 1,
- .hsync_len = LCD_HSYNC_LEN + 1,
- .upper_margin = LCD_UPPER_MARGIN + 1,
- .lower_margin = LCD_LOWER_MARGIN + 1,
- .vsync_len = LCD_VSYNC_LEN + 1,
- };