嵌入式linux之LCD驱动层次分析

这里写图片描述

这里写图片描述

static int __init  
fbmem_init(void)  
{  
    proc_create("fb", 0, NULL, &fb_proc_fops);  

    if (register_chrdev(FB_MAJOR,"fb",&fb_fops))    //注册了名字为fb的字符设备,相关操作为fb_fops  
        printk("unable to get major %d for fb devs\n", FB_MAJOR);  

    fb_class = class_create(THIS_MODULE, "graphics");//创建了一个名字为graphics的类  
    if (IS_ERR(fb_class)) {  
        printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));  
        fb_class = NULL;  
    }  
    return 0;  
}  

fb_fops为上层app提供了open,read,write,mmap,ioctrl的相关操作:
open操作:
app:  open("/dev/fb0", ...)   主设备号: 29, 次设备号: 0
--------------------------------------------------------------
kernel:
         fb_open
            int fbidx = iminor(inode);
            struct fb_info *info = = registered_fb[0]; // registered_fb很重要,从registered_fb数组中获取到fb_info,并且如果定义了info->fbops->fb_open,就会调用底层的fb_open

read操作:
app:  read()
---------------------------------------------------------------
kernel:
        fb_read
            int fbidx = iminor(inode);      //获取次设备号
            struct fb_info *info = registered_fb[fbidx];   //和open一样,从registered_fb数组中获取fb_info
            if (info->fbops->fb_read)                                //假如底层定义了info->fbops->fb_read,就使用底层的fb_read
                return info->fbops->fb_read(info, buf, count, ppos);

            //否则就直接copy_to_user
            src = (u32 __iomem *) (info->screen_base + p);
            dst = buffer;
            *dst++ = fb_readl(src++);
            copy_to_user(buf, buffer, c)

问1. registered_fb数组在哪里被设置?
答1. register_framebuffer

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
int  
register_framebuffer(struct fb_info *fb_info)  
{  
。。。  
    fb_info->dev = device_create(fb_class, fb_info->device,  
                     MKDEV(FB_MAJOR, i), NULL, "fb%d", i); //生成/dev/下的fb节点  
。。。  
    registered_fb[i] = fb_info; //将传进来的fb_info放入到registered_fb数组中  
。。。  
}  

再查找register_framebuffer再哪被调用,发现6410的LCD驱动代码(硬件相关操作)路径为:
S3cfb.c (drivers\video),可以参考此代码编写驱动程序。

总结一下如何编写一个LCD驱动程序:
1. 分配一个fb_info结构体: framebuffer_alloc
2. 设置,fb_info相关
3. 注册: register_framebuffer
4. 硬件相关的操作:硬件设备寄存器相关

//以下为转载

应用程序要操作LCD,就操作设备节点(/dev/fb0由帧缓冲创建),fbmem.c是提供应用程序的操作接口,fbmem.c本身并不实现这些功能,这就需要下一层接口实现,就是XXXfb.c要实现的与lcd底层硬件相关的操作接口。具体可以参考s3c2410fb.c。
帧缓冲技术是与LCD驱动混在一起从而形成帧缓冲LCD设备驱动程序,主要是由下面几个重要数据结构起关联。

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

     int node;  

     int flags;  

     struct fb_var_screeninfo var; /*LCD可变参数结构体 */  

     struct fb_fix_screeninfo fix;     /* LCD固定参数结构体 */  

     struct fb_monspecs monspecs;       /* LCD显示器标准 */  

     struct work_struct queue;       /* 帧缓冲事件队列 */  

     struct fb_pixmap pixmap;        /*图像硬件 mapper */  

     struct fb_pixmap sprite; /* 光标硬件mapper */  

     struct fb_cmap cmap;               /*当前颜色表 */  

     struct list_head modelist;      /* mode list */  

     struct fb_videomode *mode;  /* 当前的显示模式 */  

ifdef CONFIG_FB_BACKLIGHT

     struct backlight_device *bl_dev;/*对应背光设备*/  



     /* Backlight level curve */  

     struct mutex bl_curve_mutex;          

     u8 bl_curve[FB_BACKLIGHT_LEVELS];/*背光调整*/  

endif

。。。。。。。。

     struct fb_ops *fbops;/*对底层硬件操作的函数指针*/  

     ……  

     struct device *dev;           /* FB设备 */  

     ……  

ifdef CONFIG_FB_TILEBLITTING

     struct fb_tile_ops *tileops;    /*图块 Blitting */  

endif

     char __iomem *screen_base;          /* 虚拟基地址 */  

     unsigned long screen_size;     /* LCD IO 映射的虚拟内存大小*/   

     void *pseudo_palette;              /*伪16色颜色表 */   

define FBINFO_STATE_RUNNING 0

