七 linux LCD驱动代分析

Posted bigPillow

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了七 linux LCD驱动代分析相关的知识,希望对你有一定的参考价值。

LCD驱动分析

原文地址:

http://blog.csdn.net/woshidahuaidan2011/article/details/52054795


1、对LCD驱动添加设备信息

对lcd驱动程序,跟之前分析的方式一样,还是先看设备信息,其定义在Mach-smdk2440.c(arch\\arm\\mach-s3c24xx)文件中,在该文件中使用了填充了s3c2410fb_display结构体,

struct s3c2410fb_display

      /*LCD type */

      unsignedtype;

/*********************************************************************************

设置LCD的类型,比如TFTSTNLCD的类型。

各种类型的宏定义在Regs-lcd.h(arch\\arm\\mach-s3c24xx\\include\\mach)文件中,比如:

#defineS3C2410_LCDCON1_STN8    (2<<5)

#defineS3C2410_LCDCON1_TFT       (3<<5)

。。。。。。。。。。。。。。。。。。。。。。。等等

***********************************************************************************/

 

 

      /*Screen size */

      unsignedshort width;//屏幕宽度

      unsignedshort height; //屏幕高度

 

      /*Screen info */

      unsignedshort xres;  //X轴像素点的个数

      unsignedshort yres;  //Y轴像素点的个数

      unsignedshort bpp;   //BPP

 

      unsignedpixclock;            /*像素周期每皮秒 */

      unsignedshort left_margin;  /* HBPD */

      unsignedshort right_margin; /* HFPD */

      unsignedshort hsync_len;    /* HSPW*/

      unsignedshort upper_margin;  /*VBPD*/

      unsignedshort lower_margin;  /*VFPD */

      unsignedshort vsync_len; /*VSPW */

 

      /*lcd configuration registers */

      unsignedlong      lcdcon5; //lcd配置寄存器

因此可以修改Mach-smdk2440.c (arch\\arm\\mach-s3c24xx)文件中的smdk2440_lcd_cfg的结构体:

 

static struct s3c2410fb_displaysmdk2440_lcd_cfg __initdata =

 

.lcdcon5        = S3C2410_LCDCON5_FRM565 |    //565格式

                S3C2410_LCDCON5_INVVLINE |  //HSYNC极性反正

                S3C2410_LCDCON5_INVVFRAME |  //VSYNC极性反正

                S3C2410_LCDCON5_PWREN |      //使能信号输出功能

                S3C2410_LCDCON5_HWSWP,     //存储格式 P1 P2

 

        .type           = S3C2410_LCDCON1_TFT,    //lcd类型

 

        .width          = 480,    //屏幕的宽高尺寸

        .height         = 272,

        .pixclock       =100000, /* HCLK100 MHz, divisor 10*/  像素时钟(皮秒)

        .xres           = 480,  //图像的宽度

        .yres           =272,   //图像的高度

        .bpp            = 16,   //像素的位宽

       .left_margin    = 1,  *行切换,从同步到绘图之间的延迟*/ 

       .right_margin   = 1,  /*行切换,从绘图到同步之间的延迟*/ 

        .hsync_len      = 40,  /*水平同步的长度*/ 

       .upper_margin   = 1,  /*帧切换,从同步到绘图之间的延迟*/ 

        .lower_margin   = 1, /*帧切换,从绘图到同步之间的延迟*/ 

        .vsync_len      = 9  /*垂直同步的长度*/

;

 

