Framebuffer简介
在Linux设备中,LCD显示采用了帧缓冲(framebuffer)技术,所以LCD驱动也叫Framebuffer驱动,所以LCD驱动框架就是围绕帧缓冲展开工作。帧缓冲(framebuffer)是Linux系统为显示设备提供的一个接口,它将显示缓冲区抽象出来,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。帧缓冲为标准字符设备, 主设备号为29,对应于/dev/fbn。
Framebuffer框架结构

核心层代码fbmem.c向上提供了完整的字符设备操作接口,也就是实现注册字符设备,提供通用的open,read,write,ioctl,mmap等接口;向下给硬件设备驱动层提供标准的驱动编程接口。
在linux系统中,一个硬件控制器(显卡)抽象为一个fb_info结构体,要实现一个LCD驱动就是要实现这个结构,并且使用核心层提供的注册函数注册。
重要结构体
内核版本:4.20.12
struct fb_info {
atomic_t count;
int node;
int flags;
int fbcon_rotate_hint;
struct mutex lock;
struct mutex mm_lock;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
struct fb_monspecs monspecs;
struct work_struct queue;
struct fb_pixmap pixmap;
struct fb_pixmap sprite;
struct fb_cmap cmap;
struct list_head modelist;
struct fb_videomode *mode;
#ifdef CONFIG_FB_BACKLIGHT
struct backlight_device *bl_dev;
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;
int class_flag;
#ifdef CONFIG_FB_TILEBLITTING
struct fb_tile_ops *tileops;
#endif
union {
char __iomem *screen_base;
char *screen_buffer;
};
unsigned long screen_size;
void *pseudo_palette;
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1
u32 state;
void *fbcon_par;
void *par;
struct apertures_struct {
unsigned int count;
struct aperture {
resource_size_t base;
resource_size_t size;
} ranges[0];
} *apertures;
bool skip_vt_switch;
};
使用标准的LCD框架编写,var, fix, fbops, screen_base这四个成员是一定要实现的。
struct fb_var_screeninfo {
__u32 xres;
__u32 yres;
__u32 xres_virtual;
__u32 yres_virtual;
__u32 xoffset;
__u32 yoffset;
__u32 bits_per_pixel;
__u32 grayscale;
struct fb_bitfield red;
struct fb_bitfield green;
struct fb_bitfield blue;
struct fb_bitfield transp;
__u32 nonstd;
__u32 activate;
__u32 height;
__u32 width;
__u32 accel_flags;
__u32 pixclock;
__u32 left_margin;
__u32 right_margin;
__u32 upper_margin;
__u32 lower_margin;
__u32 hsync_len;
__u32 vsync_len;
__u32 sync;
__u32 vmode;
__u32 rotate;
__u32 colorspace;
__u32 reserved[4];
};
上面结构体的参数大部分都是要从LCD屏的datasheet中获取。
struct fb_fix_screeninfo {
char id[16];
unsigned long smem_start;
__u32 smem_len;
__u32 type;
__u32 type_aux;
__u32 visual;
__u16 xpanstep;
__u16 ypanstep;
__u16 ywrapstep;
__u32 line_length;
unsigned long mmio_start;
__u32 mmio_len;
__u32 accel;
__u16 capabilities;
__u16 reserved[2];
};
struct fb_ops {
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);
int (*fb_release)(struct fb_info *info, int user);
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos);
int (*fb_check_var)(struct fb_var_screeninfo *var, struct fb_info *info);
int (*fb_set_par)(struct fb_info *info);
int (*fb_setcolreg)(unsigned regno, unsigned red, unsigned green,
unsigned blue, unsigned transp, struct fb_info *info);
int (*fb_setcmap)(struct fb_cmap *cmap, struct fb_info *info);
int (*fb_blank)(int blank, struct fb_info *info);
int (*fb_pan_display)(struct fb_var_screeninfo *var, struct fb_info *info);
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
int (*fb_cursor) (struct fb_info *info, struct fb_cursor *cursor);
int (*fb_sync)(struct fb_info *info);
int (*fb_ioctl)(struct fb_info *info, unsigned int cmd,
unsigned long arg);
int (*fb_compat_ioctl)(struct fb_info *info, unsigned cmd,
unsigned long arg);
int (*fb_mmap)(struct fb_info *info, struct vm_area_struct *vma);
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);
void (*fb_destroy)(struct fb_info *info);
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};
常用的重要成员:
- fb_open:当你的lcd不需要做什么特殊的初始化操作,这个方法可以不实现
- fb_release:当你的应用程序不使用lcd设备的时候,需要做的事情在这里实现
- fb_read:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层read
- fb_write:当你的lcd控制器使用的内存是独立显存的时候才需要使用,直接使用核心层write
- fb_check_var:检测应用程序传递下来的可变参数是否合法。当你不提供给应用程序通过ioctl命令动态修改LCD可变参数时不需要实现。
- fb_set_par:实现的功能是把可变参数设置到硬件寄存器中去
- fb_blank:实现屏幕的黑屏白屏模式(开屏,关屏)
- fb_fillrect:实现功能是填充矩形
- fb_copyarea:实现功能是区域复制
- fb_imageblit:实现功能是绘制位图
- fb_mmap:实现的功能是把内核空间的分配的显存映射到用户空间中对应的mmap系统调用,当你的控制器是独显的时候才需要
API函数
int register_framebuffer(struct fb_info *fb_info)
int unregister_framebuffer(struct fb_info *fb_info)
void *dma_alloc_writecombine(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t flag)
void dma_free_writecombine(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_handle)
lcd每屏显示的数据量很大,所以lcd一般是利用DMA来搬运数据,而DMA模块只会使用物理地址,所以LCD驱动中需要记录物理地址。
总结
上面的结构体中有很多参数,对于一些普通的LCD屏,需要用到的参数并不多。主要就是从数据手册中获取屏幕参数信息,填充fb_info,然后注册。另一部分就LCDC的寄存器配置。目前很多原厂会将这两部分进行分离,这样就更方便客户进行定制。