歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> mini2440驅動分析之LCD

mini2440驅動分析之LCD

日期:2017/3/1 11:16:27   编辑:Linux編程
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. #ifdef CONFIG_FB_BACKLIGHT
  16. /* assigned backlight device */
  17. /* set before framebuffer registration,
  18. remove after unregister */
  19. struct backlight_device *bl_dev;
  20. /* Backlight level curve */
  21. struct mutex bl_curve_mutex;
  22. u8 bl_curve[FB_BACKLIGHT_LEVELS];
  23. #endif
  24. #ifdef CONFIG_FB_DEFERRED_IO
  25. struct delayed_work deferred_work;
  26. struct fb_deferred_io *fbdefio;
  27. #endif
  28. struct fb_ops *fbops;
  29. struct device *device; /* This is the parent */
  30. struct device *dev; /* This is this fb device */
  31. int class_flag; /* private sysfs flags */
  32. #ifdef CONFIG_FB_TILEBLITTING
  33. struct fb_tile_ops *tileops; /* Tile Blitting */
  34. #endif
  35. char __iomem *screen_base; /* Virtual address */
  36. unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */
  37. void *pseudo_palette; /* Fake palette of 16 colors */
  38. #define FBINFO_STATE_RUNNING 0
  39. #define FBINFO_STATE_SUSPENDED 1
  40. u32 state; /* Hardware state i.e suspend */
  41. void *fbcon_par; /* fbcon use-only private area */
  42. /* From here on everything is device dependent */
  43. void *par;
  44. /* we need the PCI or similiar aperture base/size not
  45. smem_start/size as smem_start may just be an object
  46. allocated inside the aperture so may not actually overlap */
  47. resource_size_t aperture_base;
  48. resource_size_t aperture_size;
  49. };
這個結構是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. __u32 bits_per_pixel; /* 像素的位數 */
  9. __u32 grayscale; /* 灰度標志,如果為1代表是灰度 */
  10. struct fb_bitfield red; /* 如果是真彩色,這個是顏色位,如果不是那麼只有結構的大小重要,其他表示的信息無關緊要 */
  11. struct fb_bitfield green;
  12. struct fb_bitfield blue;
  13. struct fb_bitfield transp; /* 透明度 */
  14. __u32 nonstd; /* 非標准顏色表示標志位 */
  15. __u32 activate; /* 參照 FB_ACTIVATE_* */
  16. __u32 height; /* 在內存地址空間的長度 */
  17. __u32 width; /* 在內存地址空間的寬度 */
  18. __u32 accel_flags; /* (不用了) 參照 fb_info.flags */
  19. /* 時序: 以下所有的值單位都是pixclock, 當然除了pixclock */
  20. __u32 pixclock; /* 每秒像素值 */
  21. __u32 left_margin; /* 從sync信號到顯示真正的像素的時鐘個數 */
  22. __u32 right_margin; /* 從真正顯示像素到sync信號的時鐘個數 */
  23. __u32 upper_margin; /* 上面兩個是針對列像素的,這個針對行的 */
  24. __u32 lower_margin;
  25. __u32 hsync_len; /* 水平sync信號的長度 */
  26. __u32 vsync_len; /* 垂直sync信號的長度 */
  27. __u32 sync; /* 參照 FB_SYNC_* */
  28. __u32 vmode; /* 參照 FB_VMODE_* */
  29. __u32 rotate; /* angle we rotate counter clockwise */
  30. __u32 reserved[5]; /* 保留 */
  31. };
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. struct resource *mem; //io內存物理地址也就是寄存器的地址
  5. void __iomem *io; //用ioremap映射的io虛擬地址
  6. void __iomem *irq_base; //中斷控制器寄存器對應的虛擬地址
  7. enum s3c_drv_type drv_type;
  8. struct s3c2410fb_hw regs;
  9. unsigned long clk_rate;
  10. unsigned int palette_ready;
  11. #ifdef CONFIG_CPU_FREQ
  12. struct notifier_block freq_transition;
  13. #endif
  14. /* keep these registers in case we need to re-write palette */
  15. u32 palette_buffer[256];
  16. u32 pseudo_pal[16];
  17. };
這個結構是和硬件相關的,包括寄存器的物理地址,虛擬地址和調色板的一些信息。這個結構也是在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. /* lpc3600 control register */
  15. unsigned long lpcsel;
  16. };
這個結構包括一個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. .gpccon = 0xaa955699,
  6. .gpccon_mask = 0xffc003cc,
  7. .gpcup = 0x0000ffff,
  8. .gpcup_mask = 0xffffffff,
  9. .gpdcon = 0xaa95aaa1,
  10. .gpdcon_mask = 0xffc0fff0,
  11. .gpdup = 0x0000faff,
  12. .gpdup_mask = 0xffffffff,
  13. .lpcsel = 0xf82,
  14. };
這裡初始化了結構中的所有成員,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. /* Screen size */
  5. unsigned short width;
  6. unsigned short height;
  7. /* Screen info */
  8. unsigned short xres;
  9. unsigned short yres;
  10. unsigned short bpp;
  11. unsigned pixclock; /* pixclock in picoseconds */
  12. unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */
  13. unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
  14. unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */
  15. unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
  16. unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
  17. unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */
  18. /* lcd configuration registers */
  19. unsigned long lcdcon5;
  20. };
這個結構體非常重要,他包括了一個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. #if !defined (LCD_CON5)
  3. .lcdcon5 = S3C2410_LCDCON5_FRM565 |
  4. S3C2410_LCDCON5_INVVLINE |
  5. S3C2410_LCDCON5_INVVFRAME |
  6. S3C2410_LCDCON5_PWREN |
  7. S3C2410_LCDCON5_HWSWP,
  8. #else
  9. .lcdcon5 = LCD_CON5,
  10. #endif
  11. .type = S3C2410_LCDCON1_TFT,
  12. .width = LCD_WIDTH,
  13. .height = LCD_HEIGHT,
  14. .pixclock = LCD_PIXCLOCK,
  15. .xres = LCD_WIDTH,
  16. .yres = LCD_HEIGHT,
  17. .bpp = 16,
  18. .left_margin = LCD_LEFT_MARGIN + 1,
  19. .right_margin = LCD_RIGHT_MARGIN + 1,
  20. .hsync_len = LCD_HSYNC_LEN + 1,
  21. .upper_margin = LCD_UPPER_MARGIN + 1,
  22. .lower_margin = LCD_LOWER_MARGIN + 1,
  23. .vsync_len = LCD_VSYNC_LEN + 1,
  24. };
Copyright © Linux教程網 All Rights Reserved