Pixclock具体的数值的计算就是:

 pixclock =   1000000* 1 /【(left_margin + right_margin+hsync_len+ xres* upper_margin+ lower_margin +vsync_len+ yres*lcd像素时钟周期

=10000*[1/(1+1+40+480)*(1+1+9+272)*9000000]

=752143

然后修改smdk2440_fb_info结构体位:

static struct s3c2410fb_mach_infosmdk2440_fb_info __initdata =

   .displays       = &smdk2440_lcd_cfg,

   .num_displays     = 1,  //显示器的个数

   .default_display= 0,  //默认显示器编号

// .lpcsel           =((0xCE6) & ~7) | 1<<4, //这里要去掉,这个专门为三星公司生产的lcd设置的

;

 

在Mach-smdk2440.c (arch\\arm\\mach-s3c24xx)文件的,将lcd的platform_device   s3c_device_lcd,加入到smdk2440_devices进而加入到platform平台上。至于lcd的platform_device,其定义在Devs.c(arch\\arm\\plat-samsung)    文件中:

 

structplatform_device s3c_device_lcd =

      .name            = "s3c2410-lcd",  //平台设备的名字

      .id          =-1,

      .num_resources   = ARRAY_SIZE(s3c_lcd_resource),

      .resource       =s3c_lcd_resource, //平台设备所用到的资源

      .dev       =

             .dma_mask          = &samsung_device_dma_mask, //DMA掩码

             .coherent_dma_mask  = DMA_BIT_MASK(32),

     

;

接下来看一下lcd所需要的资源:

static structresource s3c_lcd_resource[] =

      [0] = DEFINE_RES_MEM(S3C24XX_PA_LCD,S3C24XX_SZ_LCD),

      [1] = DEFINE_RES_IRQ(IRQ_LCD),

;

可以看到lcd用到内存资源和中断资源这两个资源。

其中,内存资源的起始地址为0x4D000000,大小为SZ_1M(0x4D000000是lcd寄存器组的开始地址也就是LCDCON1的地址)。

在Mach-smdk2440.c (arch\\arm\\mach-s3c24xx)文件中有中的smdk2440_machine_init函数中有:

s3c24xx_fb_set_platdata(&smdk2440_fb_info);

s3c24xx_fb_set_platdata最终会把s3c2410fb_mach_info赋值给s3c_device_lcd.dev.platform_data。

对lcd的平台资源暂时介绍到这里。

注意这里设置并没有设置背光灯。设备背光灯的方案很多,这里先列举出来其中一个(以后会列出来其他办法):

linux下面有一个通用的GPIO操作接口,那就是我要介绍的 “/sys/class/gpio” 方式,首先在内核菜单选择编译内核的时候加入 Device Drivers  >  GPIO Support  >/sys/class/gpio/… (sysfs interface),然后编译下载内核后会在/sys/class看到gpio 的文件夹,这是 gpio_operation 通过/sys/文件接口操作IO端口 GPIO到文件系统的映射 进入gpio 会看到:

这里的gpiochip0到gpiochip224分别对应A口B口。。。。。。到H口,每类引脚对应32则,A口的起始地址就是0,A口地址就是0到31,B口就是32到63一直类推H口就是256到256+32。打开其中的文件夹里面会包括每个寄存器控制引脚的起始编base,寄存器名称,引脚总数 导出一个引脚的操作步骤  /sys/class/gpio/export文件用于通知系统需要导出控制的GPIO引脚编号,相反的/sys/class/gpio/unexport用于通知系统取消导出。其中引脚编号 = 控制引脚的寄存器基数 + 控制引脚寄存器位数 ,比如我想控制GPB0引脚只需要写数字32到 /sys/class/gpio/export就好,执行:echo 32 > /sys/class/gpio/export,命令成功后生成/sys/class/gpio/gpio32目录,如果没有出现相应的目录,说明此引脚不可导出,假如想删除/sys/class/gpio/gpio12只需要向/sys/class/gpio/unexport写入32就好,执行:echo 32>  /sys/class/gpio/unexport

这里,进入/sys/class/gpio/gpio32目录:direction文件是定义输入输入方向,可以通过下面命令定义为输出 :echo “out” >/sys/class/gpio/gpio32/direction 其中direction接受的参数:in, out, high, low。high/low同时设置方向为输出, 并将value设置为相应的1/0;value文件是端口的数值,为1或0. echo 1 >/sys/class/gpio/gpio32/value 就是控制GPB0输出高电平,也就是打开lcd背光灯。

此时,打开在屏幕黑乎乎的一片,不太好看,此时可以显示内核准备好的背光图片,我们此时仅仅需要将内核设计的图片添加到内核就可以:

在内核配置菜单里面配置:

Device drivers >Graphics support >bootuplogo 选中要显示的格式。

选择完毕,重新下载到内核,打开背光灯就可以看到屏幕的左上角会出现一个小企鹅的图像。

为了每次开机都要执行

echo 32 >  /sys/class/gpio/export

echo “out” >/sys/class/gpio/gpio32/direction 

echo 1 >/sys/class/gpio/gpio32/value 

上面的三条指令打开lcd背光灯,比较繁琐,这里只需要将在开发板的根文件系统下的/etc目录下建立profile文件(假如存在的话不直接在文件写入下面的语句就可以)

vi /etc/profile

写入

echo 32 > /sys/class/gpio/export

echo “out” >/sys/class/gpio/gpio32/direction 

echo 1>/sys/class/gpio/gpio32/value 

保存退出就可以。

下面开看一下测试程序。

2、对LCD驱动的测试

对于lcd,我可以通过ioctl来设置和得到参数,ioctl可用到的参数定义在Fb.h (include\\uapi\\linux)       文件中。由于该文件的内容过多,不再一一列出,因为下面的测试函数获得lcd的可变参数和固定参数,这里我们仅仅列出来这两个结构体。

structfb_fix_screeninfo 可变参数

      char id[16];                 /* identification string eg "TT Builtin"*/

      unsigned long smem_start;       /* Start of frame buffer mem */

                                  /* (physicaladdress) */

      __u32 smem_len;                     /* Length of frame buffer mem */

      __u32 type;                /* see FB_TYPE_*           */

      __u32 type_aux;                /* Interleave for interleaved Planes */

      __u32 visual;                     /* see 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;             /* length of a line in bytes    */

      unsigned long mmio_start;       /* Start of Memory Mapped I/O   */

                                  /* (physicaladdress) */

      __u32 mmio_len;                     /* Length of Memory Mapped I/O  */

      __u32 accel;               /* Indicate to driver which       */

                                  /*  specific chip/card we have      */

      __u16 capabilities;             /* see FB_CAP_*                    */

      __u16 reserved[2];            /* Reserved for future compatibility */

structfb_var_screeninfo   固定的参数

      __u32 xres;                 /* visible resolution           */

      __u32 yres;

      __u32 xres_virtual;            /* virtual resolution           */

      __u32 yres_virtual;

      __u32 xoffset;                   /* offset from virtual to visible */

      __u32 yoffset;                   /* resolution                */

      __u32 bits_per_pixel;               /* guess what                    */

      __u32 grayscale;        /* 0 = color, 1 = grayscale,       */

                                  /* >1 =FOURCC                    */

      struct fb_bitfield red;        /* bitfield in fb mem if true color, */

      struct fb_bitfield green;     /* else only length is significant */

      struct fb_bitfield blue;

      struct fb_bitfield transp;    /* transparency                  */   

      __u32 nonstd;                    /* != 0 Non standard pixel format */

      __u32 activate;                  /* see FB_ACTIVATE_*         */

      __u32 height;                    /* height of picture in mm    */

      __u32 width;                     /* width of picture in mm     */

      __u32 accel_flags;             /* (OBSOLETE) see fb_info.flags */

      /* Timing: All values in pixclocks, exceptpixclock (of course) */

      __u32 pixclock;                 /* pixel clock in ps (pico seconds) */

      __u32 left_margin;            /* time from sync to picture     */

      __u32 right_margin;          /* time from picture to sync     */

      __u32 upper_margin;        /* time from sync to picture     */

      __u32 lower_margin;

      __u32 hsync_len;              /* length of horizontal sync     */

      __u32 vsync_len;              /* length of vertical sync  */

      __u32 sync;                /* see FB_SYNC_*          */

      __u32 vmode;                   /* see FB_VMODE_*             */

      __u32 rotate;                     /* angle we rotate counter clockwise */

      __u32 colorspace;             /* colorspace for FOURCC-based modes */

      __u32 reserved[4];            /* Reserved for future compatibility */

至于上面的结构体的具体的含义暂时不再列出,在下文中将会详细的介绍每个成员的具体含义。

我们可以编写测试代码进行测试。测试函数的作用是现实一副自定义的图片,代码如下:

lcd.c文件为:

#include <unistd.h>

#include <stdio.h>

#include <fcntl.h>

#include <linux/fb.h>

#include"class_lcd.h" //自定义的h文件

 

volatile unsigned short LCDBANK[272][480];

 

void paint_pic(const unsigned char pic[]) //将8转化成16位

 

       int x,y;

       unsigned int colour;

       int p = 0;

 

    for(y = 0 ; y < 272 ; y++ )

   

       for( x = 0 ; x < 480 ; x++ )

       

               colour = pic[p] | (pic[p+1]<<8) ;

 

               //colour = pic[p] ;

                        if ( ( x < 480)&& ( y < 272) )

                                LCDBANK[y][x] =colour ;

                        p = p + 2 ;

                        //p++;

       

   

 

 

 

 

int main(void)

    intfd = 0;

       struct fb_var_screeninfo var; //可变参数

       struct fb_fix_screeninfo fix;  //固定参数

 

    intx = 0, y = 0;

 

    fd =open("/dev/fb0", O_RDWR);

    if(!fd) 

       printf("error open file.\\n");

       close(fd);

   

      if (ioctl(fd, FBIOGET_FSCREENINFO,&var))    //得到可变参数

       printf(" error reading fixed information .\\n");

       close(fd);

   

 

    if(ioctl(fd, FBIOGET_VSCREENINFO, &fix))   //得到固定参数

       printf("error reading variable information.\\n");

       close(fd);

   

       paint_pic(gImage_test);//8位变为16位

       int dat=write(fd,LCDBANK,sizeof(LCDBANK));

//     printf(“%d”,dat );

       close(fd);

 

      return 0;

 

h文件为:

#ifndef __class_lcd_h__

#define __class_lcd_h__

extern const unsigned chargImage_test[];//ͼƬÊý×é

 

#endif //__class_led_h__

 

其中gImage_test[]为用取模软件获得的数组,由于数组比较大不再列出,与之前介绍的裸机代码一样,这里只是将该数组放在test.c的文件中。

接下来就是Makefile文件:

CC=arm-linux-2440-gcc

.c.o:

        $CC -c $<

lcd:test.o lcd.o

        $CC -o $@  $^

 

        cp lcd /work/root/work/

clean:

        rm -rf lcd lcd.o test.o

 

 

编译完毕,会elf的可执行文件lcd,只需要将生成lcd拷贝到arm的文件系统下运行即可。运行完毕,会看到图片显示在lcd中。

 

3、对LCD驱动的分析

lcd的驱动代码定义在S3c2410fb.c (drivers\\video)文件中,前面对于Platform平台的介绍寂静够详细的了,这里不再赘述,就从probe函数开始介绍:

static ints3c24xxfb_probe(struct platform_device *pdev,

                       enum s3c_drv_type drv_type)

      structs3c2410fb_info *info;

      structs3c2410fb_display *display;

      structfb_info *fbinfo;

      structs3c2410fb_mach_info *mach_info;

      structresource *res;

      intret;

      intirq;

      inti;

      intsize;

      u32lcdcon1;

 

      mach_info= dev_get_platdata(&pdev->dev);//得到设备数据platform_data

      if(mach_info == NULL)

             dev_err(&pdev->dev,

                    "noplatform data for lcd, cannot attach\\n");

             return-EINVAL;

     

 

if (mach_info->default_display >=mach_info->num_displays) //判断默认显示器的编号是否大于总显示器的个数

             dev_err(&pdev->dev,"default is %d but only %d displays\\n",

                    mach_info->default_display,mach_info->num_displays);

             return-EINVAL;

     

 

      display= mach_info->displays + mach_info->default_display;

/*********************************************************************************

获取设备定义结构体s3c2410fb_display的实体smdk2440_lcd_cfg的首地址。这里也就获得了平台设备对lcd设置的那些数据。后面又加了一个mach_info->default_display,是指名用的那个设备。

***********************************************************************************/

      irq= platform_get_irq(pdev, 0); //得到中断号

      if(irq < 0)

             dev_err(&pdev->dev,"no irq for device\\n");

             return-ENOENT;

     

 

      fbinfo= framebuffer_alloc(sizeof(struct s3c2410fb_info),&pdev->dev);

/*********************************************************************************

struct fb_info*framebuffer_alloc(size_t size, struct device *dev)

这是在创建一个帧缓冲结构体,

size_t size是驱动私有数据的大小(这里指structs3c2410fb_info)可为0

struct device *de 为指向平台设备的的指针,可以为NULL

返回值为帧缓冲fb_info的结构体,

对于fb_info相当于电脑的显卡。其定义为:

struct fb_info

      atomic_tcount;

      intnode;   //子设备号

      intflags;

      structmutex lock;             /* Lock foropen/release/ioctl funcs */

      structmutex mm_lock;            /* Lock for fb_mmapand smem_* fields */

      structfb_var_screeninfo var;  /* Current var */变化的参数

      struct fb_fix_screeninfofix;   /* Current fix */固定的参数

      structfb_monspecs monspecs; /* Current Monitorspecs */当前显示器规格

      structwork_struct queue;  /* Framebuffer eventqueue */帧缓冲事件队列

      structfb_pixmap pixmap; /* Image hardwaremapper */图像硬件映射

      structfb_pixmap sprite;    /* Cursor hardware mapper */光标硬件映射

      structfb_cmap cmap;        /* Current cmap */color映射表

      structlist_head modelist;      /* mode list */模式链表

      structfb_videomode *mode;   /* current mode */当前的模式

 

#ifdef CONFIG_FB_BACKLIGHT

      /*assigned backlight device */

      /*set before framebuffer registration,

         remove after unregister */

      structbacklight_device *bl_dev ; //背光设备

 

      /*Backlight level curve */

      structmutex bl_curve_mutex;

      u8bl_curve[FB_BACKLIGHT_LEVELS]; //应该设置背光的亮度

#endif

#ifdef CONFIG_FB_DEFERRED_IO

      structdelayed_work deferred_work;   //应该是延时工作

      structfb_deferred_io *fbdefio;

#endif

 

      structfb_ops *fbops;         //缓冲区有关文件操作

      structdevice *device;       /* This is theparent */

      structdevice *dev;            /* This is this fbdevice */

      intclass_flag;                    /* private sysfs flags */

#ifdef CONFIG_FB_TILEBLITTING  

      structfb_tile_ops *tileops;    /* Tile Blitting*/位图移动

#endif

      char__iomem *screen_base;   /* Virtual address*/

      unsignedlong screen_size;       /* Amount ofioremapped VRAM or 0 */ 帧缓存大小

      void*pseudo_palette;              /* Fakepalette of 16 colors */16色调色板

#define FBINFO_STATE_RUNNING 0

#define FBINFO_STATE_SUSPENDED  1

      u32state;                    /* Hardwarestate i.e suspend *///

      void*fbcon_par;                /* fbconuse-only private area */驱动定义的私有信息

      /*From here on everything is device dependent */

      void*par;

      /*we need the PCI or similar aperture base/size not

         smem_start/size as smem_start may just be anobject

         allocated inside the aperture so may notactually overlap */

      structapertures_struct

             unsignedint count;

             structaperture

                    resource_size_tbase;

                    resource_size_tsize;

             ranges[0];

      *apertures;

 

      boolskip_vt_switch; /* no VT switch on suspend/resume required */

;

上面有提到对于可变参数的一个结构体structfb_var_screeninfo,该结构体主要是定义的一些lcd的可变信息,比较重要,这里来看一下:

structfb_var_screeninfo

   __u32 xres;                 /*visible resolution    */可见分辨率480x272320x480等等)

   __u32 yres;

   __u32 xres_virtual;           /* virtual resolution    *//虚拟分辨率(这是为了屏幕显示区可移动设置的)

   __u32 yres_virtual;

   __u32 xoffset;                   /* offset from virtual to visible */偏移量,对应2440lcd控制器的15-25页的offsize

   __u32 yoffset;                   /* resolution               */

 

   __u32 bits_per_pixel;               /* guess what      */ bpp

   __u32 grayscale;        /* 0 = color, 1 = grayscale,       */ 灰度还是颜色

                               /* >1 = FOURCC                    */

   struct fb_bitfield red;        /* bitfield in fb mem if true color, */

   struct fb_bitfield green;    /* else only length is significant */

   struct fb_bitfield blue;

   struct fb_bitfield transp;   /* transparency                  */   

