分享

LCD驱动 framebuffer机制

 nt_bookworm 2012-04-24

文章来源:http://blog.csdn.net/guolele2010/article/details/6234905


一、帧缓冲机制

         在谈到lcd驱动时,先谈谈,帧缓冲机制,为什么呢?因为Linux系统是工作在保护模式下,所以用户态进程无法像DOS那要使用显卡BIOS里提供的中断调用来实现直接写屏蔽,Framebuffer是出现在linux 2.2及以后的一种驱动程序接口,它是一项重要技术,基本上都是用它来实现图形界面的。

下面是LCD驱动程序与应用程序以及帧缓冲机制的关系

应用程序要操作LCD,就操作设备节点(/dev/fb0由帧缓冲创建),fbmem.c是提供应用程序的操作接口,fbmem.c本身并不实现这些功能,这就需要下一层接口实现,就是XXXfb.c要实现的与lcd底层硬件相关的操作接口。具体可以参考s3c2410fb.c

帧缓冲技术是与LCD驱动混在一起从而形成帧缓冲LCD设备驱动程序,主要是由下面几个重要数据结构起关联。

 

1Struct fb_info

Struct fb_info这结构记录了帧缓冲设备的全部信息,包括设备的设置参数、状态、以及对底层硬件操作的函数指针。下面具体分析一下。

  1. struct fb_info {  
  2.   
  3.          int node;  
  4.   
  5.          int flags;  
  6.   
  7.          struct fb_var_screeninfo var; /*LCD可变参数结构体 */  
  8.   
  9.          struct fb_fix_screeninfo fix;     /* LCD固定参数结构体 */  
  10.   
  11.          struct fb_monspecs monspecs;       /* LCD显示器标准 */  
  12.   
  13.          struct work_struct queue;       /* 帧缓冲事件队列 */  
  14.   
  15.          struct fb_pixmap pixmap;        /*图像硬件 mapper */  
  16.   
  17.          struct fb_pixmap sprite; /* 光标硬件mapper */  
  18.   
  19.          struct fb_cmap cmap;               /*当前颜色表 */  
  20.   
  21.          struct list_head modelist;      /* mode list */  
  22.   
  23.          struct fb_videomode *mode;  /* 当前的显示模式 */  
  24.   
  25.    
  26.   
  27. #ifdef CONFIG_FB_BACKLIGHT  
  28.   
  29.          struct backlight_device *bl_dev;/*对应背光设备*/  
  30.   
  31.    
  32.   
  33.          /* Backlight level curve */  
  34.   
  35.          struct mutex bl_curve_mutex;          
  36.   
  37.          u8 bl_curve[FB_BACKLIGHT_LEVELS];/*背光调整*/  
  38.   
  39. #endif  
  40.   
  41. 。。。。。。。。  
  42.   
  43.          struct fb_ops *fbops;/*对底层硬件操作的函数指针*/  
  44.   
  45.          ……  
  46.   
  47.          struct device *dev;           /* FB设备 */  
  48.   
  49.          ……  
  50.   
  51. #ifdef CONFIG_FB_TILEBLITTING  
  52.   
  53.          struct fb_tile_ops *tileops;    /*图块 Blitting */  
  54.   
  55. #endif  
  56.   
  57.          char __iomem *screen_base;          /* 虚拟基地址 */  
  58.   
  59.          unsigned long screen_size;     /* LCD IO 映射的虚拟内存大小*/   
  60.   
  61.          void *pseudo_palette;              /*伪16色颜色表 */   
  62.   
  63. #define FBINFO_STATE_RUNNING  0  
  64.   
  65. #define FBINFO_STATE_SUSPENDED       1  
  66.   
  67.          u32 state;                           /* LCD挂起或者恢复的状态*/  
  68.   
  69.          void *fbcon_par;                /* fbcon use-only private area */  
  70.   
  71.          /* From here on everything is device dependent */  
  72.   
  73.          void *par;           
  74.   
  75. };  

 其中比较重要的就是struct fb_var_screeninfo var;              struct fb_fix_screeninfo fix;

struct fb_ops *fbops;

下面各自分析一下

 

2struct fb_var_screeninfo

 

