美文网首页
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