/*********************************************************************************

分别是红绿 透明度所占用的bpp的位数信息。其中:

struct fb_bitfield

       __u32 offset;                     /* beginning of bitfield     */开始位子

       __u32 length;                    /* length of bitfield           */长度

       __u32 msb_right;              /* != 0 : Most significant bit is */影响最大的位

                                   /* right */

;

/*********************************************************************************/

 

   __u32 nonstd;                   /*!= 0 Non standard pixel format */假如不为0代表为标准bpp

 

   __u32 activate;                  /* see FB_ACTIVATE_* */FB_ACTIVATE_*宏确定

 

   __u32 height;                    /*height of picture in mm    */

   __u32 width;                     /*width of picture in mm     */

 

   __u32 accel_flags;            /* (OBSOLETE) see fb_info.flags */

 

   /* Timing: All values in pixclocks, exceptpixclock (of course) */

   __u32 pixclock;                 /* pixel clock in ps (pico seconds) */ 下面几个参数第一节已经分析

   __u32 left_margin;            /* time from sync to picture     */

   __u32 right_margin;          /* time from picture to sync     */

   __u32 upper_margin;        /* time from sync to picture     */

   __u32 lower_margin;

   __u32 hsync_len;              /* length of horizontal sync     */  HSYNC

   __u32 vsync_len;              /* length of vertical sync  */      VSYNC

   __u32 sync;                /*see FB_SYNC_*          */

   __u32 vmode;                   /*see FB_VMODE_*             */

   __u32 rotate;                     /*angle we rotate counter clockwise */

   __u32 colorspace;             /* colorspace for FOURCC-based modes */

   __u32 reserved[4];            /* Reserved for future compatibility */