struct fb_var_screeninfo 主要是记录用户可以修改的控制器可变参数

  1. struct fb_var_screeninfo {  
  2.   
  3.          __u32 xres;                         /* 可见屏幕一行有多少个像素点*/  
  4.   
  5.          __u32 yres;                         /*可见屏幕一列有多少个像素点*/  
  6.   
  7.          __u32 xres_virtual;          /*虚拟屏幕一列有多少个像素点*/  
  8.   
  9.          __u32 yres_virtual;          /*虚拟屏幕一列有多少个像素点*/  
  10.   
  11.          __u32 xoffset;                    /* 虚拟到可见屏幕之间的行偏移*/  
  12.   
  13.          __u32 yoffset;                    /*虚拟到可见屏幕之间的列偏移 */  
  14.   
  15.    
  16.   
  17.          __u32 bits_per_pixel;               /* 每个像素由多少位组成即BPP*/  
  18.   
  19.          __u32 grayscale;               /* != 0 Graylevels instead of colors */  
  20.   
  21.    
  22.   
  23. /*fb缓存的RGB位域*/  
  24.   
  25.          struct fb_bitfield red;                /* bitfield in fb mem if true color, */  
  26.   
  27.          struct fb_bitfield green;  /* else only length is significant */  
  28.   
  29.          struct fb_bitfield blue;  
  30.   
  31.          struct fb_bitfield transp; /* transparency                          */       
  32.   
  33.    
  34.   
  35.          __u32 nonstd;                   /* != 0 Non standard pixel format */  
  36.   
  37.    
  38.   
  39.          __u32 activate;                           /* see FB_ACTIVATE_*             */  
  40.   
  41.    
  42.   
  43.          __u32 height;                     /*高度mm*/  
  44.   
  45.          __u32 width;                      /* 宽度 mm*/  
  46.   
  47.    
  48.   
  49.          __u32 accel_flags;            /* (OBSOLETE) see fb_info.flags */  
  50.   
  51.          /*时间选择:除了像素时钟外,所有的值都以像素时钟为单位*/  
  52.   
  53.          /* Timing: All values in pixclocks(像素时钟), except pixclock (of course) */  
  54.   
  55.          __u32 pixclock;                           /* 像素时钟(pico seconds皮秒) */  
  56.   
  57.          __u32 left_margin;           /* time from sync to picture行切换,从同步到绘图之间的延迟       */  
  58.   
  59.          __u32 right_margin;                 /* time from picture to sync行切换,从绘图到同步延迟   */  
  60.   
  61.          __u32 upper_margin;               /* time from sync to picture    帧切换,从同步到绘图之间的延迟*/  
  62.   
  63.          __u32 lower_margin; /*帧切换,从绘图到同步之间的延迟*/  
  64.   
  65.          __u32 hsync_len;              /* length of horizontal sync水平同步的长度*/  
  66.   
  67.          __u32 vsync_len;              /* length of vertical sync 垂直同步的长度*/  
  68.   
  69.          __u32 sync;                        /* see FB_SYNC_*            */  
  70.   
  71.          __u32 vmode;                    /* see FB_VMODE_*                 */  
  72.   
  73.          __u32 rotate;                     /* angle we rotate counter clockwise */  
  74.   
  75.          __u32 reserved[5];           /* Reserved for future compatibility */  
  76.   
  77. };  

 

3struct fb_fix_screeninfo

 

struct fb_fix_screeninfo fix;就是固定的控制器配置,比如屏幕缓冲区的物理地址和长度,定义如下:

  1. struct fb_fix_screeninfo {  
  2.   
  3.          char id[16];                         /* identification string eg "TT Builtin" */  
  4.   
  5.          unsigned long smem_start;    /* Start of frame buffer mem帧缓冲缓存的开始地址 */  
  6.   
  7.                                                /* (physical address) 物理地址*/  
  8.   
  9.          __u32 smem_len;                      /* Length of frame buffer mem 缓冲的长度*/  
  10.   
  11.          __u32 type;                        /* see FB_TYPE_*             */  
  12.   
  13.          __u32 type_aux;                         /* Interleave for interleaved Planes */  
  14.   
  15.          __u32 visual;                      /* see FB_VISUAL_*                  */   
  16.   
  17.          __u16 xpanstep;                         /* 没硬件panning就置0zero if no hardware panning  */  
  18.   
  19.          __u16 ypanstep;                         /*没硬件panning就置0 zero if no hardware panning  */  
  20.   
  21.          __u16 ywrapstep;             /*没硬件ywrap就置0 zero if no hardware ywrap    */  
  22.   
  23.          __u32 line_length;            /*一行的字节数 length of a line in bytes    */  
  24.   
  25.          unsigned long mmio_start;     /*内存映射的开始地址 Start of Memory Mapped I/O   */  
  26.   
  27.                                                /* (physical address) */  
  28.   
  29.          __u32 mmio_len;                       /*内存映射的长度 Length of Memory Mapped I/O  */  
  30.   
  31.          __u32 accel;                       /* Indicate to driver which       */  
  32.   
  33.                                                /*  specific chip/card we have       */  
  34.   
  35.          __u16 reserved[3];           /* Reserved for future compatibility */  
  36.   
  37. };  

 

4struct fb_ops

 

