您的位置:首页 > 运维架构 > Linux

个人总结日记:ltv350三星LCD并行接口接2440处理器的linux驱动程序移植

2014-12-23 20:42 856 查看
ltv350三星LCD并行接口接2440处理器的linux驱动程序移植

总体上分三步:

1> framebuffer_alloc函数分配一个fb_info类型的结构体

该结构体用于填充描述使用的液晶参数,比如像 像素类型,是否有硬件加速,

长宽,每个像素的位数,调色板等。

其中主要填充fix与var这两个成员结构体变量,这两个结构体在应用程序中

可以通过ioctl函数的命令字 FBIOGET_VSCREENINFO与FBIOGET_FSCREENINFO

获取这两个结构体。

填充一个结构体fb_ops类型的变量,并让fb_info结构体成员指针fbops指向该

变量。fb_ops需要完成如下设置:

.owner
= THIS_MODULE,

.fb_setcolreg = live2440_setcolreg,

.fb_fillrect
= cfb_fillrect,

.fb_copyarea
= cfb_copyarea,

.fb_imageblit
= cfb_imageblit,

fb_setcolreg用于根据红绿蓝三基色的分量合成颜色到调色板数组中

fb_fillrect fb_copyarea fb_imageblit三个函数用于无显存硬件加器的系统

完成显示数据的填充和复制,使用这三个函数时需要配置相应.c文件编译成模块

或编译进内核。

通过dma_alloc_writecombine函数调协dma方式内存数据到LCD显示总线的数据

传输开始地址及传输长度,并返回传输的内存地址的物理地址及虚拟地址

2>设置lcd控制器及其相关的引脚

主要是设置lcdcon1--lcdcon5 lcdaddr1--lcdaddr3及LCD控制所使用的GPIO引脚

的复用功能:GPC,GPD,GPG。其中数据总线与地址总线使用GPC GPD,GPG的引脚4

作为LCD屏的电源控制引脚。

3>注册frame buffer结构体到内核

调用内核函数register_framebuffer把分配的fb_info结构体注册到内核中。

内核中分配了一个长度为32的fb_info类型的数组指针,每注册一个fb_info就把

其放入到数组中,并把数组的下标做为fb设置的序号给设备使用。然后创建设备

文件/dev/fbx,由于fbmem.c的初始化函数中已经完成了fb主设备的注册,其已经

提供了fb设备的 read write ioctl函数,这部分不需要为其进行其实设置

至此整个lcd驱动程序的基本结构就完成了,需要需要写成platform平台驱动的结

构,只需要按其结构修改,并把以上三部分的代码写到其probe函数中。

本来比较简单的程序,调试了几个周才算是完成也是比较纠结,期间也是相当的烦躁

曾经有过放弃的念头(之前移植uboot时也有过类似经历:

默认的nfcont的12位Soft lock是打开的,禁止写nand,但可以读nand,初始化时需要

清0该位,同时清0ECC相关位)。

遇到问题如下:

a>

编译后能直接insmod,但是使用echo nihao > /dev/tty1 或

cat xx.file > /dev/fb0 屏幕无反应。

发现/dev/下有fb0与fb1两个设备文件,将上面命令中的tty1换成tty2,fb0换成fb1

依然没有反应。

<a解决方法:发现源代码中已经存在文件s3c2410fb.c,make menuconfig修改源码

配置项,把S3C2410FB配置成M,编译内核make uImage,编译模块make modules。

b>然后insmod cfb(三个cfb模块)*.ko和insmod lcd.ko出现段错误,而这时插入

源码中的s3c2410fb.ko一切正常。

<b这地方卡了好久,曾经一路查看和打印内核源代码,发现程序在console_lock()

中调用down_console_sem()请求信号量前能打印出信息,之后的信息没有打印出

来就段错误了,曾经怀疑是busybox的insmod命令代码错误(用的busybox比较新)

后来看了源码感觉不是它的问题。后来又挂成最新的3.18.0的内核还是同样死在

请求console的信息量时段错误。于是最后又回归到检查自己的源码的路子上。

最后发现是在设置 fix.line_length 的参数填写成240*2,填成了列的长度,修改之。

