TQ2440平台上LCD驱动的移植
参考:
http://liu1227787871.blog.163.com/blog/static/205363197201242393031250/
http://blog.csdn.net/cumtgao/article/details/8649006
http://www.360doc.com/content/12/0424/17/9159905_206213245.shtml
http://blog.csdn.net/yj4231/article/details/7878762
硬件平台:TQ2440
LCD型号:WXCAT43,分辨率480*270
U-boot版本:u-boot-2015.04
内核版本:Linux-3.14
作者:彭东林
下面主要完成Linux下面的LCD驱动的移植。
首先我们需要知道一些LCD的知识:
我们使用的LCD是TFT类型,下面是S3C2440的LCD控制器的信号引脚:
下面是TQ2440的LCD原理图:
下面介绍一下这些引脚的功能:
VCLK:发出lcd时钟信号,每来一个时钟,就会在屏幕上显示一个像素
VLINE:发出lcd行扫描信号
VFRAME:发出lcd桢扫描信号
VM:VDEN,有效时才会在屏幕上显示象素
LCD_PWREN:发出lcd面板电源使能控制信号
VD[3]——VD[7] :lcd数据总线
VD[10]——VD[15] :lcd数据总线
VD[19]——VD[23] :lcd数据总线
各信号的含义
VSYNC:帧同步信号
每发出一个脉冲,表示新的一屏图像数据开始传送。
HSYNC:行同步信号
每发出一个脉冲,表示新的一行图像数据开始传送。
VCLK:像素时钟信号
每发出一个脉冲,表示新的一个点图像数据开始传送。
LEND:行结束信号
VBPD:表示在一帧图像开始时,帧同步信号以后的无效的行数,对应驱动中的upper_margin;
VFBD:表示在一帧图像结束后,帧同步信号以前的无效的行数,对应驱动中的lower_margin;
VSPW:表示垂直同步脉冲的宽度,单位是行数
HBPD:表示从水平同步信号开始到一行的有效数据开始之间的vclk的个数,对应驱动中的left_margin;
HFPD:表示一行的有效数据结束到下一个水平同步信号开始之间的vclk的个数,对应驱动中的right_margin;
HSPW:表示水平同步信号的宽度,单位是vclk的个数
下面我们结合两张图理解一下:
下面我们结合TQ2440上的LCD芯片手册分析:
注意上面这幅图下面的文字中对CLK和H的说明,其中:CLK表示的是像素时钟周期,H表示的是行同步时钟周期。可以发现上面图中的规律:
525=480+2+41+2 他们的单位都是CLK
286=272+2+10+2 他们的单位都是H
所以帧率就是: 1/(525*286*像素时钟周期) Hz
这样我们也容易理解S3C2440上的两个公式:
VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 像素时钟频率(Hz)
Frame Rate = 1/ [ { (VSPW+1) + (VBPD+1) + (LIINEVAL + 1) + (VFPD+1) } x {(HSPW+1) + (HBPD +1)+ (HFPD+1) + (HOZVAL + 1) } x { 2 x ( CLKVAL+1 ) / ( HCLK ) } ] 帧率(Hz)
对照上面的两幅图,我们采用典型值来填充这个结构体
static struct s3c2410fb_display tq2440_lcd_cfg __initdata = {
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,
.type = S3C2410_LCDCON1_TFT,
.width = 480,
.height = 272,
.pixclock = 100000,
.xres = 480,
.yres = 272,
.bpp = 16,
.left_margin = 2, /* For HBPD+1, 这里我们取的都是典型值 */
.right_margin = 2, /* For HFPD+1 */
.hsync_len = 41, /* For HSPW+1 */
.upper_margin = 2, /* For VBPD+1 */
.lower_margin = 2, /* For VFPD+1 */
.vsync_len = 10, /* For VSPW+1 */
};
#define S3C2410_GPCCON_MASK(x) (3 << ((x) * 2))
#define S3C2410_GPDCON_MASK(x) (3 << ((x) * 2))
static struct s3c2410fb_mach_info tq2440_fb_info __initdata = {
.displays = &tq2440_lcd_cfg,
.num_displays = 1,
.default_display = 0,
/* Enable VD[2..7], VD[10..15], VD[18..23] and VCLK, syncs, VDEN
* and disable the pull down resistors on pins we are using for LCD
* data. */
.gpcup = (0xf << 1) | (0x3f << 10),
.gpccon = (S3C2410_GPC1_VCLK | S3C2410_GPC2_VLINE |
S3C2410_GPC3_VFRAME | S3C2410_GPC4_VM |
S3C2410_GPC8_VD0 | S3C2410_GPC9_VD1 |
S3C2410_GPC10_VD2 | S3C2410_GPC11_VD3 |
S3C2410_GPC12_VD4 | S3C2410_GPC13_VD5 |
S3C2410_GPC14_VD6 | S3C2410_GPC15_VD7),
.gpccon_mask = (S3C2410_GPCCON_MASK(1) | S3C2410_GPCCON_MASK(2) |
S3C2410_GPCCON_MASK(3) | S3C2410_GPCCON_MASK(4) |
S3C2410_GPCCON_MASK(8) | S3C2410_GPCCON_MASK(9) |
S3C2410_GPCCON_MASK(10) | S3C2410_GPCCON_MASK(11) |
S3C2410_GPCCON_MASK(12) | S3C2410_GPCCON_MASK(13) |
S3C2410_GPCCON_MASK(14) | S3C2410_GPCCON_MASK(15)),
.gpdup = (0x3f << 2) | (0x3f << 10),
.gpdcon = (S3C2410_GPD2_VD10 | S3C2410_GPD3_VD11 |
S3C2410_GPD4_VD12 | S3C2410_GPD5_VD13 |
S3C2410_GPD6_VD14 | S3C2410_GPD7_VD15 |
S3C2410_GPD10_VD18 | S3C2410_GPD11_VD19 |
S3C2410_GPD12_VD20 | S3C2410_GPD13_VD21 |
S3C2410_GPD14_VD22 | S3C2410_GPD15_VD23),
.gpdcon_mask = (S3C2410_GPDCON_MASK(2) | S3C2410_GPDCON_MASK(3) |
S3C2410_GPDCON_MASK(4) | S3C2410_GPDCON_MASK(5) |
S3C2410_GPDCON_MASK(6) | S3C2410_GPDCON_MASK(7) |
S3C2410_GPDCON_MASK(10) | S3C2410_GPDCON_MASK(11)|
S3C2410_GPDCON_MASK(12) | S3C2410_GPDCON_MASK(13)|
S3C2410_GPDCON_MASK(14) | S3C2410_GPDCON_MASK(15)),
// .lpcsel = ((0xCE6) & ~7) | 1<<4, // 禁用lpsel,因为如果不是使用三星LPC3600/LCC3600 LCD,必须禁止LPC3600/LCC3600模式(写入0到TCONSEL)。
};
接下来要说的参数是pixclock,他是用来计算像素频率的。
在driver/video/s3c2410fb.c中:
static void s3c2410fb_activate_var(struct fb_info *info)
{
struct s3c2410fb_info *fbi = info->par;
void __iomem *regs = fbi->io;
int type = fbi->regs.lcdcon1 & S3C2410_LCDCON1_TFT;
struct fb_var_screeninfo *var = &info->var;
int clkdiv;
clkdiv = DIV_ROUND_UP(s3c2410fb_calc_pixclk(fbi, var->pixclock), 2);
dprintk("%s: var->xres = %d\n", __func__, var->xres);
dprintk("%s: var->yres = %d\n", __func__, var->yres);
dprintk("%s: var->bpp = %d\n", __func__, var->bits_per_pixel);
if (type == S3C2410_LCDCON1_TFT) {
s3c2410fb_calculate_tft_lcd_regs(info, &fbi->regs);
--clkdiv;
if (clkdiv < 0)
clkdiv = 0;
} else {
s3c2410fb_calculate_stn_lcd_regs(info, &fbi->regs);
if (clkdiv < 2)
clkdiv = 2;
}
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_CLKVAL(clkdiv);
......
}
上面计算得到的clkdiv就是VCLK(Hz) = HCLK/[(CLKVAL+1)x2] 中的CLKVAL.
static unsigned int s3c2410fb_calc_pixclk(struct s3c2410fb_info *fbi,
unsigned long pixclk)
{
unsigned long clk = fbi->clk_rate;
unsigned long long div;
/* pixclk is in picoseconds, our clock is in Hz
*
* Hz -> picoseconds is / 10^-12
*/
div = (unsigned long long)clk * pixclk;
div >>= 12; /* div / 2^12 */
do_div(div, 625 * 625UL * 625); /* div / 5^12 */
dprintk("pixclk %ld, divisor is %ld\n", pixclk, (long)div);
return div;
}
首先pixclock作为参数传递给了s3c2410fb_calc_pixclk函数,当该函数执行完以后
clkdiv = (clk * pixclk / 10^12 + (2 - 1))/ 2。
随后由于是采用TFT模式,将clkdiv-1。最后得:
clkdiv = (clk * pixclk / 10^12 + (2 - 1))/ 2 - 1,
这里的clk即为HCLK,LCD模块使用HCLK作为时钟源,从内核启动代码中可以看到HCLK是100MHz
为方便观察,将前面datasheet中的计算公式复制在此:CLKVAL = HCLK / VCLK / 2 -1。
我们可以看出1/VCLK = pixclk / 10^12,也就是说pixclk = 10^12 / VCLK。 从LCD的芯片手册上可以看到VCLK的典型值是9MHz,我们取10MHz。
因此,pixclk=100000。
其实在内核的参考文档中有这样一段话:
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
也就是说VCLK的倒数,再乘10^12即为pixclk。picoseconds单位表示微微秒,即10^12。
完。
TQ2440平台上LCD驱动的移植的更多相关文章
- linux 驱动之LCD驱动(有framebuffer)
<简介> LCD驱动里有个很重要的概念叫帧缓冲(framebuffer),它是Linux系统为显示设备提供的一个接口,应用程序在图形模式允许对显示缓冲区进行读写操作.用户根本不用关心物理显 ...
- 运行在TQ2440开发板上以及X86平台上的linux内核编译
一.运行在TQ2440开发板上的linux内核编译 1.获取源码并解压 直接使用天嵌移植好的“linux-2.6.30.4_20100531.tar.bz2”源码包. 解压(天嵌默认解压到/opt/E ...
- LCD驱动移植在在mini2440(linux2.6.29)和FS4412(linux3.14.78)上实现对比(deep dive)
1.Linux帧缓冲子系统 帧缓冲(FrameBuffer)是Linux为显示设备提供的一个接口,用户可以将帧缓冲看成是显示内存的一种映像,将其映射到进程地址空间之后,就可以直接进行读写操作,而写操作 ...
- AM335x(TQ335x)学习笔记——LCD驱动移植
TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由 ...
- 移植ok6410 LCD驱动
1.本次移植过程选择 linux-2.6.28 lcd驱动为参考移植到 linux-2.6.34 ok6410 开发板上. 2.移植过程 主要以给内核增加驱动的思想,在/driver/video/ 下 ...
- Linux的LCD驱动分析及移植
测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 LCD驱动分析 LCD屏的驱动总体上分成两块,一块是GUI ...
- 全志A33移植LCD驱动(ILI9806E)
0x00 环境说明: 所使用的开发板为锐尔威视的插针版A33_Vstar 屏幕是买的第三方的KD050FWFPA011-C009A,其中LCD驱动IC为ILI9806E,所使用的接口为RGB666 0 ...
- Linux平台上DPDK入门指南
1. 简介 本文档包含DPDK软件安装和配置的相关说明.旨在帮助用户快速启动和运行软件.文档主要描述了在Linux环境下编译和 运行DPDK应用程序,但是文档并不深入DPDK的具体实现细节. 1.1. ...
- S3C2440 LCD驱动(FrameBuffer)实例开发<一>(转)
1. 背景知识 在多媒体的推动下,彩色LCD越来越多地应用到嵌入式系统中,PDA和手机等大多都采用LCD作为显示器材,因此学习LCD的应用很有实际意义! LCD工作的硬件需求:要使一块LCD正常的显示 ...
随机推荐
- hexo 配置文件 实例
# Hexo Configuration ## Docs: https://hexo.io/docs/configuration.html ## Source: https://github.com/ ...
- 【转】PHP对象在内存中的分配
对像在PHP 里面和整型.浮点型一样,也是一种数据类,都是存储不同类型数据用的, 在运行的时候都要加载到内存中去用,那么对象在内存里面是怎么体现的呢?内存从逻辑上 说大体上是分为4 段,栈空间段.堆空 ...
- Android 热更新是如何实现的?
Android开发中,我们常常遇到热更新这个概念,而这个热更新具体是怎么实现的呢?今天在网上看到一个大神分享的热更新相关实现原理和实现代码,感觉灰常不错,分享给广大码农盆友look look . Cl ...
- 洛谷 P3573 [POI2014]RAJ-Rally 解题报告
P3573 [POI2014]RAJ-Rally 题意: 给定一个\(N\)个点\(M\)条边的有向无环图,每条边长度都是\(1\). 请找到一个点,使得删掉这个点后剩余的图中的最长路径最短. 输入输 ...
- NOI退役啦
没进前一百 签的上交一本 高三加油喽
- bzoj 3507 DP+哈希
[Cqoi2014]通配符匹配 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 541 Solved: 235[Submit][Status][Dis ...
- XML格式化及解析
XML格式化工具:notepad++ 下载地址 http://rj.baidu.com/soft/detail/13478.html?ald 一个教程地址:http://jingyan.ba ...
- Nano
Nano命令指南 今天在输命令时,无意中输入了nano,对这个命令不太熟悉,结果不知道如何才能退出,保存,赶快查了一下资料,原来是这样的啊. 打开文件与新建文件 使用nano打开或新建文件,只需键入: ...
- JAVA中GC时finalize()方法是不是一定会被执行?
在回答上面问题之前,我们一定要了解JVM在进行垃圾回收时的机制,首先: 一.可达性算法 要知道对象什么时候死亡,我们需要先知道JVM的GC是如何判断对象是可以回收的.JAVA是通过可达性算法来来判断 ...
- 我们曾经心碎的数据库之 用SQL语句操作数据
第八章 用SQL语句操作数据 1.SQL简介 SQL语言是能够识别指令,执行相应的操作并为程序提供数据的一套指令集 SQL的全称: 结构化查询语言(Structured Query Languag ...