;

那么再看一下固定参数的结构体fb_fix_screeninfo

 

structfb_fix_screeninfo

   char id[16];                /*identification string eg "TT Builtin" */标识符,一般是驱动的名字

   unsigned long smem_start;      /* Start of frame buffer mem */内存开始物理地址

                               /* (physicaladdress) */

   __u32 smem_len;                     /* Length of frame buffer mem */假如有多个lcd,这里记录的是帧内存最大的内存大小

   __u32 type;                /*see FB_TYPE_*           */

   __u32 type_aux;               /* Interleave for interleaved Planes */

   __u32 visual;                     /*see FB_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;            /* length of a line in bytes    */

   unsigned long mmio_start;       /* Start of Memory Mapped I/O  */引脚起始物理地址

                               /* (physicaladdress) */

   __u32 mmio_len;                     /* Length of Memory Mapped I/O  */

   __u32 accel;               /*Indicate to driver which       */指出那个驱动

                               /*  specific chip/card we have      */

   __u16 capabilities;            /* see FB_CAP_*                    */

   __u16 reserved[2];            /* Reserved for future compatibility */

;

 

***********************************************************************************/

 

      if (!fbinfo)

             return -ENOMEM;

 

      platform_set_drvdata(pdev,fbinfo);  //保存数据

 

      info = fbinfo->par;  //获取设备定义依赖信息

      info->dev =&pdev->dev;  获得设备信息

      info->drv_type =drv_type; //或许类型

 

      res =platform_get_resource(pdev, IORESOURCE_MEM, 0); //获取内存资源

      if (res == NULL)

             dev_err(&pdev->dev,"failed to get memory registers\\n");

             ret = -ENXIO;

             goto dealloc_fb;

     

 

      size = resource_size(res); //获取内存资源大小,单位byte

      info->mem =request_mem_region(res->start, size, pdev->name); 