struct fb_ops,帧缓冲操作,关联硬件跟应用程序。

  1. /* 
  2.  
  3.  * Frame buffer operations 
  4.  
  5.  * 
  6.  
  7.  * LOCKING NOTE: those functions must _ALL_ be called with the console 
  8.  
  9.  * semaphore held, this is the only suitable locking mechanism we have 
  10.  
  11.  * in 2.6. Some may be called at interrupt time at this point though. 
  12.  
  13.  */  
  14.   
  15.    
  16.   
  17. struct fb_ops {  
  18.   
  19.          /* open/release and usage marking */  
  20.   
  21.          struct module *owner;  
  22.   
  23.          。。。。。。  
  24.   
  25. /*检查可变参数并进行设置*/  
  26.   
  27.          /* checks var and eventually tweaks it to something supported, 
  28.  
  29.           * DO NOT MODIFY PAR */  
  30.   
  31.          int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);  
  32.   
  33. //根据设置的值进行更新,根据info->var  
  34.   
  35.          /* set the video mode according to info->var */  
  36.   
  37.          int (*fb_set_par)(struct fb_info *info);  
  38.   
  39. //设置颜色寄存器  
  40.   
  41.          /* set color register */  
  42.   
  43.          int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,  
  44.   
  45.                                 unsigned blue, unsigned transp, struct fb_info *info);  
  46.   
  47.    
  48.   
  49.          /* set color registers in batch */  
  50.   
  51.          int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);  
  52.   
  53. //显示空白  
  54.   
  55.          /* blank display */  
  56.   
  57.          int (*fb_blank)(int blank, struct fb_info *info);  
  58.   
  59.    
  60.   
  61. //矩形填充  
  62.   
  63.          /* pan display */  
  64.   
  65.          int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);  
  66.   
  67.    
  68.   
  69.          /* Draws a rectangle */  
  70.   
  71.          void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);  
  72.   
  73.          /* Copy data from area to another */  
  74.   
  75.          void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);  
  76.   
  77.          /* Draws a image to the display */  
  78.   
  79.          void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);  
  80.   
  81.    
  82.   
  83.          /* Draws cursor */  
  84.   
  85.          int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);  
  86.   
  87.    
  88.   
  89.          /* Rotates the display */  
  90.   
  91.          void (*fb_rotate)(struct fb_info *info, int angle);  
  92.   
  93.    
  94.   
  95.          /* wait for blit idle, optional */  
  96.   
  97.          int (*fb_sync)(struct fb_info *info);  
  98.   
  99.    
  100.   
  101.          /* perform fb specific ioctl (optional) */  
  102.   
  103.          int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,  
  104.   
  105.                             unsigned long arg);  
  106.   
  107.    
  108.   
  109.          /* Handle 32bit compat ioctl (optional) */  
  110.   
  111.          int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,  
  112.   
  113.                             unsigned long arg);  
  114.   
  115.    
  116.   
  117.          /* perform fb specific mmap */  
  118.   
  119.          int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);  
  120.   
  121.    
  122.   
  123.          /* save current hardware state */  
  124.   
  125.          void (*fb_save_state)(struct fb_info *info);  
  126.   
  127.    
  128.   
  129.          /* restore saved state */  
  130.   
  131.          void (*fb_restore_state)(struct fb_info *info);  
  132.   
  133.    
  134.   
  135.          /* get capability given var */  
  136.   
  137.          void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,  
  138.   
  139.                                 struct fb_var_screeninfo *var);  
  140.   
  141. };  

5、帧缓冲设备以及设备资源

LCD帧缓冲设备在Linux里是作为一个平台设备,在内核arch/arm/plat-s3c24xx/devs.c中定义LCD相关平台设备如下:

  1. /* LCD Controller */  
  2.   
  3.    
  4.   
  5. static struct resource s3c_lcd_resource[] = {  
  6.   
  7.          [0] = {  
  8.   
  9.                    .start = S3C24XX_PA_LCD,//寄存器的开始地址  
  10.   
  11.                    .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,//长度  
  12.   
  13.                    .flags = IORESOURCE_MEM,  
  14.   
  15.          },  
  16.   
  17.          [1] = {  
  18.   
  19.                    .start = IRQ_LCD,  
  20.   
  21.                    .end   = IRQ_LCD,  
  22.   
  23.                    .flags = IORESOURCE_IRQ,  
  24.   
  25.          }  
  26.   
  27.    
  28.   
  29. };  
  30.   
  31.    
  32.   
  33. static u64 s3c_device_lcd_dmamask = 0xffffffffUL;  
  34.   
  35.    
  36.   
  37. struct platform_device s3c_device_lcd = {  
  38.   
  39.          .name                  = "s3c2410-lcd",  
  40.   
  41.          .id                = -1,  
  42.   
  43.          .num_resources         = ARRAY_SIZE(s3c_lcd_resource),资源数量  
  44.   
  45.          .resource   = s3c_lcd_resource,  
  46.   
  47.          .dev              = {  
  48.   
  49.                    .dma_mask               = &s3c_device_lcd_dmamask,  
  50.   
  51.                    .coherent_dma_mask     = 0xffffffffUL  
  52.   
  53.          }  
  54.   
  55. };  
  56.   
  57.    
  58.   
  59. EXPORT_SYMBOL(s3c_device_lcd);  

