⑥tiny4412 Linux驱动开发之LCD(framebuffer)驱动程序

友善之臂对这个的支持还是比较坑的,我买的开发板用的是X710屏,我嘞个去,没有X710的datasheet,网上也找不到,只能另辟蹊径了,幸好,友善提供的源代码里有X710的配置参数,然后也可以顺利地显示出自己定制化的开机logo.

在说驱动之前,我们先来看一下框架知识,和以往驱动不同的是,这里用到了framebuffer,如下图是用framebuffer和以往驱动的差异的框架图:


如上,开发LCD驱动一般的做法就是上面两种形式,当然,也可以通过块设备的方式进行开发,这里主要讲字符形式的开发,后边有机会的话,用块设备驱动的形式做做,然后再分享.

以往字符设备一般分为3层,驱动控制层,驱动核心层和驱动适配器层.而framebuffer则简化为了两层,以方便快速开发,和减少开发人员的工作量,常见的驱动操作数据的形式就是copy_from_user()和copy_to_user(),这样的形式,可以实现对用户层和驱动层之间的隔离和区分管控,但是特殊情况则特殊对待,LCD我们一般应用的场景都是播放连续的画面,这就是形成目前视频播放的原理,目前的视频就是由一张一张连续的画面连续的显示得到的,一般视频都是数据量比较大,经典驱动架构copy_from_user()则对此是低效的方式,因为要把数据转移两遍,第一遍是从用户空间拷贝到内核空间,第二遍是从内核空间拷贝到物理器件(这里是LCD控制器),这种方式对于小数据量是没问题的,但是对于视频这种大数据量时,则会增加内核的负载和CPU的负载,因为这种转移是依靠CPU来实现的,所以为了针对视频这种特殊情况,Linux调整了视频驱动的架构,直接把本该内核操作的内存地址透明给用户空间,使用户空间直接给相应的内存数据,同时为了减轻CPU搬运数据的负担,一般SOC都是有集成DMA外设的,比如我们使用这款exynos 4412就具备,所以,在这里对于视频数据,我们采用映射DMA内存的方式搬运数据,以腾出CPU去做别的事情,而这块被映射的DMA内存的视频缓冲区则称之为显存,我们这里使用的是映射到RAM的显存,属于集成显存,还有一种叫独立显存,比如独立显卡,嵌入式设备为了节约成本,一般不用独立显存,同时,也视频架构除了帧缓冲之外,还用一种控制台的形式的驱动,比如VGA控制台,这里则只介绍framebuffer帧缓冲.

我们回到实际开发中,我先来说一下,这块开发的分工:

framebuffer核心层---->Linux内核完成(fbmem.c)

LCD控制器层---------->芯片原厂完成(这里是三星提供, s3c-fb.c)

LCD屏物理参数-------->我们自己添加(tiny4412-lcds.c)

我们需要做的就是只有一点,就是添加平台总线数据,因为这个芯片的LCD控制器只有一个,而LCD屏则可以使多选的,比如我们可以使用5寸的也可以使用7寸的,这两者肯定是有一定的差异的,有差异,就可以采取数据总线的形式,这里就是,LCD驱动采用了数据总线,我们根据自己的屏幕的实际物理特性,把相关参数添加到已经构件的总台总线的驱动数据层即可.

tiny4412的平台自定义数据在mach-tiny4412.c里面,我们直接搜fb即可,然后会在smdk4x12_machine_init()里面发现如下代码:

#ifdef CONFIG_TOUCHSCREEN_FT5X0X
	struct s3cfb_lcd *lcd = tiny4412_get_lcd();
	ft5x0x_pdata.screen_max_x = lcd->width;
	ft5x0x_pdata.screen_max_y = lcd->height;
#endif

其中的tiny4412_get_lcd()就是获取屏幕的参数的,这个函数定义在tiny4412-lcds.c,可以从这个c文件中发现X710屏幕的参数信息:

static struct s3cfb_lcd wsvga_x710 = {
	.width = 1024,			// 水平像素
	.height = 600,			// 垂直像素
	.p_width = 154,			// 物理水平尺寸
	.p_height = 90,			// 物理垂直尺寸,16:9
	.bpp = 24,			// 像素位宽,RGB888
	.freq = 61,			// 帧率

	.timing = {
		.h_fp = 84,		// 水平前肩,水平无效时间
		.h_bp = 84,		// 水平折返时间
		.h_sw = 88,		// 水平稳定时间
		.v_fp = 10,		// 垂直无效时间
		.v_fpe = 1,		// 均匀场垂直前肩
		.v_bp = 10,		// 垂直折返时间
		.v_bpe = 1,		// 均匀场垂直后肩
		.v_sw = 20,		// 垂直稳定时间
	},
	.polarity = {
		.rise_vclk = 1,		// 上升沿数据有效
		.inv_hsync = 1,		// 水平极性反转
		.inv_vsync = 1,		// 垂直极性反转
		.inv_vden = 0,		// 数据使能
	},
};