/*********************************************************************************

这个是关系到有关io内存的申请,对于一般内存的控制,比如向某个控制寄存器写入数据,这直接使用ioremap函数,将物理地址转换为虚拟地址就可以;但是对于I/OPort内存则需先申请再映射,即先调用request_mem_region,然后在ioremap,这样的话就告诉内核该引脚已经被我使用,别人不可再用,加入对于I/OPort不使用request_mem_region而直接ioremap,虽然可以也可以使用,但是可能内核并不知道相应的引脚已经被使用,于是肯呢个会会出现难以预料的错误。

 

********************************************************************************/

 

      if (info->mem == NULL)

             dev_err(&pdev->dev,"failed to get memory region\\n");

             ret = -ENOENT;

             goto dealloc_fb;

     

 

      info->io =ioremap(res->start, size); //物理地址转化为虚拟地址

      if (info->io == NULL)

             dev_err(&pdev->dev,"ioremap() of registers failed\\n");

             ret = -ENXIO;

             goto release_mem;

     

 

      if (drv_type == DRV_S3C2412) //判断类型

             info->irq_base =info->io + S3C2412_LCDINTBASE;

      else

             info->irq_base =info->io + S3C2410_LCDINTBASE;

 

      dprintk("devinit\\n");

 

      strcpy(fbinfo->fix.id,driver_name); //拷贝名字

 

      /* Stop the video */

      lcdcon1 = readl(info->io+ S3C2410_LCDCON1); //读取寄存器的值

      writel(lcdcon1 &~S3C2410_LCDCON1_ENVID, info->io + S3C2410_LCDCON1);

 //暂时关闭信号输出使能

 

      fbinfo->fix.type      =FB_TYPE_PACKED_PIXELS;  //类型

      fbinfo->fix.type_aux     = 0;

      fbinfo->fix.xpanstep      = 0;

      fbinfo->fix.ypanstep      = 0;

      fbinfo->fix.ywrapstep          = 0;

      fbinfo->fix.accel     =FB_ACCEL_NONE; //无硬件加速

 

      fbinfo->var.nonstd         =0; 标准格式bpp

      fbinfo->var.activate       =FB_ACTIVATE_NOW;

