LCD驱动(Framebuffer)

本文基于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,
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值