linux lcd驱动分析二

时间:2022-05-13 17:28:22

接着上 一篇,程序看到了probe函数中。

    831         mach_info = pdev->dev.platform_data;
    832         if (mach_info == NULL) {
    833                 dev_err(&pdev->dev,
    834                         "no platform data for lcd, cannot attach\n");
    835                 return -EINVAL;
    836         }

首先获取平台设备中定义的数据,先看struct s3c2410fb_mach_info这个结构体类型的定义:

/* arch/arm/mach-s3c2410/include/mach/fb.h */

     51 struct s3c2410fb_mach_info {
     52
     53         struct s3c2410fb_display *displays;     /* attached diplays info */
     54         unsigned num_displays;                  /* number of defined displays */
     55         unsigned default_display;
     56
     57         /* GPIOs */
     58
     59         unsigned long   gpcup;
     60         unsigned long   gpcup_mask;
     61         unsigned long   gpccon;
     62         unsigned long   gpccon_mask;
     63         unsigned long   gpdup;
     64         unsigned long   gpdup_mask;
     65         unsigned long   gpdcon;
     66         unsigned long   gpdcon_mask;
     67
     68         /* lpc3600 control register */
     69         unsigned long   lpcsel;
     70 };

我们再来看看这个结构体的定义:

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,
};

再看gpio口定义之前,我们先来看mini2440与lcd的连线。

1. 数据线

lcd总共有18位数据线,r、g、b分别占6位,他们连接到s3c2440的lcd控制器数据线上,分别是VD18~VD23、VD10~VD15、VD2~VD7,但是这些数据线它是复用的,不仅可以作为lcd的数据线,还可以当作普通的gpio口用,所以再使用这些数据线的时候还需要指明这些gpio口的作用。这就这里配置这些gpio口的目的。

2. 行、场信号线

HSYNC、VSYNC也称水平同步信号和垂直同步信号。lcd显示时,是z字形方式扫描,当HSYNC信号出现时,表示一行扫描结束。当VSYNC信号出现时,表示一帧数据结束。所以VSYNC信号的频率为lcd的显示频率,表示一秒钟显示多少帧图像。

3. MCLK

MCLK为lcd的像素时钟,一周期MCLK信号传输一个像素数据,这样数据就源源不断的发送给lcd。

4. RESET、DE

RESET为复位信号线,DE为数据有效数据线。


再来看另外一个数据结构类型定义:

     25 /* LCD description */
     26 struct s3c2410fb_display {
     27         /* LCD type */
     28         unsigned type;
     29
     30         /* Screen size */
     31         unsigned short width;
     32         unsigned short height;
     33
     34         /* Screen info */
     35         unsigned short xres;
     36         unsigned short yres;
     37         unsigned short bpp;
     38
     39         unsigned pixclock;              /* pixclock in picoseconds */
     40         unsigned short left_margin;  /* value in pixels (TFT) or HCLKs (STN) */
     41         unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
     42         unsigned short hsync_len;    /* value in pixels (TFT) or HCLKs (STN) */
     43         unsigned short upper_margin;    /* value in lines (TFT) or 0 (STN) */
     44         unsigned short lower_margin;    /* value in lines (TFT) or 0 (STN) */
     45         unsigned short vsync_len;       /* value in lines (TFT) or 0 (STN) */
     46
     47         /* lcd configuration registers */
     48         unsigned long   lcdcon5;
     49 };

struct s3c2410fb_display描述lcd的显示参数,width和height为像素的宽度与高度,bpp为数据线宽度,是16位还是18位等等,pixclock为像素时钟。mini2440相关定义如下:

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,
};

与TD035STED4 lcd屏相关定义如下:

#define LCD_WIDTH 240
#define LCD_HEIGHT 320
#define LCD_PIXCLOCK 170000

#define LCD_RIGHT_MARGIN 25
#define LCD_LEFT_MARGIN 0
#define LCD_HSYNC_LEN 4

#define LCD_UPPER_MARGIN 1
#define LCD_LOWER_MARGIN 4
#define LCD_VSYNC_LEN 1

struct s3c2410fb_mach_info这个结构是有了,那么它是如何赋值给平台设备的呢。

调用的是s3c24xx_fb_set_platdata这个函数,该函数定义如下:

    172 void __init s3c24xx_fb_set_platdata(struct s3c2410fb_mach_info *pd)
    173 {
    174         struct s3c2410fb_mach_info *npd;
    175
    176         npd = kmalloc(sizeof(*npd), GFP_KERNEL);
    177         if (npd) {
    178                 memcpy(npd, pd, sizeof(*npd));
    179                 s3c_device_lcd.dev.platform_data = npd;
    180         } else {
    181                 printk(KERN_ERR "no memory for LCD platform data\n");
    182         }
    183 }

我们看,的确赋值给了s3c_device_lcd这个平台设备。