这里导出s3c_device_lcd是为了在arch/asm/mach-s3c2410/mach-smdk2410.c里的smdk2410_devices[](或者其它smdk2440_devices[])中添加到平台设备列表中。

下面准备分析具体实例,但分析前还要了解LCD的特性以及读写时序。

实在不如别人做得漂亮,做得详细,大家还是去看原文吧,我这里就不接了。

二、LCD的硬件知识

1. LCD工作的硬件需求:

   要使一块 LCD正常的显示文字或图像,不仅需要 LCD驱动器,而且还需要

相应的 LCD控制器。在通常情况下,生产厂商把LCD驱动器会以 COF/COG

的形式与 LCD玻璃基板制作在一起,而 LCD控制器则是由外部的电路来实现,

现在很多的 MCU内部都集成了 LCD控制器,  S3C2410/2440 等。 通过LCD

控制器就可以产生LCD驱动器所需要的控制信号来控制STN/TFT 屏了。

 

2. S3C2440内部 LCD 控制器结构图:

 

我们根据数据手册来描述一下这个集成在 S3C2440 内部的 LCD控制器:

aLCD控制器由REGBANKLCDCDMATIMEGENVIDPRCS寄存器组

成;

bREGBANK 17个可编程的寄存器组和一块 256*16 的调色板内存组成,

它们用来配置 LCD控制器的;

cLCDCDMA是一个专用的 DMA,它能自动地把在侦内存中的视频数据传送

 LCD驱动器,通过使用这个 DMA通道,视频数据在不需要 CPU的干预的情

况下显示在 LCD屏上;

dVIDPRCS接收来自 LCDCDMA的数据,将数据转换为合适的数据格式,比

如说 4/8 位单扫,位双扫显示模式,然后通过数据端口 VD[23:0]传送视频数

据到 LCD驱动器;

……

在这里我加上《S3c2410 LCD驱动学习心得》因为这里面分析如何确定驱动里的lcd配置参数写得很明白

S3C2410实验箱上的LCD是一款3.5TFT真彩LCD屏,分辩率为240*320,下图为该屏的时序要求。

1.3
通过对比图1.2和图1.3,我们不难看出:
VSPW+1=2 -> VSPW=1

VBPD+1=2 -> VBPD=1
LINVAL+1=320-> LINVAL=319
VFPD+1=3 -> VFPD=2
HSPW+1=4 -> HSPW=3
HBPD+1=7 -> HBPW=6
HOZVAL+1=240-> HOZVAL=239
HFPD+1=31 -> HFPD=30
以上各参数,除了LINVALHOZVAL直接和屏的分辩率有关,其它的参数在实际操作过程中应以上面的为参考,不应偏差太多。 

1.3  LCD
控制器主要寄存器功能详解

1.4
LINECNT 
:当前行扫描计数器值,标明当前扫描到了多少行。
CLKVAL 
:决定VCLK的分频比。LCD控制器输出的VCLK是直接由系统总线(AHB)的工作频率HCLK直接分频得到的。做为240*320TFT屏,应保证得出的VCLK5~10MHz之间。
MMODE 
VM信号的触发模式(仅对STN屏有效,对TFT屏无意义)。
PNRMODE 
:选择当前的显示模式,对于TFT屏而言,应选择[11],即TFT LCD panel
BPPMODE 
:选择色彩模式,对于真彩显示而言,选择16bpp64K色)即可满足要求。
ENVID 
:使能LCD信号输出。

1.5
VBPD 
 LINEVAL  VFPD  VSPW 的各项含义已经在前面的时序图中得到体现。

1.6
HBPD 
 HOZVAL  HFPD 的各项含义已经在前面的时序图中得到体现。

1.7
HSPW 
的含义已经在前面的时序图中得到体现。
MVAL 
只对 STN屏有效,对TFT屏无意义。
HSPW 
的含义已经在前面的时序图中得到体现,这里不再赘述。
MVAL 
只对 STN屏有效,对TFT屏无意义。 