遇到这样的错误其实首先应该去自己的代码中去仔细检查,找出错误,而不是先

怀疑别人的代码,kernel,busybox这都是很多编写使用的代码一般发行的版本不会

有大错误;浪费了大量的时间,当然其间也阅读也一些相关的代码也算是一点收获吧。

c>insmod lcd.ko后,注册成功但是屏幕还是没有反应

<c打印出lcdcon1-lcdaddr1寄存器值查看是否正确,发现打印出的值全是0,怀疑是

lcd控制器的时钟没有打开,阅读源码中s3c2410fb.c的probe函数中有clk_get相关

函数调用,于是在初始化LCD控制器前加入

clk_get(NULL, "lcd")与clk_prepare_enable(lcd_clk)

使能控制器时钟.默认地内核会关闭不使用的外设的时钟,以降低功率.

之间还有过一次,设置lcdaddr2时与0x1fffff进行位与运算时少写了一个f,造成屏幕

不停地在闪烁,像时小时候的黑白电视机在没有台时显示的波纹一样。

d>操作fb0和tty1设备文件,屏幕有反应能显示。在使用16位显示时,通过

echo nihao > /dev/tty1 能看到屏幕上显示出了nihao但是很不清楚,

在使用24位色显示时就只能看到屏幕上显示出一个黑块,该问题没能解决。

应用程序可以通过ioctl获取屏幕的参数,通过mmap系统调用将屏幕的显存映射到

内存空间中,通过向映射的内存空间写入颜色的值使屏幕点亮。

<d通过在屏幕的四周画线,观察能否在屏幕上看到来校正驱动程序参数。

通过阅读屏幕的手册参数来设置lcdcon1-lcdcon5就能校正使显示正常。

e>在全屏显示纯色时,屏幕左上角大约有一个7*7像素的黑格在闪

使用echo nihao > /dev/tty1命令后,发现黑格向下移动

<e这可能是内核默认的支持lcd console功能导致,make menuconfig修改内核配置

去除该功能

至此LCD驱动程序移植完毕

驱动程序编码调试成功后静态编译进内核

考虑到编写的驱动程序只是自己使用,就不再为其分类放到内核相应的目录树下,而是

在drivers目录下新建立文件夹live2440_platform,然后把.c文件放到该文件夹下,并

新建Kconfig与Makefile文件,Kconfig与Makefile的写法比较简单可参靠内核源码目录

下的其他文件填充编写。完成后修改drivers目录下的Kconfig,在endmenu前加入

source "drivers/live2440_platform/Kconfig"

修改drivers/Makefile文件

在最后一行加入

或 写死obj-y += live2440_platform/

obj-$(CONFIG_LIVE2440_PLATFORM) += live2440_platform/

只有修改了drivers/Makefile后编译时make才会进入live2440_platform去执行它下面

的Makefile,否则及时通过make menuconfig配置上选项也不会将其编译进内核

最后附上LCD控制器的参数设置:

S3C2440,400MHz--Fclk 100MHz--Hclk 50MHz--Pclk

live2440_lcd_ctrl->lcdcon1 = (5<<8)|(3<<5)|(0xD<<1);

live2440_lcd_ctrl->lcdcon2 = (11<<24)|(239<<14)|(4<<6)|(7<<0);

live2440_lcd_ctrl->lcdcon3 = (8<<19)|(319<<8)|(4<<0);

live2440_lcd_ctrl->lcdcon4 = 7;

live2440_lcd_ctrl->lcdcon5 = (1<<11)|(1<<9)|(1<<8);

live2440_lcd_ctrl->lcdsaddr1 = (live2440_fbinfo->fix.smem_start>>1)&(0x3fffffff);

live2440_lcd_ctrl->lcdsaddr2 = ((live2440_fbinfo->fix.smem_start+live2440_fbinfo->fix.smem_len)>>1)&0x1fffff;

live2440_lcd_ctrl->lcdsaddr3 = 320*32/16;

live2440_lcd_ctrl->lcdcon5 |= (1<<3);

live2440_lcd_ctrl->lcdcon1 |= (1<<0);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: