1. eLCDIF设备树
lcdif: lcdif@021c8000 {compatible = "fsl,imx6ul-lcdif", "fsl,imx28-lcdif"; //属性reg = <0x021c8000 0x4000>; //起始地址 地址大小interrupts = <GIC_SPI 5 IRQ_TYPE_LEVEL_HIGH>; //中断clocks = <&clks IMX6UL_CLK_LCDIF_PIX>, //时钟子系统<&clks IMX6UL_CLK_LCDIF_APB>,<&clks IMX6UL_CLK_DUMMY>;clock-names = "pix", "axi", "disp_axi"; //系统名称status = "disabled"; //状态};
* Freescale MXS LCD Interface (LCDIF)Required properties:
- compatible: Should be "fsl,<chip>-lcdif". Supported chips includeimx23 and imx28.
- reg: Address and length of the register set for lcdif
- interrupts: Should contain lcdif interrupts
- display : phandle to display node (see below for details)* display nodeRequired properties:
- bits-per-pixel : <16> for RGB565, <32> for RGB888/666.
- bus-width : number of data lines. Could be <8>, <16>, <18> or <24>.Required sub-node:
- display-timings : Refer to binding doc display-timing.txt for details.+----------+-------------------------------------+----------+-------+| | ↑ | | || | |vback_porch | | || | ↓ | | |+----------#######################################----------+-------+| # ↑ # | || # | # | || hback # | # hfront | hsync || porch # | hactive # porch | len ||<-------->#<-------+--------------------------->#<-------->|<----->|| # | # | || # |vactive # | || # | # | || # ↓ # | |+----------#######################################----------+-------+| | ↑ | | || | |vfront_porch | | || | ↓ | | |+----------+-------------------------------------+----------+-------+| | ↑ | | || | |vsync_len | | || | ↓ | | |+----------+-------------------------------------+----------+-------+Examples:&lcdif@80030000 {pinctrl-names = "default"; //pinctrl 名字pinctrl-0 = <&pinctrl_lcdif_dat //pinctrl 子系统&pinctrl_lcdif_ctrl&pinctrl_lcdif_reset>;display = <&display0>; status = "okay"; //状态display: display { //子节点bits-per-pixel = <32>; //每个像素点大小bus-width = <24>; //总线宽度display-timings { //display-timing子节点native-mode = <&timing0>;timing0: timing0 {clock-frequency = <33500000>; //时钟频率hactive = <800>; //水平显示分别率vactive = <480>; //垂直显示分别率hfront-porch = <164>; //水平方向前肩hback-porch = <89>; //水平方向后肩hsync-len = <10>; //水平脉冲宽度vback-porch = <23>; //垂直方向后肩vfront-porch = <10>; //垂直方向前肩 vsync-len = <10>; //垂直脉冲宽度hsync-active = <0>; //水平方向有效脉冲极性vsync-active = <0>; //垂直方向有效脉冲极性de-active = <1>; //使能有效极性pixelclk-active = <0>; //像素时钟边沿采样有效性};};};
};
2. 相关数据结构
(1)struct fb_info
Linux内核中使用fb_info结构体变量来描述一个framebuffer,在调用register_framebuffer接口注册framebuffer之前,必须要初始化其中的重要数据成员。
struct fb_info中成员众多,我们需要着重关注以下成员:
fb_var_screeninfo:代表可修改的LCD显示参数,如分辨率和像素比特数等;
fb_fix_screeninfo:代表不可修改的LCD属性参数,如显示内存的物理地址和长度等;
fb_ops:LCD底层硬件操作接口集。
struct fb_info
{int node; //用来表示该fb设备的次设备号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 */ // fb的可变参数struct fb_fix_screeninfo fix; /* Current fix */ // fb的不可变参数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_IOstruct delayed_work deferred_work;struct fb_deferred_io *fbdefio;
#endifstruct fb_ops *fbops; // 该设备对应的操作方法struct device *device; /* This is the parent */ //fb设备的父设备struct device *dev; /* This is this fb device */ //本设备的deviceint class_flag; /* private sysfs flags */
#ifdef CONFIG_FB_TILEBLITTINGstruct fb_tile_ops *tileops; /* Tile Blitting */
#endifchar __iomem *screen_base; /* Virtual address */ //LCD的显存地址(虚拟地址) unsigned long screen_size; /* Amount of ioremapped VRAM or 0 */// LCD显存的字节大小void *pseudo_palette; /* Fake palette of 16 colors */
#define FBINFO_STATE_RUNNING 0
#define FBINFO_STATE_SUSPENDED 1u32 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 similiar aperture base/size notsmem_start/size as smem_start may just be an objectallocated 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;
};struct fb_info
(2)struct fb_var_screeninfo
Linux内核中使用struct fb_var_screeninfo来描述可修改的LCD显示参数,如分辨率和像素比特数等。
struct fb_var_screeninfo
{__u32 xres; // 水平分辨率 __u32 yres; // 垂直分辨率__u32 xres_virtual; // 虚拟水平分辨率__u32 yres_virtual; // 虚拟垂直分辨率__u32 xoffset; // 当前显存水平偏移量__u32 yoffset; // 当前显存垂直偏移量__u32 bits_per_pixel; // 像素深度__u32 grayscale; /* != 0 Graylevels instead of colors */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 Non standard pixel format */__u32 activate; /* see FB_ACTIVATE_* */__u32 height; // LCD的物理高度mm__u32 width; // LCD的物理宽度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) */ // 像素时钟//下面这六个就是LCD的时序参数__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 reserved[5]; /* Reserved for future compatibility */
};struct fb_var_screeninfo
(3)struct fb_fix_screeninfo
Linux内核中使用struct fb_fix_screeninfo来描述不可修改的LCD属性参数,如显示内存的物理地址和长度等。
struct fb_fix_screeninfo
{char id[16]; /* identification string eg "TT Builtin" */unsigned long smem_start; // LCD显存的起始地址(物理地址)/* (physical address) */__u32 smem_len; /* Length of frame buffer mem */// LCD显存的字节大小__u32 type; /* see FB_TYPE_**/__u32 type_aux; /* Interleave for interleaved Planes */__u32 visual; /* see FB_VISUAL_* */ __u16 xpanstep; /* zero if no hardware panning */__u16 ypanstep; /* zero if no hardware panning */__u16 ywrapstep; /* zero if no hardware ywrap */__u32 line_length; /* length of a line in bytes */// LCD一行的长度 (以字节为单位)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 reserved[3]; /* Reserved for future compatibility */
};struct fb_fix_screeninfo
3. fbmem.c
3.1 入口函数
FrameBuffer驱动是以模块的形式注册到系统中,在模块初始化时,创建FrameBuffer对应的设备文件及proc文件,并注册FrameBuffer设备操作接口函数fb_fops。
static int __init
fbmem_init(void)
{proc_create("fb", 0, NULL, &fb_proc_fops); //向 proc 文件系统报告驱动状态和参数if (register_chrdev(FB_MAJOR,"fb",&fb_fops)) //注册字符设备驱动,主设备号是29 名称为fbprintk("unable to get major %d for fb devs\n", FB_MAJOR);fb_class = class_create(THIS_MODULE, "graphics"); //创建 /sys/class/graphics 设备类,配合 mdev生成设备文件if (IS_ERR(fb_class)) {printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));fb_class = NULL;}return 0;
}
3.2 fb_fops
在linux设备驱动中,所有的显示缓存设备均由framebuffer子系统内部管理,即linux设备驱动框架只认识一个主设备号为29的framebuffer设备。应用层所有针对显示缓存(最多32个)的访问均会推送给fb_fops进行进一步分发操作。
static const struct file_operations fb_fops = {.owner = THIS_MODULE,.read = fb_read,.write = fb_write,.unlocked_ioctl = fb_ioctl,
#ifdef CONFIG_COMPAT.compat_ioctl = fb_compat_ioctl,
#endif.mmap = fb_mmap,.open = fb_open,.release = fb_release,
#ifdef HAVE_ARCH_FB_UNMAPPED_AREA.get_unmapped_area = get_fb_unmapped_area,
#endif
#ifdef CONFIG_FB_DEFERRED_IO.fsync = fb_deferred_io_fsync,
#endif.llseek = default_llseek,
};
3.2.1 fb_open
3.2.2 fb_mmap
3.2.3 fb_ioctl
static long do_fb_ioctl(struct fb_info *info, unsigned int cmd,unsigned long arg)
{struct fb_ops *fb;struct fb_var_screeninfo var;struct fb_fix_screeninfo fix;struct fb_con2fbmap con2fb;struct fb_cmap cmap_from;struct fb_cmap_user cmap;struct fb_event event;void __user *argp = (void __user *)arg;long ret = 0;switch (cmd) {case FBIOGET_VSCREENINFO: // 获取可变屏幕参数if (!lock_fb_info(info))return -ENODEV;var = info->var;unlock_fb_info(info);ret = copy_to_user(argp, &var, sizeof(var)) ? -EFAULT : 0;break;case FBIOPUT_VSCREENINFO: // 设置可变屏幕参数if (copy_from_user(&var, argp, sizeof(var)))return -EFAULT;console_lock();if (!lock_fb_info(info)) {console_unlock();return -ENODEV;}info->flags |= FBINFO_MISC_USEREVENT;ret = fb_set_var(info, &var);info->flags &= ~FBINFO_MISC_USEREVENT;unlock_fb_info(info);console_unlock();if (!ret && copy_to_user(argp, &var, sizeof(var)))ret = -EFAULT;break;case FBIOGET_FSCREENINFO: //获得固定的屏幕参数设置if (!lock_fb_info(info))return -ENODEV;fix = info->fix;unlock_fb_info(info);ret = copy_to_user(argp, &fix, sizeof(fix)) ? -EFAULT : 0;break;case FBIOPUTCMAP: // 获得固定的屏幕参数设置if (copy_from_user(&cmap, argp, sizeof(cmap)))return -EFAULT;ret = fb_set_user_cmap(&cmap, info);break;case FBIOGETCMAP: // 获得颜色表if (copy_from_user(&cmap, argp, sizeof(cmap)))return -EFAULT;if (!lock_fb_info(info))return -ENODEV;cmap_from = info->cmap;unlock_fb_info(info);ret = fb_cmap_to_user(&cmap_from, &cmap);break;case FBIOPAN_DISPLAY: // 平移显示if (copy_from_user(&var, argp, sizeof(var)))return -EFAULT;console_lock();if (!lock_fb_info(info)) {console_unlock();return -ENODEV;}ret = fb_pan_display(info, &var);unlock_fb_info(info);console_unlock();if (ret == 0 && copy_to_user(argp, &var, sizeof(var)))return -EFAULT;break;case FBIO_CURSOR:ret = -EINVAL;break;case FBIOGET_CON2FBMAP:if (copy_from_user(&con2fb, argp, sizeof(con2fb)))return -EFAULT;if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)return -EINVAL;con2fb.framebuffer = -1;event.data = &con2fb;if (!lock_fb_info(info))return -ENODEV;event.info = info;fb_notifier_call_chain(FB_EVENT_GET_CONSOLE_MAP, &event);unlock_fb_info(info);ret = copy_to_user(argp, &con2fb, sizeof(con2fb)) ? -EFAULT : 0;break;case FBIOPUT_CON2FBMAP:if (copy_from_user(&con2fb, argp, sizeof(con2fb)))return -EFAULT;if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES)return -EINVAL;if (con2fb.framebuffer >= FB_MAX)return -EINVAL;if (!registered_fb[con2fb.framebuffer])request_module("fb%d", con2fb.framebuffer);if (!registered_fb[con2fb.framebuffer]) {ret = -EINVAL;break;}event.data = &con2fb;console_lock();if (!lock_fb_info(info)) {console_unlock();return -ENODEV;}event.info = info;ret = fb_notifier_call_chain(FB_EVENT_SET_CONSOLE_MAP, &event);unlock_fb_info(info);console_unlock();break;case FBIOBLANK:console_lock();if (!lock_fb_info(info)) {console_unlock();return -ENODEV;}info->flags |= FBINFO_MISC_USEREVENT;ret = fb_blank(info, arg);info->flags &= ~FBINFO_MISC_USEREVENT;unlock_fb_info(info);console_unlock();break;default:if (!lock_fb_info(info))return -ENODEV;fb = info->fbops;if (fb->fb_ioctl)ret = fb->fb_ioctl(info, cmd, arg);elseret = -ENOTTY;unlock_fb_info(info);}return ret;
}
4. mxsfb.c
一个标准的platform平台设备驱动