1.8
VSTATUS 
:当前VSYNC信号扫描状态,指明当前VSYNC同步信号处于何种扫描阶段。
HSTATUS 
:当前HSYNC信号扫描状态,指明当前HSYNC同步信号处于何种扫描阶段。
BPP24BL 
:设定24bpp显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp64K色显示模式,该设置位无意义。
FRM565 
:对于16bpp显示模式,有2中形式,一种是RGB5:5:5:1,另一种是5:6:5。后一种模式最为常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,蓝色(B)占了5bit
INVVCLK 
 INVLINE  INVFRAME  INVVD :通过前面的时序图,我们知道,CPULCD控制器输出的时序默认是正脉冲,而LCD需要VSYNCVFRAME)、VLINEHSYNC)均为负脉冲,因此 INVLINE  INVFRAME 必须设为“1 ”,即选择反相输出。
INVVDEN 
 INVPWREN  INVLEND 的功能同前面的类似。
PWREN 
LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。
ENLEND 
对普通的TFT屏无效,可以不考虑。
BSWP 
 HWSWP 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUIFrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP  HWSWP 来适应GUI

 

分析之后,我们能否把这LCD弄成模块?如果可以,又怎么弄?(这跟平台设备驱动有很大关系)

1、修改
linux-2.6.24/arch/arm/mach-s3c2410/mach-smdk2410.c

先加头文件
#include <asm/arch/fb.h>

再加入如下

  1. static struct s3c2410fb_display qt2410_lcd_cfg[] __initdata = {  
  2. {  
  3. /* Configuration for 640x480 SHARP LQ080V3DG01 */  
  4. .lcdcon5 = S3C2410_LCDCON5_FRM565 |  
  5. S3C2410_LCDCON5_INVVLINE |  
  6. S3C2410_LCDCON5_INVVFRAME |  
  7. S3C2410_LCDCON5_PWREN |  
  8. S3C2410_LCDCON5_HWSWP,  
  9.   
  10. .type        = S3C2410_LCDCON1_TFT,  
  11. .width        = 640,  
  12. .height        = 480,  
  13.   
  14. .pixclock    = 40000, /* HCLK/4 */  
  15. .xres        = 640,  
  16. .yres        = 480,  
  17. .bpp        = 16,  
  18. .left_margin    = 44,  
  19. .right_margin    = 116,  
  20. .hsync_len    = 96,  
  21. .upper_margin    = 19,  
  22. .lower_margin    = 11,  
  23. .vsync_len    = 15,  
  24. }  
  25. };  
  26.   
  27. static struct s3c2410fb_mach_info qt2410_fb_info __initdata = {  
  28. .displays     = qt2410_lcd_cfg,  
  29. .num_displays     = 1,  
  30. .default_display = 0,  
  31. //设置引脚模式  
  32. .gpccon=    0xaa8002a8,  
  33. .gpccon_mask=   0xffc003fc,  
  34. .gpcup=     0xf81e,  
  35. .gpcup_mask=    0xf81e,  
  36. .gpdcon=    0xaa80aaa0,  
  37. .gpdcon_mask=   0xffc0fff0,  
  38. .gpdup=     0xf8fc,  
  39. .gpdup_mask=    0xf8fc,  
  40.   
  41. //.lpcsel        = ((0xCE6) & ~7) | 1<<4,  
  42. };  

然后找到
static void __init smdk2410_init(void)
函数
加入
s3c24xx_fb_set_platdata(&qt2410_fb_info);

OK,
文件修改完毕
make menuconfig 
Device Drivers ---> 
Graphics support --->
Display device support ---> 
勾上     S3C2410 LCD framebuffer support 
想看开机的小企鹅就勾上
           Bootup logo
想换一个启动图案的话,如下

1)进入linuxkde图形界面,使用The GIMP 图像编辑器打开你想要的图像文件,依次选择图像->模式->索引颜色,将颜色改为224色;至于图片大小,不要大于你的显示器分辨率就好(我只试过8080320240的大小),最后将文件保存为ppm格式(ASCii码),文件名为:logo_linux_clut224.ppm
2)将logo_linux_clut224.ppm拷贝到/drivers/video/logo文件夹下,替换原有的文件(记得备份啊,以防万一)。
3)重新编译内核,tftp到开发板启动。

直接分析源码

Drivers/video/s3c2410fb.c

前面就是注册LCD平台驱动层,看到结构体static struct platform_driver s3c2410fb_driver,

里面就是这个平台设备的函数指针,通过调用platform_driver_register,如果系统里有LCD设备已经注册了(如果直接移植,就是在mach-smdk2410.c里加的内容注册的),就会调用s3c24xxfb_probe

