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

作者:彭东林

邮箱:[email protected]

下面主要完成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/s3c2410_fb.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。

完。

时间: 2024-11-03 15:14:58

TQ2440平台上LCD驱动的移植的相关文章

移植ok6410 LCD驱动

1.本次移植过程选择 ldd6410 lcd驱动为参考移植到 ok6410 开发板上,由于 ok6410 2.28内核已有相关驱动,故将其删除后再将新驱动移植. 2.移植过程 主要以给内核增加驱动的思想,在/driver/video/ 下增加 samsung目录,提取 ldd6410 中驱动相关源代码,将源代码复制到samsung 下. 修改 /driver/video 下的Makefile 文件,增加进入samsung目录编译的编译条目 修改 /driver/video 下的Kconfig 文

LCD驱动移植配置总结

总结下移植LCD驱动时的参数配置情况: 根据LCD数据手册和处理器数据手册LCD控制器部分, 得到如下参数: 一.基本参数(4个) 1.宽度即水平像素点个数(eg:800) 2.高度即垂直像素点个数(eg:480) 3.描述单个像素点需要的位数(eg:32) 4.刷新频率(eg:60) 二.时序参数(6个) 1.行同步信号前回扫时间 2.行同步信号后回扫时间 3.行同步信号脉冲宽度 4.帧同步信号前回扫时间 5.帧同步信号后回扫时间 6.帧同步信号脉冲宽度 三.极性参数(4个) 1.像素时钟极性

AM335x(TQ335x)学习笔记——LCD驱动移植

TI的LCD控制器驱动是非常完善的,共通的地方已经由驱动封装好了,与按键一样,我们可以通过DTS配置完成LCD的显示.下面,我们来讨论下使用DTS方式配置内核完成LCD驱动的思路. (1)初步分析 由于TQ335x使用的芯片是AM335x,故仍然可以参考am335x-evm.dts.当然,am335x-evmsk.dts.am335x-beagbone.dts都可以.本文以am335x-evm.dts为例.大体上浏览下DTS文件,可以发现两个醒目的节点:一个是panel,一个是backlight

GitHub Android 最火开源项目Top20 GitHub 上的开源项目不胜枚举,越来越多的开源项目正在迁移到GitHub平台上。基于不要重复造轮子的原则,了解当下比较流行的Android与iOS开源项目很是必要。利用这些项目,有时能够让你达到事半功倍的效果。

1. ActionBarSherlock(推荐) ActionBarSherlock应该算得上是GitHub上最火的Android开源项目了,它是一个独立的库,通过一个API和主题,开发者就可以很方便地使用所有版本的Android动作栏的设计模式. 对于Android 4.0及更高版本,ActionBarSherlock可以自动使用本地ActionBar实现,而对于之前没有ActionBar功能的版本,基于Ice Cream Sandwich的自定义动作栏实现将自动围绕布局.能够让开发者轻松开发

S3C2440 LCD驱动(FrameBuffer)实例开发&lt;二&gt;(转)

开发板自带的LCD驱动是基于platform总线写的,所以如果要使其它的LCD能够在自己的开发板上跑起来,那么就先了解platform驱动的架构,下面简单记录下自己看platform驱动时体会,简单的说platform是一种虚拟总线,那么它也是一条总线,所以它分为3个部分,platform_bus,platform_device,platform_driver.在platform_device向platform_bus注册设备,platform_driver向platform_bus注册驱动,注

S3C2440 LCD驱动(FrameBuffer)实例开发&lt;一&gt;(转)

1. 背景知识 在多媒体的推动下,彩色LCD越来越多地应用到嵌入式系统中,PDA和手机等大多都采用LCD作为显示器材,因此学习LCD的应用很有实际意义! LCD工作的硬件需求:要使一块LCD正常的显示文字或图像,不仅需要LCD驱动器,而且还需要相应的LCD控制器.在通常情况下,生产厂商把LCD驱动器会以COF/COG的形式与LCD玻璃基板制作在一起,而LCD控制器则是由外部的电路来实现,现在很多的MCU内部都集成了LCD控制器,如S3C2410/2440等.TQ2440是采用了S3C2440,S

Android平台上PMEM的使用及Platform设备注册(一)

Android中PMEM驱动程序是物理内存的驱动程序,可用于分配物理内存.PMEM在camera和video系统中频繁使用.下面,简单记录一下PMEM的使用方法.另外,由于PMEM设备做为Platform设备存在,所以我们将对Platform设备做以简单描述. 一.PMEM的使用 使用PMEM需要包含如下几个头文件: #include <sys/ioctl.h> #include <binder/MemoryHeapBase.h> #include <binder/Memor

Android平台上PMEM的使用及Platform设备注册(二)

三.注册PMEM设备 这里我们除了描述PMEM设备,还将注册一个拥有memory空间和IRQ资源的示例设备example_device. 对于example_device,定义如下结构体: static struct resource example_resources[] = { [0] = { .start  = 0xC0000000, .end    = 0xC0020000, .flags  = IORESOURCE_MEM, }, [1] = { .start  = 30, .end 

OpenStack平台上,windows云主机可以ping通百度但是无法打开网页,部分其它网页可以打开

问题描述: 在OpenStack平台上的64位Windows7虚拟机,可以ping通百度,但是却无法打开百度网页. 于是,笔者又对其它网址进行的测试,发现淘宝.京东.携程部分网页可以打开,而新浪等等网页依然打不开,瞬间郁闷了. 按照百度网上的搜索结果进行了各种尝试,包括重启路由.重装virtio驱动.重置winsoc文件(CMD命令:netsh winsock reset).重装TCP/IP协议等各种方法,均不见效. 然后看到网上有说旗舰版windows7系统中有这样的问题存在,于是笔者对同一个