define FBINFO_STATE_SUSPENDED 1

     u32 state;                           /* LCD挂起或者恢复的状态*/  

     void *fbcon_par;                /* fbcon use-only private area */  

     /* From here on everything is device dependent */  

     void *par;           

};

其中比较重要的就是struct fb_var_screeninfo var; struct fb_fix_screeninfo fix;
跟struct fb_ops *fbops;
下面各自分析一下

2、struct fb_var_screeninfo

struct fb_var_screeninfo 主要是记录用户可以修改的控制器可变参数
[cpp] view plaincopy
struct fb_var_screeninfo {

     __u32 xres;                         /* 可见屏幕一行有多少个像素点*/  

     __u32 yres;                         /*可见屏幕一列有多少个像素点*/  

     __u32 xres_virtual;          /*虚拟屏幕一列有多少个像素点*/  

     __u32 yres_virtual;          /*虚拟屏幕一列有多少个像素点*/  

     __u32 xoffset;                    /* 虚拟到可见屏幕之间的行偏移*/  

     __u32 yoffset;                    /*虚拟到可见屏幕之间的列偏移 */  



     __u32 bits_per_pixel;               /* 每个像素由多少位组成即BPP*/  

     __u32 grayscale;               /* != 0 Graylevels instead of colors */  

/fb缓存的RGB位域/

     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;                     /*高度mm*/  

     __u32 width;                      /* 宽度 mm*/  



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

     /*时间选择:除了像素时钟外,所有的值都以像素时钟为单位*/  

     /* Timing: All values in pixclocks(像素时钟), except pixclock (of course) */  

     __u32 pixclock;                           /* 像素时钟(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 reserved[5];           /* Reserved for future compatibility */  

};

3、struct fb_fix_screeninfo

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

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

     unsigned long smem_start;    /* Start of frame buffer mem帧缓冲缓存的开始地址 */  

                                           /* (physical address) 物理地址*/  

     __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;                         /* 没硬件panning就置0zero if no hardware panning  */  

     __u16 ypanstep;                         /*没硬件panning就置0 zero if no hardware panning  */  

     __u16 ywrapstep;             /*没硬件ywrap就置0 zero if no hardware ywrap    */  

     __u32 line_length;            /*一行的字节数 length of a line in bytes    */  

     unsigned long mmio_start;     /*内存映射的开始地址 Start of Memory Mapped I/O   */  

                                           /* (physical address) */  

     __u32 mmio_len;                       /*内存映射的长度 Length of Memory Mapped I/O  */  

     __u32 accel;                       /* Indicate to driver which       */  

                                           /*  specific chip/card we have       */  

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

};

4、struct fb_ops

struct fb_ops,帧缓冲操作,关联硬件跟应用程序。
[cpp] view plaincopy
/*

  • Frame buffer operations

  • LOCKING NOTE: those functions must ALL be called with the console

  • semaphore held, this is the only suitable locking mechanism we have

  • in 2.6. Some may be called at interrupt time at this point though.

    */

struct fb_ops {

     /* open/release and usage marking */  

     struct module *owner;  

     。。。。。。  

/检查可变参数并进行设置/

     /* checks var and eventually tweaks it to something supported, 

      * DO NOT MODIFY PAR */  

     int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);  

//根据设置的值进行更新,根据info->var

     /* set the video mode according to info->var */  

     int (*fb_set_par)(struct fb_info *info);  

//设置颜色寄存器

     /* set color register */  

     int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,  

                            unsigned blue, unsigned transp, struct fb_info *info);  



     /* set color registers in batch */  

     int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);  

//显示空白

     /* blank display */  

     int (*fb_blank)(int blank, struct fb_info *info);  

//矩形填充

     /* pan display */  

     int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);  



     /* Draws a rectangle */  

     void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);  

     /* Copy data from area to another */  

     void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);  

     /* Draws a image to the display */  

     void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);  



     /* Draws cursor */  

     int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);  



     /* Rotates the display */  

     void (*fb_rotate)(struct fb_info *info, int angle);  



     /* wait for blit idle, optional */  

     int (*fb_sync)(struct fb_info *info);  



     /* perform fb specific ioctl (optional) */  

     int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,  

                        unsigned long arg);  



     /* Handle 32bit compat ioctl (optional) */  

     int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,  

                        unsigned long arg);  



     /* perform fb specific mmap */  

     int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);  



     /* save current hardware state */  

     void (*fb_save_state)(struct fb_info *info);  



     /* restore saved state */  

     void (*fb_restore_state)(struct fb_info *info);  



     /* get capability given var */  

     void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,  

                            struct fb_var_screeninfo *var);  

};