分析s3c24xxfb_probe(假设是采用移植直接编译在内核里,而不是写成模块)

  1. static int __init s3c24xxfb_probe(struct platform_device *pdev,  
  2.   
  3.                                        enum s3c_drv_type drv_type)  
  4.   
  5. {  
  6.   
  7.          ……  
  8.   
  9. // 这语句是为了得到lcd平台设备数据,也就是lcd的配置(在mach-smdk2410.c定义)  
  10.   
  11.          mach_info = pdev->dev.platform_data;  
  12.   
  13.          ……  
  14.   
  15.    
  16.   
  17. //拿出lcd配置数据  
  18.   
  19.          display = mach_info->displays + mach_info->default_display;  
  20.   
  21. //获中断  
  22.   
  23.          irq = platform_get_irq(pdev, 0);  
  24.   
  25.          ……  
  26.   
  27. //新创一个struct fb_info   
  28.   
  29.          fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
  30.   
  31.          if (!fbinfo)  
  32.   
  33.                    return -ENOMEM;  
  34.   
  35. //放在dev->driver_data里  
  36.   
  37.          platform_set_drvdata(pdev, fbinfo);  
  38.   
  39.    
  40.   
  41.          info = fbinfo->par;  
  42.   
  43.          info->dev = &pdev->dev;  
  44.   
  45.          info->drv_type = drv_type;  
  46.   
  47.    
  48.   
  49.          res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  
  50.   
  51.          ……  
  52.   
  53. //映射  
  54.   
  55.          size = (res->end - res->start) + 1;  
  56.   
  57.          info->mem = request_mem_region(res->start, size, pdev->name);  
  58.   
  59.          ……  
  60.   
  61.    
  62.   
  63.          info->io = ioremap(res->start, size);  
  64.   
  65. ……  
  66.   
  67.          info->irq_base = info->io + ((drv_type == DRV_S3C2412) ? S3C2412_LCDINTBASE : S3C2410_LCDINTBASE);  
  68.   
  69.    
  70.   
  71.    
  72.   
  73.          strcpy(fbinfo->fix.id, driver_name);  
  74.   
  75.    
  76.   
  77.          /* Stop the video */  
  78.   
  79.          lcdcon1 = readl(info->io + S3C2410_LCDCON1);  
  80.   
  81.          writel(lcdcon1 & ~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);  
  82.   
  83.    
  84.   
  85.          fbinfo->fix.type             = FB_TYPE_PACKED_PIXELS;  
  86.   
  87.          fbinfo->fix.type_aux             = 0;  
  88.   
  89.          fbinfo->fix.xpanstep             = 0;  
  90.   
  91.          fbinfo->fix.ypanstep              = 0;  
  92.   
  93.          fbinfo->fix.ywrapstep           = 0;  
  94.   
  95.          fbinfo->fix.accel            = FB_ACCEL_NONE;  
  96.   
  97.    
  98.   
  99.          fbinfo->var.nonstd       = 0;  
  100.   
  101.          fbinfo->var.activate     = FB_ACTIVATE_NOW;  
  102.   
  103.          fbinfo->var.accel_flags     = 0;  
  104.   
  105.          fbinfo->var.vmode        = FB_VMODE_NONINTERLACED;  
  106.   
  107. //主要的接口  
  108.   
  109.          fbinfo->fbops                 = &s3c2410fb_ops;  
  110.   
  111.          fbinfo->flags                  = FBINFO_FLAG_DEFAULT;  
  112.   
  113.          fbinfo->pseudo_palette      = &info->pseudo_pal;  
  114.   
  115.    
  116.   
  117.          for (i = 0; i < 256; i++)  
  118.   
  119.                    info->palette_buffer[i] = PALETTE_BUFF_CLEAR;  
  120.   
  121.    
  122.   
  123.          ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);  
  124.   
  125.          ……  
  126.   
  127. //开时钟  
  128.   
  129.          info->clk = clk_get(NULL, "lcd");  
  130.   
  131.          ……  
  132.   
  133.    
  134.   
  135.          clk_enable(info->clk);  
  136.   
  137. ……  
  138.   
  139. //将一开始加入的lcd设备配置的尺寸加入  
  140.   
  141.          /* find maximum required memory size for display */  
  142.   
  143.          for (i = 0; i < mach_info->num_displays; i++) {  
  144.   
  145.                    unsigned long smem_len = mach_info->displays[i].xres;  
  146.   
  147.    
  148.   
  149.                    smem_len *= mach_info->displays[i].yres;  
  150.   
  151.                    smem_len *= mach_info->displays[i].bpp;  
  152.   
  153.                    smem_len >>= 3;  
  154.   
  155.                    if (fbinfo->fix.smem_len < smem_len)  
  156.   
  157.                             fbinfo->fix.smem_len = smem_len;  
  158.   
  159.          }  
  160.   
  161.    
  162.   
  163.          /* Initialize video memory */  
  164.   
  165.          //申请DRAM作为缓存,用于DMA操作  
  166.   
  167. ret = s3c2410fb_map_video_memory(fbinfo);  
  168.   
  169.          ……  
  170.   
  171.    
  172.   
  173.          fbinfo->var.xres = display->xres;  
  174.   
  175.          fbinfo->var.yres = display->yres;  
  176.   
  177.          fbinfo->var.bits_per_pixel = display->bpp;  
  178.   
  179. //下面这函数设置lcd寄存器  
  180.   
  181.          s3c2410fb_init_registers(fbinfo);  
  182.   
  183. //这个是将lcd的配置写入,这里主要搞清几个结构体的关系  
  184.   
  185. //特别注意fb_info后面还加了一点空间用来保存info的,而info->dev = &pdev->dev,即可以直接调用到传递进来的lcd配置。  
  186.   
  187.          s3c2410fb_check_var(&fbinfo->var, fbinfo);  
  188.   
  189. //注册framebuffer创建设备节点  
  190.   
  191.          ret = register_framebuffer(fbinfo);  
  192.   
  193.          ……  
  194.   
  195.    
  196.   
  197.          /* create device files */  
  198.   
  199.          ret = device_create_file(&pdev->dev, &dev_attr_debug);  
  200.   
  201.          ……  
  202.   
  203. }  

