美文网首页
LCD驱动分析

LCD驱动分析

作者: 章辉_8bef | 来源:发表于2019-01-14 19:28 被阅读0次

    内核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本身
    • 使能背光

    相关文章

      网友评论

          本文标题:LCD驱动分析

          本文链接:https://www.haomeiwen.com/subject/jkhddqtx.html