LCD驱动分析

内核LCD框架分析

最近在看韦佬的LCD驱动部分的视频,韦佬对内核自带的LCD驱动框架的讲解较少,所以在此先分析一下内核自带的LCD驱动框架。
内核自带的LCD驱动框架依然符合分层分离驱动模型,不再复述分离分层驱动模型,直接分析LCD的驱动框架。

20151218164722354.png

1 相关文件

  • 核心层
    fbmem.c
  • driver
    s3c2410fb.c
  • device
    mach-smdk2440.c
    fb.h

2 核心层 fbmem.c

核心层提供了标准的lcd接口函数和注册函数

  • fbmem_init()(驱动入口函数)
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))     //注册字符设备驱动
        printk("unable to get major %d for fb devs\n", FB_MAJOR);

    fb_class = class_create(THIS_MODULE, "graphics");
    if (IS_ERR(fb_class)) {
        printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
        fb_class = NULL;
/* 此时没有创建设备节点 */
  • fb_open()
    根据次设备号查找registered_fb[fbidx]里面的info结构体,如果info结构体的fops里面有open函数,则调用。
int fbidx = iminor(inode);
    struct fb_info *info;    
info = registered_fb[fbidx] // 从registered_fb中获取到LCD信息
                if (info->fbops->fb_open) {
                    res = info->fbops->fb_open(info,1);
                    if (res)
                        module_put(info->fbops->owner);
/* 调用info结构体里面的open函数 */
/*  lcd.c里面没有实现open函数 */
  • fb_read()
int fbidx = iminor(inode);
struct fb_info *info = registered_fb[fbidx];
if (info->fbops->fb_read)
        return info->fbops->fb_read(info, buf, count, ppos);
  • register_framebuffer
    提供注册函数,创建设备节点
for (i = 0 ; i < FB_MAX; i++)
         if (!registered_fb[i])
             break;
    fb_info->node = i;  //查找空数组
    fb_info->dev = device_create(fb_class, fb_info->device,
                     MKDEV(FB_MAJOR, i), "fb%d", i);         //   此时创建设备节点
  ...
                registered_fb[i] = fb_info; // 注册fb_info结构体,即放入数组registered_fb[i]

3 driver层 s3c2410fb.c

平台驱动,驱动中稳定的部分

  • s3c2410fb_init :
platform_driver_register(&s3c2410fb_driver);  //注册平台设备
  • 构造platform_driver结构体
static struct platform_driver s3c2410fb_driver = {    
        .probe      = s3c2410fb_probe,
        .remove     = s3c2410fb_remove,
        .suspend    = s3c2410fb_suspend,
        .resume     = s3c2410fb_resume,
        .driver     = {
            .name   = "s3c2410-lcd",
            .owner  = THIS_MODULE,
        },
};  // 按照分离分层驱动模型,是按照名字与device进行匹配
/*   分离分层驱动模型 : driver,device匹配上就执行probe函数 */
  • s3c2410fb_probe(struct platform_device *pdev)

1分配一个info结构体
2设置info结构体
3硬件相关的操作
4注册info结构体

mach_info = pdev->dev.platform_data;  //获取lcd数据
fbinfo = framebuffer_alloc(sizeof(struct s3c2410fb_info), &pdev->dev);  
/*分配一个fbinfo结构体*/
strcpy(fbinfo->fix.id, driver_name);
fbinfo->fbops = &s3c2410fb_ops;   
...
/*设置info结构体  名字,操作函数等*/
ret = request_irq(irq, s3c2410fb_irq, IRQF_DISABLED, pdev->name, info);
info->clk = clk_get(NULL, "lcd"); 
/* 硬件操作 */
        ret = register_framebuffer(fbinfo);
/* 注册info结构体,同时创建设备节点*/

4 device 层 mach-smdk2440.c fb.h

平台设备,提供设备信息

static struct s3c2410fb_mach_info smdk2440_lcd_cfg __initdata = {
    .regs   = {
        .lcdcon1    = S3C2410_LCDCON1_TFT16BPP |
                      S3C2410_LCDCON1_TFT |
                      S3C2410_LCDCON1_CLKVAL(0x04),
        .lcdcon2    = S3C2410_LCDCON2_VBPD(7) |
                      S3C2410_LCDCON2_LINEVAL(319) |
                      S3C2410_LCDCON2_VFPD(6) |
                      S3C2410_LCDCON2_VSPW(3),

        .lcdcon3    = S3C2410_LCDCON3_HBPD(19) |
                      S3C2410_LCDCON3_HOZVAL(239) |
                      S3C2410_LCDCON3_HFPD(7),

        .lcdcon4    = S3C2410_LCDCON4_MVAL(0) |
                      S3C2410_LCDCON4_HSPW(3),

        .lcdcon5    = S3C2410_LCDCON5_FRM565 |
                      S3C2410_LCDCON5_INVVLINE |
                      S3C2410_LCDCON5_INVVFRAME |
                      S3C2410_LCDCON5_PWREN |
                      S3C2410_LCDCON5_HWSWP,
    },
    ...
};

5 fb_info结构体

struct fb_info {
    atomic_t count;
    int node;             //子设备号
    int flags;
    struct mutex lock;        //互斥锁
    struct mutex mm_lock;        /* Lock for fb_mmap and smem_* fields */
    struct fb_var_screeninfo var;    //当前缓冲区的可变参数
    struct fb_fix_screeninfo fix;    //固定参数
    struct fb_monspecs monspecs;    //当前显示器标志
    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      
    /* assigned backlight device *//支持lcd背光的设置
    /* set before framebuffer registration, 
     remove after unregister */
    struct backlight_device *bl_dev;  

    /* Backlight level curve */
    struct mutex bl_curve_mutex;    
    u8 bl_curve[FB_BACKLIGHT_LEVELS];
#endif
#ifdef CONFIG_FB_DEFERRED_IO
    struct delayed_work deferred_work;
    struct fb_deferred_io *fbdefio;
#endif

    struct fb_ops *fbops;     //帧缓冲操作函数集
    struct device *device;        //父设备
    struct device *dev;        /* This is this fb device */
    int class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTING
    struct fb_tile_ops *tileops; /* Tile Blitting */
#endif
    char __iomem *screen_base;    //虚拟基地址
    unsigned long screen_size;    /* Amount of ioremapped VRAM or 0 */ 
    void *pseudo_palette;        /* Fake palette of 16 colors */ 
#define FBINFO_STATE_RUNNING    0
#define FBINFO_STATE_SUSPENDED    1
    u32 state;            /* Hardware state i.e suspend */
    void *fbcon_par; /* fbcon use-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 an object
     allocated inside the aperture so may not actually overlap */
    struct apertures_struct {
        unsigned int count;
        struct aperture {
            resource_size_t base;
            resource_size_t size;
        } ranges[0];
    } *apertures;
};

如何自己写LCD驱动程序

基本是按照probe函数里面的步骤
1 分配一个fb_info结构体,framebuffer_alloc
2 设置
3 注册 : register_framebuffer
4 硬件相关的操作

LCD硬件操作

LCD硬件操作的步骤:设置芯片的LCD控制器部分的寄存器,对照LCD的芯片手册设置即可

1 设置水平方向时间参数

  • HBPD : HSYNC之后过多长时间发出第1个像素的数据(左黑边)
  • 多少列:HOZVAL
  • HFPD : 发出一行里最后一个像素之后再过多长时间才发出HSYNC(右黑边)
  • HSPW :HSYNC信号的脉冲宽度

2 设置垂直方向的时间参数

  • VBPD : VSYNC之后过多长时间发出第一行数据(上黑边)
  • 多少行:LINEVAL
  • VFPD 发出最后一行数据之后再过多长时间才发出VSYNC(下黑边)
  • VSPW: VSYNC信号的脉冲宽度

3 设置LCD的其他参数

  • VCLK : 设置LCD的时钟
  • bpp : 设置像素的位数
  • 设置framebuffer的数据格式

4 设置信号的极性

  • HYSNC反转
  • VYSNC反转
  • video data 反转
  • VDEN 反转
  • ...

5 分配framebuffer

  • dma_alloc_writecombine分配内存
  • 物理地址赋值给芯片的寄存器

6 启动LCD

  • 使能LCD控制器
  • 使能LCD本身
  • 使能背光
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容