在注册framebuffer,即register_framebuffer里注册完后,假如你将这编译成模块,会发现最终程序死在fb_notifier_call_chain一直等待,最后出现Segmentation fault具体做法是将这语句注释掉,但如果你是把这驱动编译进内核,注释掉这步不能显示开机logo,原因在于,模块编译缺少依赖的内核模块,主要为cfbcopyarea.ko cfbfillrect.ko cfbimgblt.ko,这几个主要是给下面s3c2410fb_ops里的后三个,因为要 显示logoint fb_show_logo(struct fb_info *info)函数中,需要应用fb_ops结构体中的fb_imageblit域来在屏幕上画一幅图象,且是必须的,所以,fb_ops结构中fb_imageblit域不能为NULL,如果为NULL,那么这个函数就没有办法完成功能,也就是一个无用的函数,Fb_ops里面的内容就是完成应用程序系统调用。那register_framebuffer>>fb_notifier_call_chain》》》blocking_notifier_call_chain里的fb_notifier_list,这个内核链表又是哪里定义的?static BLOCKING_NOTIFIER_HEAD(fb_notifier_list);慢慢看就知道定义成什么样子,那接上面的函数深入,到__blocking_notifier_call_chain》》notifier_call_chain,最终会调用nb->notifier_call(nb, val, v);,那什么时候加入到这内核链表?

加的地方有两个,一个是fbcon.c一个是backlight.cfbcon.c里的是fb_register_client(&fbcon_event_notifier);backlight.c里的是info->fb_notif

其中

  1. static struct notifier_block fbcon_event_notifier = {  
  2.   
  3.          .notifier_call    = fbcon_event_notify,  
  4.   
  5. };  

fbcon_event_notify,这函数就根据不同的标志做不同的处理,再跟踪到较里面就发现,原来根据 是不是编译成内核模块来执行不同的东西,如果是编译进内核,就会显示logo了。大概完了。

现在更专业的方法是什么?当然是把那三个内核模块都加载进来

  1. static struct fb_ops s3c2410fb_ops = {  
  2.   
  3.          .owner               = THIS_MODULE,  
  4.   
  5.          .fb_check_var  = s3c2410fb_check_var,  
  6.   
  7.          .fb_set_par      = s3c2410fb_set_par,  
  8.   
  9.          .fb_blank = s3c2410fb_blank,  
  10.   
  11.          .fb_setcolreg   = s3c2410fb_setcolreg,  
  12.   
  13.          .fb_fillrect         = cfb_fillrect,  
  14.   
  15.          .fb_copyarea   = cfb_copyarea,  
  16.   
  17.          .fb_imageblit   = cfb_imageblit,  
  18.   
  19. };  

这里有一个关于pixclock像素时钟计算问题,它是怎么计算得来的?

其实它就是VCLK的另一种表述,VCLK是每秒多少像素,耐pixclock是每像素多少微微秒,1Hz = 10^12picoseconds,举个例子,当pixclock = 80000(pic) VCLK=1/80000*10^12/10^6 = 12.5MHz

由于LCD时钟是使用AHB分频得到的HCLK时钟再分频得来的,pixclock确定之后,怎么确定分频值呢?在函数s3c2410fb_set_par》》》》s3c2410fb_activate_var》》》》》s3c2410fb_calc_pixclk就是计算分频值也就是CLKAL的。还有一个提一下,就是在s3c2410fb_calc_pixclk里有一个unsigned long clk = clk_get_rate(fbi->clk);,其实它是得到HCLK的,具体是在clk_get(NULL,”lcd”)时得到的。

应用层操作lcd

