参考资料:http://blog.chinaunix.net/uid-9688646-id-1998441.html
http://blog.163.com/changchunxi@126/blog/static/111800823201212533243484/
主机:Windows 7旗舰版,VMware7.1.2,Fedora9
集成开发环境:Source Insight 3.5
编译环境:arm-linux-gcc 4.4.3
开发板:华中科技大学惠世科技S3C2440实验箱开发板,奇美4.3寸LCD(与TQ2440相似,参数见LR043JC211_V04.pdf)。
Uboot版本:u-boot-2009.11
Linux版本:linux-2.6.32.2
这里只讨论TFT LCD。
1.LCD驱动移植准备
Linux-2.6.32.2 内核已经支持S3C2440 的LCD 控制器驱动,在这里主要介绍一下LCD驱动移植时需要设置的参数。
在移植LCD驱动时,我们需要根据LCD datasheet来设置相应的参数,这些参数包括:
pixclock,left_margin,right_margin,upper_margin,lower_margin,hsync_len,vsync_len。
各个参数的设置方法在内核目录树Documentation\fb\framebuffer.txt中都有介绍(其实最好的方法就是看文档,但开始可能由于对LCD参数不熟悉,又是全英文,看着比较困难,做完一遍再回头看就很清晰明了了),为了方便这里摘取我们需要的部分内容如下:
5. Video Mode Timings
---------------------
A monitor draws an image on the screen by using an electron beam (3 electron
beams for color models, 1 electron beam for monochrome monitors). The front of
the screen is covered by a pattern of colored phosphors (pixels). If a phosphor
is hit by an electron, it emits a photon and thus becomes visible.
The electron beam draws horizontal lines (scanlines) from left to right, and
from the top to the bottom of the screen. By modifying the intensity of the
electron beam, pixels with various colors and intensities can be shown.
After each scanline the electron beam has to move back to the left side of the
screen and to the next line: this is called the horizontal retrace. After the
whole screen (frame) was painted, the beam moves back to the upper left corner:
this is called the vertical retrace. During both the horizontal and vertical
retrace, the electron beam is turned off (blanked).
The speed at which the electron beam paints the pixels is determined by the
dotclock in the graphics board. For a dotclock of e.g. 28.37516 MHz (millions
of cycles per second), each pixel is 35242 ps (picoseconds) long:
1/(28.37516E6 Hz) = 35.242E-9 s
If the screen resolution is 640x480, it will take
640*35.242E-9 s = 22.555E-6 s
to paint the 640 (xres) pixels on one scanline. But the horizontal retrace
also takes time (e.g. 272 `pixels'), so a full scanline takes
(640+272)*35.242E-9 s = 32.141E-6 s
We'll say that the horizontal scanrate is about 31 kHz:
1/(32.141E-6 s) = 31.113E3 Hz
A full screen counts 480 (yres) lines, but we have to consider the vertical
retrace too (e.g. 49 `lines'). So a full screen will take
(480+49)*32.141E-6 s = 17.002E-3 s
The vertical scanrate is about 59 Hz:
1/(17.002E-3 s) = 58.815 Hz
This means the screen data is refreshed about 59 times per second. To have a
stable picture without visible flicker, VESA recommends a vertical scanrate of
at least 72 Hz. But the perceived flicker is very human dependent: some people
can use 50 Hz without any trouble, while I'll notice if it's less than 80 Hz.
Since the monitor doesn't know when a new scanline starts, the graphics board
will supply a synchronization pulse (horizontal sync or hsync) for each
scanline. Similarly it supplies a synchronization pulse (vertical sync or
vsync) for each new frame. The position of the image on the screen is
influenced by the moments at which the synchronization pulses occur.
The following picture summarizes all timings. The horizontal retrace time is
the sum of the left margin, the right margin and the hsync length, while the
vertical retrace time is the sum of the upper margin, the lower margin and the
vsync length.
+----------+---------------------------------------------+----------+-------+
| | ↑ | | |
| | |upper_margin | | |
| | ↓ | | |
+----------###############################################----------+-------+
| # ↑ # | |
| # | # | |
| # | # | |
| # | # | |
| left # | # right | hsync |
| margin # | xres # margin | len |
|<-------->#<---------------+--------------------------->#<-------->|<----->|
| # | # | |
| # | # | |
| # | # | |
| # |yres # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # | # | |
| # ↓ # | |
+----------###############################################----------+-------+
| | ↑ | | |
| | |lower_margin | | |
| | ↓ | | |
+----------+---------------------------------------------+----------+-------+
| | ↑ | | |
| | |vsync_len | | |
| | ↓ | | |
+----------+---------------------------------------------+----------+-------+
The frame buffer device expects all horizontal timings in number of dotclocks
(in picoseconds, 1E-12 s), and vertical timings in number of scanlines.
6. Converting XFree86 timing values info frame buffer device timings
--------------------------------------------------------------------
An XFree86 mode line consists of the following fields:
"800x600" 50 800 856 976 1040 600 637 643 666
< name > DCF HR SH1 SH2 HFL VR SV1 SV2 VFL
The frame buffer device uses the following fields:
- pixclock: pixel clock in ps (pico seconds)
- left_margin: time from sync to picture
- right_margin: time from picture to sync
- upper_margin: time from sync to picture
- lower_margin: time from picture to sync
- hsync_len: length of horizontal sync
- vsync_len: length of vertical sync
1) Pixelclock:
xfree: in MHz
fb: in picoseconds (ps)
pixclock = 1000000 / DCF
2) horizontal timings:
left_margin = HFL - SH2
right_margin = SH1 - HR
hsync_len = SH2 - SH1
3) vertical timings:
upper_margin = VFL - SV2
lower_margin = SV1 - VR
vsync_len = SV2 - SV1
Good examples for VESA timings can be found in the XFree86 source tree,
under "xc/programs/Xserver/hw/xfree86/doc/modeDB.txt".
这里介绍了如何计算LCD一帧图片的刷新频率,以及我们之前提到的那些参数的设置。我们可以找到Pixclock的计算方法:
pixclock = 1000000 / DCF
DCF是Dot Clk Frequency,单位是MHz,是扫描像素点的频率。计算出来的pixclock单位是ps。
其他参数虽然给出了计算方法,但与我们的TFT LCD Datasheet中所给的的参数可能不太一致。下面对left_margin,right_margin,upper_margin,lower_margin,hsync_len,vsync_len这几个参数进行进一步讲解。
下图是典型的TFT LCD时序图(移植时以自己LCD相应的datasheet为准):
VBP(vertical back porch):表示在一帧图像开始时,垂直同步信号以后的无效的行数,
对应驱动中的upper_margin;
VFB(vertical front porch):表示在一帧图像结束后,垂直同步信号以前的无效的行数,
对应驱动中的lower_margin;
VSPW(vertical sync pulse width):表示垂直同步脉冲的宽度,用行数计算,
对应驱动中的vsync_len;
HBP(horizontal back porch):表示从水平同步信号开始到一行的有效数据开始之间的VCLK的个数,
对应驱动中的left_margin;
HFP(horizontal front porth):表示一行的有效数据结束到下一个水平同步信号开始之间的VCLK的个数,
对应驱动中的right_margin;
HSPW(horizontal sync pulse width):表示水平同步信号的宽度,用VCLK计算,
对应驱动中的hsync_len。
知道每个参数对应的值是什么意思后,查看我们所需移植的LCD Datasheet(LR043JC211_V04.pdf),参数和时序见下图:
根据所给参数可以计算出:
pixclock = 1000000 / DCLK = 1000000 / 9 = 111111
left_margin = Thb = 2
right_margin = Thf = 2
hsync_len = Thp = 41
upper_margin = Tvb = 2
lower_margin = Tvf = 2
vsync_len = Tvp = 10
xres = Thd = 480
Yres = Tvd = 272
2.内核中添加LCD驱动
在arch/arm/mach-s3c2440/mach-mini2440.c中添加如下代码:
点击(此处)折叠或打开
- static struct s3c2410fb_display mini2440_lcd_cfg __initdata = {
- .lcdcon5 = S3C2410_LCDCON5_FRM565 |
- S3C2410_LCDCON5_INVVLINE |
- S3C2410_LCDCON5_INVVFRAME |
- S3C2410_LCDCON5_PWREN |
- S3C2410_LCDCON5_HWSWP,
-
- .type = S3C2410_LCDCON1_TFT,
-
- #if defined(CONFIG_FB_S3C2410_TFT480272)
- .width = 480,
- .height = 272,
- .pixclock = 111111,
- .xres = 480,
- .yres = 272,
- .bpp = 16,
- .left_margin = 2,
- .right_margin = 2,
- .hsync_len = 41,
- .upper_margin = 2,
- .lower_margin = 2,
- .vsync_len = 10,
- #endif
- };
- static struct s3c2410fb_mach_info mini2440_fb_info __initdata = {
- .displays = &mini2440_lcd_cfg,
- .num_displays = 1,
- .default_display = 0,
-
- #if 0
- /* currently setup by downloader */
- .gpccon = 0xaa940659,
- .gpccon_mask = 0xffffffff,
- .gpcup = 0x0000ffff,
- .gpcup_mask = 0xffffffff,
- .gpdcon = 0xaa84aaa0,
- .gpdcon_mask = 0xffffffff,
- .gpdup = 0x0000faff,
- .gpdup_mask = 0xffffffff,
-
- .default_display = 0,
- .gpccon = 0xaa955699,
- .gpccon_mask = 0xffc003cc,
- .gpcup = 0x0000ffff,
- .gpcup_mask = 0xffffffff,
- .gpdcon = 0xaa95aaa1,
- .gpdcon_mask = 0xffc0fff0,
- .gpdup = 0x0000faff,
- .gpdup_mask = 0xffffffff,
- #endif
- .lpcsel = 0xf82,
- };
在设备初始化函数中加入设置LCD初始化参数函数,如下:
点击(此处)折叠或打开
- static void __init mini2440_machine_init(void)
- {
- s3c24xx_fb_set_platdata(&mini2440_fb_info);
- s3c_i2c0_set_platdata(NULL);
-
- s3c_device_nand.dev.platform_data = &mini2440_nand_info;
- platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
- //smdk_machine_init();
- }
在drivers/video/Kconfig中大概1930行加入添加内核配置选项:
点击(此处)折叠或打开
- config FB_S3C2410_DEBUG
- bool "S3C2410 lcd debug messages"
- depends on FB_S3C2410
- help
- Turn on debugging messages. Note that you can set/unset at run time
- through sysfs
-
- choice
- prompt "LCD select"
- depends on FB_S3C2410
- help
- S3C24x0 LCD size select
-
- config FB_S3C2410_TFT480272
- boolean "4.2 inch TFT 480X272 LCD"
- depends on FB_S3C2410
- help
- 4.2 inch TFT 480X272 LCD
- endchoice
-
- config FB_SM501
- tristate "Silicon Motion SM501 framebuffer support"
- depends on FB && MFD_SM501
- select FB_CFB_FILLRECT
- select FB_CFB_COPYAREA
- select FB_CFB_IMAGEBLIT
3.配置内核
在命令行下,进入内核根目录,执行:
#make menuconfig,
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
LCD select (4.2 inch TFT 480X272 LCD) --->
(X) 4.2 inch TFT 480X272 LCD
Console display driver support --->
<*> Framebuffer Console support //支持Framebuffer控制台
[*] Select compiled-in fonts //选择字库,默认VGA 8x8 , VGA 8x16
[*] VGA 8x8 font
[*] VGA 8x16 font
[*] Bootup logo --->
[*] Standard 224-color Linux logo
按空格或者回车键选择我们需要的 LCD 型号,然后退出保存内核配置。在命令行执行:#make uImage
将会生成arch/arm/boot/uImage,把它烧写到开发板中,就可以看到熟悉的小企鹅出现在屏幕上了。
4.修改Linux内核logo
Linux 系统启动时会出现一个小企鹅图像。大部分Linux 系统会有这个开机图片, 它对应的文件其实就是linux-2.6.32.2/drivers/video/logo/logo_linux_clut224.ppm,该文件是一个特殊格式的图像文件,有很多方法可以把普通的图片转换为 logo 文件,最常用的就是netpbm 工具组。Fedora9光盘镜像中有netpbm软件包,可以在Fedora 9 i386 DVD/Packages/下找到,执行安装命令:
# rpm -ivh netpbm*.rpm
“netpbm”是一组命令行的工具,它可以转换很多格式的图片,在此以png 格式为例介绍一下如何把普通的PNG文件转换为我们需要的Linux LOGO 图片:
假定我们要转换的文件名为 logo_linux.png,首先将png 图片转成pnm
# pngtopnm logo_linux.png > logo_linux.pnm
然后将pnm 图片的颜色数限制在224
# pnmquant 224 logo_linux.pnm > logo_linux_clut224.pnm
最后将pnm 图片转换成我们需要的ppm
# pnmtoplainpnm logo_linux_clut224.pnm > logo_linux_clut224.ppm然后用logo_linux_clut224.ppm 替换linux-2.6.32.2/drivers/video/logo 中对应的图像就可以了。