本文基于Linux内核版本为4.1.15
介绍
在Linux设备中,LCD显示采用了帧缓冲(framebuffer)技术,LCD驱动也被称为Framebuffer驱动。Framebuffer机制模仿显卡的功能,将显卡硬件结构抽象出来,可以通过对Framebuffer的读写来实现对显存进行操作。用户可以将framebuffer看成是显示内存的一个映像,将其映射到进程地址空间之后,就可以直接进行映射的进程地址空间进行读写操作,而写操作可以立即反应在屏幕上。用户不需要关心物理显存的位置、换页机制等等具体细节。这些都是由framebuffer设备驱动来完成的。
帧缓冲为标准字符设备, 主设备号为29,对应于/dev/fbn。
Framebuffer的框架结构
framebuffer 起着承上启下的作用,向上,为应用层提供通用系统调用(open(),ioctl(),mmap());向下,联接LCD控制器,之前对硬件进行操作。
主要的结构体
使用标准的LCD框架编写,var, fix, fbops, screen_base这四个成员是一定要实现的。
- fb_info
struct fb_info {
atomic_t count;//引用计数,fb_open时加1,release时减1
int node;
int flags;//标志位
struct mutex lock; /* Lock for open/release/ioctl funcs */
struct mutex mm_lock; /* Lock for fb_mmap and smem_* fields */
struct fb_var_screeninfo var;//可变参数 /* Current var */
struct fb_fix_screeninfo fix;//固定参数 /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
struct list_head modelist; /* mode list */
struct fb_videomode *mode; /* current mode */
#ifdef CONFIG_FB_BACKLIGHT
/* assigned backlight device */
/* 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; /* This is the parent */
struct device *dev; //fb设备 /* 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; /* Virtual address */
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;
bool skip_vt_switch; /* no VT switch on suspend/resume required */
};
- fb_var_screeninfo (参数大部分都是要从LCD屏的datasheet中获取)
struct fb_var_screeninfo {
__u32 xres; //可见屏幕一行中的像素点个数 /* visible resolution */
__u32 yres;//可见屏幕一列中的像素点个数
__u32 xres_virtual; //虚拟屏幕一行中的像素点个数 /* virtual resolution */
__u32 yres_virtual;//虚拟屏幕一列中的像素点个数
__u32 xoffset;//虚拟屏幕与实际屏幕的水平偏移 /* offset from virtual to visible */
__u32 yoffset;//虚拟屏幕与实际屏幕的垂直偏移 /* resolution */
__u32 bits_per_pixel;//每个像素的位数即BPP /* guess what */
__u32 grayscale;//0-彩色 1-黑白色 /* 0 = color, 1 = grayscale, */
/* >1 = FOURCC */
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则为非标准像素格式 /* != 0 Non standard pixel format */
__u32 activate; /* see FB_ACTIVATE_* */
__u32 height; /* height of picture in mm */
__u32 width; /* width of picture in mm */
__u32 accel_flags; /* (OBSOLETE) see fb_info.flags */
/* Timing: All values in pixclocks, except pixclock (of course) */
__u32 pixclock; /* pixel clock in ps (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 colorspace; /* colorspace for FOURCC-based modes */
__u32 reserved[4]; /* Reserved for future compatibility */
};
- fb_fix_screeninfo
struct fb_fix_screeninfo {
char id[16];//LCD标识名 /* 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就赋值为0 /* zero 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 capabilities; /* see FB_CAP_* */
__u16 reserved[2]; /* Reserved for future compatibility */
};
- List item
struct fb_ops {
/* open/release and usage marking */
struct module *owner;
int (*fb_open)(struct fb_info *info, int user);//可以不实现,做默认操作
int (*fb_release)(struct fb_info *info, int user);//释放的时候使用
/* For framebuffers with strange non linear layouts or that do not
* work with normal memory mapped access
*/
ssize_t (*fb_read)(struct fb_info *info, char __user *buf,
size_t count, loff_t *ppos);//内存是独立显存的时候才需要使用,直接使用核心层read
ssize_t (*fb_write)(struct fb_info *info, const char __user *buf,
size_t count, loff_t *ppos);//内存是独立显存的时候才需要使用,直接使用核心层write
/* 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);//检测应用程序传递的参数合法性
/* 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);//实现的功能是把内核空间的分配的显存映射到用户空间中对应的mmap系统调用,当你的控制器是独显的时候才需要
/* get capability given var */
void (*fb_get_caps)(struct fb_info *info, struct fb_blit_caps *caps,
struct fb_var_screeninfo *var);
/* teardown any resources to do with this framebuffer */
void (*fb_destroy)(struct fb_info *info);
/* called at KDB enter and leave time to prepare the console */
int (*fb_debug_enter)(struct fb_info *info);
int (*fb_debug_leave)(struct fb_info *info);
};
驱动分析
- 设备树
&lcdif {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_lcdif_dat
&pinctrl_lcdif_ctrl>;
display = <&display0>;
status = "okay";
display0: display {
bits-per-pixel = <16>;
bus-width = <24>;
display-timings {
native-mode = <&timing0>;
timing0: timing0 {
clock-frequency = <35500000>;
hactive = <800>;
vactive = <480>;
hfront-porch = <210>;
hback-porch = <46>;
hsync-len = <20>;
vback-porch = <23>;
vfront-porch = <22>;
vsync-len = <3>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <1>;
/* rgb to hdmi: pixelclk-ative should be set to 1 */
pixelclk-active = <0>;
};
};
};
};
- 装载和卸载函数
static struct platform_driver mxsfb_driver = {
.probe = mxsfb_probe,
.remove = mxsfb_remove,
.shutdown = mxsfb_shutdown,
.id_table = mxsfb_devtype,
.driver = {
.name = DRIVER_NAME,
.of_match_table = mxsfb_dt_ids,
.pm = &mxsfb_pm_ops,
},
};
module_platform_driver(mxsfb_driver);
- probe
static int mxsfb_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(mxsfb_dt_ids, &pdev->dev);
struct resource *res;
struct mxsfb_info *host;
struct fb_info *fb_info;
struct pinctrl *pinctrl;
int irq = platform_get_irq(pdev, 0);//获取中断号
int gpio, ret;
if (of_id)
pdev->id_entry = of_id->data;
gpio = of_get_named_gpio(pdev->dev.of_node, "enable-gpio", 0);
if (gpio_is_valid(gpio)) {
ret = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_OUT_INIT_LOW, "lcd_pwr_en");
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//获取内存空间
host = devm_kzalloc(&pdev->dev, sizeof(struct mxsfb_info), GFP_KERNEL);//申请结构体空间
fb_info = framebuffer_alloc(sizeof(struct fb_info), &pdev->dev);//申请framebuffer
host->fb_info = fb_info;
fb_info->par = host;
ret = devm_request_irq(&pdev->dev, irq, mxsfb_irq_handler, 0,
dev_name(&pdev->dev), host);//申请中断
host->base = devm_ioremap_resource(&pdev->dev, res);//将获取的空间重映射
host->pdev = pdev;
platform_set_drvdata(pdev, host);
host->devdata = &mxsfb_devdata[pdev->id_entry->driver_data];
host->clk_pix = devm_clk_get(&host->pdev->dev, "pix");//获取pix时钟
if (IS_ERR(host->clk_pix)) {
host->clk_pix = NULL;
}
host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");//获取axi时钟
if (IS_ERR(host->clk_axi)) {
host->clk_axi = NULL;
}
host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");//获取disp_axi时钟
if (IS_ERR(host->clk_disp_axi)) {
host->clk_disp_axi = NULL;
}
host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
if (IS_ERR(host->reg_lcd))
host->reg_lcd = NULL;
fb_info->pseudo_palette = devm_kzalloc(&pdev->dev, sizeof(u32) * 16,
GFP_KERNEL);
INIT_LIST_HEAD(&fb_info->modelist);
pm_runtime_enable(&host->pdev->dev);//功耗相关
ret = mxsfb_init_fbinfo(host);//初始化固定参数和可变参数
mxsfb_dispdrv_init(pdev, fb_info);
if (!host->dispdrv) {
pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
}
if (!host->enabled) {
writel(0, host->base + LCDC_CTRL);
mxsfb_set_par(fb_info);
mxsfb_enable_controller(fb_info);
pm_runtime_get_sync(&host->pdev->dev);
}
ret = register_framebuffer(fb_info);//注册fb_info
console_lock();
ret = fb_blank(fb_info, FB_BLANK_UNBLANK);
console_unlock();
}
屏幕的各种操作函数是在mxsfb_init_fbinfo()中进行的赋值。
static struct fb_ops mxsfb_ops = {
.owner = THIS_MODULE,
.fb_check_var = mxsfb_check_var,
.fb_set_par = mxsfb_set_par,
.fb_setcolreg = mxsfb_setcolreg,
.fb_ioctl = mxsfb_ioctl,
.fb_blank = mxsfb_blank,
.fb_pan_display = mxsfb_pan_display,
.fb_mmap = mxsfb_mmap,
.fb_fillrect = cfb_fillrect,
.fb_copyarea = cfb_copyarea,
.fb_imageblit = cfb_imageblit,
};