//使设定值马上有效,与之相对可以设定下次打开设备设定值有效(FB_ACTIVATE_NXTOPEN

      fbinfo->var.accel_flags     = 0;

      fbinfo->var.vmode         =FB_VMODE_NONINTERLACED;

 

      fbinfo->fbops                = &s3c2410fb_ops;

/*********************************************************************************

对于文件操作:

staticstruct fb_ops s3c2410fb_ops =

      .owner          =THIS_MODULE,

      .fb_check_var      = s3c2410fb_check_var, 检查可变参数的设定,kernel并适当调整参数值

      .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, //显示图像

;

上面的这些函数会在属性文件中调用。

********************************************************************************/

 

 

      fbinfo->flags                 = FBINFO_FLAG_DEFAULT;

      fbinfo->pseudo_palette      = &info->pseudo_pal;

 

      for (i = 0; i < 256; i++)

             info->palette_buffer[i]= PALETTE_BUFF_CLEAR;  清空调色板

 

      ret = request_irq(irq,s3c2410fb_irq, 0, pdev->name, info);  //申请中断

      if (ret)

             dev_err(&pdev->dev,"cannot get irq %d - err %d\\n", irq, ret);

             ret = -EBUSY;

             goto release_regs;

     

 

      info->clk = clk_get(NULL,"lcd"); //得到lcd的时钟Clock-s3c2410.c (arch\\arm\\mach-s3c24xx)

      if (IS_ERR(info->clk))

             dev_err(&pdev->dev,"failed to get lcd clock source\\n");

             ret =PTR_ERR(info->clk);

             goto release_irq;

     

 

      clk_enable(info->clk);//时钟使能

      dprintk("got andenabled clock\\n");

 

      usleep_range(1000, 1100);等待时钟完成,等待时间为1000微妙到1100微妙之间

 

      info->clk_rate =clk_get_rate(info->clk);//获取时钟频率

 

      /* find maximum requiredmemory size for display */ /

      for (i = 0; i <mach_info->num_displays; i++) //加入有多个lcd,获取最大的帧内存的大小

             unsigned longsmem_len = mach_info->displays[i].xres; //下面三句话是得到帧内存的大小

 

             smem_len *=mach_info->displays[i].yres;

             smem_len *=mach_info->displays[i].bpp;

             smem_len >>= 3;//上面得到的单位为bit,这里是将其为byte

             if (fbinfo->fix.smem_len< smem_len) //记录最大值

                    fbinfo->fix.smem_len= smem_len;

     