5、帧缓冲设备以及设备资源
LCD帧缓冲设备在Linux里是作为一个平台设备,在内核arch/arm/plat-s3c24xx/devs.c中定义LCD相关平台设备如下:
[cpp] view plaincopy
/* LCD Controller */

static struct resource s3c_lcd_resource[] = {

     [0] = {  

               .start = S3C24XX_PA_LCD,//寄存器的开始地址  

               .end   = S3C24XX_PA_LCD + S3C24XX_SZ_LCD - 1,//长度  

               .flags = IORESOURCE_MEM,  

     },  

     [1] = {  

               .start = IRQ_LCD,  

               .end   = IRQ_LCD,  

               .flags = IORESOURCE_IRQ,  

     }  

};

static u64 s3c_device_lcd_dmamask = 0xffffffffUL;

struct platform_device s3c_device_lcd = {

     .name                  = "s3c2410-lcd",  

     .id                = -1,  

     .num_resources         = ARRAY_SIZE(s3c_lcd_resource),资源数量  

     .resource   = s3c_lcd_resource,  

     .dev              = {  

               .dma_mask               = &s3c_device_lcd_dmamask,  

               .coherent_dma_mask     = 0xffffffffUL  

     }  

};

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 屏了。

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

我们根据数据手册来描述一下这个集成在 S3C2440 内部的 LCD控制器:
a:LCD控制器由REGBANK、LCDCDMA、TIMEGEN、VIDPRCS寄存器组
成;
b:REGBANK由 17个可编程的寄存器组和一块 256*16 的调色板内存组成,
它们用来配置 LCD控制器的;
c:LCDCDMA是一个专用的 DMA,它能自动地把在侦内存中的视频数据传送
到 LCD驱动器,通过使用这个 DMA通道,视频数据在不需要 CPU的干预的情
况下显示在 LCD屏上;
d:VIDPRCS接收来自 LCDCDMA的数据,将数据转换为合适的数据格式,比
如说 4/8 位单扫,4 位双扫显示模式,然后通过数据端口 VD[23:0]传送视频数
据到 LCD驱动器;
……
在这里我加上《S3c2410 LCD驱动学习心得》因为这里面分析如何确定驱动里的lcd配置参数写得很明白
S3C2410实验箱上的LCD是一款3.5寸TFT真彩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
以上各参数,除了LINVAL和HOZVAL直接和屏的分辩率有关,其它的参数在实际操作过程中应以上面的为参考,不应偏差太多。

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

图1.4
LINECNT :当前行扫描计数器值,标明当前扫描到了多少行。
CLKVAL :决定VCLK的分频比。LCD控制器输出的VCLK是直接由系统总线(AHB)的工作频率HCLK直接分频得到的。做为240*320的TFT屏,应保证得出的VCLK在5~10MHz之间。
MMODE :VM信号的触发模式(仅对STN屏有效,对TFT屏无意义)。
PNRMODE :选择当前的显示模式,对于TFT屏而言,应选择[11],即TFT LCD panel。
BPPMODE :选择色彩模式,对于真彩显示而言,选择16bpp(64K色)即可满足要求。
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显示模式时,视频资料在显示缓冲区中的排列顺序(即低位有效还是高位有效)。对于16bpp的64K色显示模式,该设置位无意义。
FRM565 :对于16bpp显示模式,有2中形式,一种是RGB=5:5:5:1,另一种是5:6:5。后一种模式最为常用,它的含义是表示64K种色彩的16bit RGB资料中,红色(R)占了5bit,绿色(G)占了6bit,蓝色(B)占了5bit
INVVCLK , INVLINE , INVFRAME , INVVD :通过前面的时序图,我们知道,CPU的LCD控制器输出的时序默认是正脉冲,而LCD需要VSYNC(VFRAME)、VLINE(HSYNC)均为负脉冲,因此 INVLINE 和 INVFRAME 必须设为“1 ”,即选择反相输出。
INVVDEN , INVPWREN , INVLEND 的功能同前面的类似。
PWREN 为LCD电源使能控制。在CPU LCD控制器的输出信号中,有一个电源使能管脚LCD_PWREN,用来做为LCD屏电源的开关信号。
ENLEND 对普通的TFT屏无效,可以不考虑。
BSWP 和 HWSWP 为字节(Byte)或半字(Half-Word)交换使能。由于不同的GUI对FrameBuffer(显示缓冲区)的管理不同,必要时需要通过调整 BSWP 和 HWSWP 来适应GUI。

分析之后,我们能否把这LCD弄成模块?如果可以,又怎么弄?(这跟平台设备驱动有很大关系)
1、修改
linux-2.6.24/arch/arm/mach-s3c2410/mach-smdk2410.c

先加头文件

include

include

include

include

include

include

include

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值