采用fb_open(),fb_mmap(),fb_write()

以华清的例子为例分析

具体参考《嵌入式linux_Framebuffer驱动开发》,复制不过来,这里我在网上找了一个例子。

 

1.    显存大小计算:xres * yres * bits_per_pixel/8 (BYTES)

2.编程流程:

1 打开设备 open("/dev/fb0",O_RDWR);调用fb_open()

(2)   获取framebuffer设备信息.ioctl(int fb,FBIOGET_FSCREENINFO,&finfo);调用fb_ioctl

       ioctl函数是实现对设备的信息获取和设定,第一个参数为文件描述符,第二个参数为具体设备的参数,对于framebuffer,参数在linux/fb.h中定义的。

      #define FBIOGET_VSCREENINFO 0x4600   //获取设备无关的数据信息fb_var_screeninfo
      #define FBIOPUT_VSCREENINFO 0x4601   //
设定设备无关的数据信息

      #define FBIOGET_FSCREENINFO 0x4602   //
获取设备无关的常值信息fb_fix_screeninfo
      #define FBIOGETCMAP   0x4604        //
获取设备无关颜色表信息

      #define FBIOPUTCMAP   0x4605       //
设定设备无关颜色表信息
      #define FBIOPAN_DISPLAY   0x4606
      #define FBIO_CURSOR            _IOWR('F', 0x08, struct fb_cursor)

      第三个参数是存放信息的结构体或者缓冲区

(3)内存映射 mmap函数。头文件:sys/mman.h .常用用法:mmap(0,screensize,PROT_RD |PROT_WR,MAP_SHARED,int fb,0)返回映射的首地址。

3。实例

程序实现在lcd 上全屏写 blue 

  1. #include <unistd.h>  
  2. #include <stdio.h>  
  3. #include <fcntl.h>  
  4. #include <linux/fb.h>  
  5. #include <sys/mman.h>  
  6. #include <stdlib.h>  
  7.   
  8. int main()  
  9. {  
  10.         int fbfd = 0;  
  11.         struct fb_var_screeninfo vinfo;  
  12.         struct fb_fix_screeninfo finfo;  
  13.         long int screensize = 0;  
  14.         char *fbp = 0;  
  15.         int x = 0, y = 0;  
  16.         long int location = 0;  
  17.        int sav=0;  
  18.   
  19.         /* open device*/  
  20.         fbfd = open("/dev/fb0", O_RDWR);  
  21.         if (!fbfd) {  
  22.                 printf("Error: cannot open framebuffer device./n");  
  23.                 exit(1);  
  24.         }  
  25.         printf("The framebuffer device was opened successfully./n");  
  26.   
  27.          
  28.   
  29.         /* Get fixed screen information */  
  30.         if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {  
  31.                 printf("Error reading fixed information./n");  
  32.                 exit(2);  
  33.         }  
  34.   
  35.         /* Get variable screen information */  
  36.         if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {  
  37.                 printf("Error reading variable information./n");  
  38.                 exit(3);  
  39.         }  
  40.   
  41. /* show these information*/  
  42. printf("vinfo.xres=%d/n",vinfo.xres);  
  43. printf("vinfo.yres=%d/n",vinfo.yres);  
  44. printf("vinfo.bits_per_bits=%d/n",vinfo.bits_per_pixel);  
  45. printf("vinfo.xoffset=%d/n",vinfo.xoffset);  
  46. printf("vinfo.yoffset=%d/n",vinfo.yoffset);  
  47. printf("finfo.line_length=%d/n",finfo.line_length);  
  48.   
  49.   
  50.         /* Figure out the size of the screen in bytes */  
  51.         screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  
  52.         总共有多少像素,一像素多少位,转化为字节  
  53.         /* Map the device to memory */  
  54.         fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,  
  55.   
  56.                 fbfd, 0);         
  57.         if ((int)fbp == -1) { printf("Error: failed to map framebuffer device to memory./n"); exit(4);  
  58.         }  
  59.         printf("The framebuffer device was mapped to memory successfully./n");  
  60.   
  61. memset(fbp,0,screensize);  
  62.             /* Where we are going to put the pixel */  
  63.   
  64. for(x=0;x<vinfo.xres;x )  
  65. for(y=0;y<vinfo.yres;y )  
  66.   
  67. {  
  68.   
  69. location = (x+vinfo.xoffset) * (vinfo.bits_per_pixel/8)   
  70.          (y+vinfo.yoffset) * finfo.line_length;  
  71.   
  72.         *(fbp location) = 0xff; /* blue */  
  73.         *(fbp location 1) = 0x00;       
  74.           }              
  75.       munmap(fbp, screensize); /* release the memory */  
  76.       close(fbfd);   
  77.       return 0;  
  78. }  

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多