/* Initialize video memory */

      ret = s3c2410fb_map_video_memory(fbinfo);

/*********************************************************************************

s3c2410fb_map_video_memory分配DRAM的缓存区给fbinfo。这个缓存区是一个non-cached,non-buffered 这片内存区域允许调色板和像素在写入时不刷新cache缓存 一旦这片区域重新映射,那么所有用来访问video memory的虚拟内存将会 对应另外一片新的区域,即另外一片物理地址。

函数返回的是可供mda使用的虚拟地址。

static int s3c2410fb_map_video_memory(struct fb_info*info)

      structs3c2410fb_info *fbi = info->par;

      dma_addr_tmap_dma; //存储申请缓冲器内存的物理地址。

      unsignedmap_size = PAGE_ALIGN(info->fix.smem_len);

/*********************************************************************************

PAGE_ALIGN返回页对齐页码

#define PAGE_ALIGN(addr) ALIGN(addr,PAGE_SIZE)

#define ALIGN(x, a) (((x) + ((a) - 1)) & ~((a) - 1))

#define PAGE_SHIFT            12

#define PAGE_SIZE        (_AC(1,UL) << PAGE_SHIFT)

替换后就是:

addr+1111 1111 1111& ~1111 0000 00000000

假如地址是addr 0x12345679那么计算后就是:

0x12345678+11111111 1111&~1111 0000 0000 0000

0001 0010 0011 0100 0110 0110 0111 0111

1111 1111 1111 1111  1111 0000 0000 0000

0001 0010 0011 0100 0110 0000 0000 0000  也就是0x12346000

这里就设置成了4字节对齐,也就是也对齐

********************************************************************************/

 

      dprintk("map_video_memory(fbi=%p)map_size %u\\n", fbi, map_size);

 

      info->screen_base= dma_alloc_writecombine(fbi->dev, map_size,

      

以上是关于七 linux LCD驱动代分析的主要内容,如果未能解决你的问题,请参考以下文章

Linux的LCD驱动分析及移植

Linux驱动分析之LCD驱动架构

Linux内核LCD驱动分析与换屏方法(Tiny4412)

《Linux驱动》iTop4412开发板LCD驱动 详细分析

LCD驱动源码分析(s3cfb.c)

Linux 帧缓冲子系统详解:LCD介绍framebuffer驱动框架LCD驱动源码分析