实际开发中,我们的工作量就是上面这么多,就这几个参数,别的都是要么Linux内核提供,要么芯片原厂提供,大大减小LCD驱动开发的难度,上面这些参数,一般响应屏幕的datasheet上会写出来,但这是个X710的,我没找到,不过,还是可以透过这个配置信息知道这个屏幕的属性,首先屏幕的分辨率是1024*600,物理尺寸是154x90(mm)接近于16:9,像素位宽是24,也就是RGB三原色各占8位,帧率从上面的数据可以大概算一下,接近于61Hz,一般也都要求至少60Hz才对人眼不会造成眩晕.然后timing结构体里的数据都是要datasheet上提供的,但是下载不到这个datasheet,这里没什么好说的,我都有写注释,自己可以百度到详细答案.polarity结构体里的东西也给了注释,就不多说了.填完这个之后,我们来验证一下效果,需要做以下事情:

1).让内核加载适合我们屏幕的参数:

这一步很坑,因为我根本没找到在哪里去做配置,这个内核没有使用设备树,然后也没有向全志一样使用script.bin的形式配置,make menuconfig也没找到在哪里配置,然后看到顶层目录的.config文件里有一个uboot传参的句式:

CONFIG_CMDLINE="root=/dev/mmcblk0p2 rootfstype=ext4 init=/linuxrc console=ttySAC0,115200 lcd=HD700 ctp=2 skipcali=y"

然后知道应该是可以通过uboot进行选择,但是,我这里直接了当,因为配置都是通过tiny4412_get_lcd()这个函数来获取的,所以,我直接修改这个函数即可,做如下修改:

struct s3cfb_lcd *tiny4412_get_lcd(void)
{
+++	lcd_idx = 7;
	return tiny4412_lcd_config[lcd_idx].lcd;
}

其中新增加一句lcd_idx = 7;是因为X710是可选配置结构体里的第7个,这样.我们就选中了我们的屏幕X710.

2),配置了LCD之后,我们来验证一下LCD是否有效可用

最简单的方式就是打开启动logo,如果开机有启动logo,就说明配置成功,如下,首先make menuconfig:



画红框的都要选中,然后,重新编译内核,把新生成的zImage下载到内存卡,从内存卡启动,然后,如果顺利的话,就可以看到4个小企鹅了,一个核心对应一个小企鹅,4个代表有4颗核心,8个则代表8核心,以此类推.

下面这张图是填参数的依据,因为这里没有找到X710的datasheet,所以,这里就不讲这些了,不过如上都是有注明什么对应什么的,一般看一下,就可以明白了.(从左到右,从上到下依次是SOC的LCD控制器时序图,LCD屏幕datasheet时序图,Linux内核定义的时序图,就这3个,第4个和第2个是一个,别看错了,它们虽然名字不同,但是却是描述的同一个物理特性)


除了这些之外,我们还来做一个自己定制化的启动logo,玩一下,需要如下步骤:

1, 网上随便下载一张图片,比如jpg格式的,然后,我们通过GIMP软件把图片
像素修改成1028x600大小,位色改为224色,然后保存为ppm格式的ASCii文件

2, 把ppm图片放在如下路径drivers/video/logo/logo_meizi_clut224.ppm

3, drivers/video/logo/Makefile
	obj-$(CONFIG_LOGO_MEIZI_CLUT224)	+= logo_meizi_clut224.o
	
4, drivers/video/logo/Kconfig
		config LOGO_MEIZI_CLUT224
		bool "Meizi Logo is very beautiful"
		help 
			meizi meizi ,sexy lady
	
5,将logo文件编译进内核:
	Device Drivers  --->
		Graphics support  --->
			[*] Bootup logo  ---> //提供启动的图片
				[*]   Standard black and white Linux logo (NEW)
				[*]   Standard 16-color Linux logo (NEW)
				[*]   Standard 224-color Linux logo (NEW) //默认小企鹅图片
				[*]   Meizi Logo is very beautiful
		
6, 指定使用哪个logo:
	include/linux/linux_logo.h
		extern const struct linux_logo logo_meizi_clut224;


	drivers/video/logo/logo.c
		|
		#ifdef CONFIG_LOGO_MEIZI_CLUT224
		            logo = &logo_meizi_clut224;
		#endif
7, 编译内核:
	make zImage 
下载zImage到内存卡,然后启动就OK了.(因为uboot没有移植好,没法通过tftp下载,烧进mmc又麻烦,有机会再搞一下uboot).

猜你喜欢

转载自blog.csdn.net/qq_23922117/article/details/80554990