Chinaunix首页 | 论坛 | 博客
  • 博客访问: 245792
  • 博文数量: 35
  • 博客积分: 1415
  • 博客等级: 上尉
  • 技术积分: 334
  • 用 户 组: 普通用户
  • 注册时间: 2009-11-10 21:31
文章分类

全部博文(35)

文章存档

2010年(22)

2009年(13)

我的朋友

分类: 嵌入式

2009-11-12 19:51:18

LCD移植记录

开发平台:MINI2440
内核版本:linux2.6.26

1.移植前的说明
>从启动信息可以看出没有加载成功LCD驱动
io scheduler cfq registered
s3c2410-lcd s3c2410-lcd: no platform data for lcd, cannot attach
s3c2410-lcd: probe of s3c2410-lcd failed with error -22
lp: driver loaded but no devices found

>实际上在linux2.6.26将LCD移植到QQ2440时,只需修改两个结构体配置参数即可。
这两个结构体分别是:struct s3c2410fb_display和s3c2410fb_mach_info 。修改参数所在文件是arch/arm/mach-s3c2410/mach-smdk2410.c,为什么不是arch/arm/mach-s3c2440/mach-smdk2440.c呢?因为在配置内核时需要选上的mach_type出选smdk2440外还需包含smdk2410,否则编译内核是通不过。既然选上了smdk2410,所以内核编译时所需编译的文件是在arm/mach-s3c2410/mach-smdk2410.c而非arm/mach-s3c2440/mach-smdk2440.c。

2.移植参考文件
>友善之臂提供了各个驱动都添加好的linux2.6.13内核原码,可以参考它的一些相关参数
>相关参数所在文件:arch/arm/mach-s3c2410/mach-sbc2440.c
>我的液晶屏是nec240 320的,所以是下面这段代码
2.6.24内核将s3c2410fb_mach_info拆成了struct s3c2410fb_display和s3c2410fb_mach_info
#if defined(CONFIG_FB_S3C2410_N240320)
static struct s3c2410fb_mach_info sbc2440_lcdcfg __initdata = {
    .regs    = {
        .lcdcon1 =    S3C2410_LCDCON1_TFT16BPP | \
                            S3C2410_LCDCON1_TFT | \
                            S3C2410_LCDCON1_CLKVAL(0x04),

        .lcdcon2 =    S3C2410_LCDCON2_VBPD(1) | \
                            S3C2410_LCDCON2_LINEVAL(319) | \
                            S3C2410_LCDCON2_VFPD(5) | \
                            S3C2410_LCDCON2_VSPW(1),

        .lcdcon3 =    S3C2410_LCDCON3_HBPD(36) | \
                            S3C2410_LCDCON3_HOZVAL(239) | \
                            S3C2410_LCDCON3_HFPD(19),

        .lcdcon4 =    S3C2410_LCDCON4_MVAL(13) | \
                            S3C2410_LCDCON4_HSPW(5),

        .lcdcon5 =    S3C2410_LCDCON5_FRM565 |
                            S3C2410_LCDCON5_INVVLINE |
                            S3C2410_LCDCON5_INVVFRAME |
                            S3C2410_LCDCON5_PWREN |
                            S3C2410_LCDCON5_HWSWP,
    },

    .lpcsel =    0xf82,

    .gpccon =    0xaa955699,
    .gpccon_mask =    0xffc003cc,
    .gpcup =    0x0000ffff,
    .gpcup_mask =    0xffffffff,

    .gpdcon =    0xaa95aaa1,
    .gpdcon_mask =    0xffc0fff0,
    .gpdup =    0x0000faff,
    .gpdup_mask =    0xffffffff,

    .fixed_syncs =    1,
    .width  =    240,
    .height =    320,

    .xres    = {
        .min =        240,
        .max =        240,
        .defval =    240,
    },

    .yres    = {
        .max =        320,
        .min =        320,
        .defval    =    320,
    },

    .bpp    = {
        .min =        16,
        .max =        16,
        .defval =    16,
    },
};


3.参照上面的参考参数修改内核代码
>修改文件/linux2.6.26/arch/arm/mach-s3c2410/mach-smdk2410.c
#加入头文件#include
#添加代码
static struct s3c2410fb_display s3c2440_lcd_cfg[] __initdata = {
            {
              /* Config for 240x320 LCD */
              .lcdcon5 = S3C2410_LCDCON5_FRM565 |
                               S3C2410_LCDCON5_INVVLINE |
                               S3C2410_LCDCON5_INVVFRAME |
                               S3C2410_LCDCON5_PWREN |
                               S3C2410_LCDCON5_HWSWP,

              .type             = S3C2410_LCDCON1_TFT,
             .width            = 320,

              .height          = 240,


              .pixclock       = 80000, /* HCLK/(CLKVAL*2) */
              .xres              = 320,

              .yres             = 240,

              .bpp              = 16,
              .left_margin   = 20,
              .right_margin       = 37,
              .hsync_len    = 6,
              .upper_margin     = 2,
              .lower_margin      = 6,
              .vsync_len    = 2,
    }
};
static struct s3c2410fb_mach_info s3c2440_fb_info __initdata = {
            .displays = s3c2440_lcd_cfg,
            .num_displays       = ARRAY_SIZE(s3c2440_lcd_cfg),
            .default_display = 0,
        .gpccon =       0xaa955699,
        .gpccon_mask =  0xffc003cc,
        .gpcup =        0x0000ffff,
        .gpcup_mask =   0xffffffff,


        .gpdcon =       0xaa95aaa1,
        .gpdcon_mask =  0xffc0fff0,
        .gpdup =        0x0000faff,
        .gpdup_mask =   0xffffffff,
         //.lpcsel             = ((0xCE6) & ~7) | 1<<4, 显示不正常

         .lpcsel             = 0xf82   //.plcsel对于着TCONSEL寄存器

};
#在函数smdk2410_init()中加入s3c24xx_fb_set_platdata(&s3c2440_fb_info);

>幕后使者drivers/vidio/s3c2410fb.c:s3c2410fb_calculate_tft_lcd_regs,调用关系:
s3c2410fb_ops->s3c2410fb_set_par->s3c2410fb_activate_var->s3c2410fb_calculate_tft_lcd_regs
static void s3c2410fb_calculate_tft_lcd_regs(const struct fb_info *info,
                                                                       struct s3c2410fb_hw *regs)
{
const struct s3c2410fb_info *fbi = info->par;
const struct fb_var_screeninfo *var = &info->var; switch (var->bits_per_pixel) {
case 1:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT1BPP;
  break;
case 2:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT2BPP;
  break;
case 4:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT4BPP;
  break;
case 8:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT8BPP;
  regs->lcdcon5 |= S3C2410_LCDCON5_BSWP |
                              S3C2410_LCDCON5_FRM565;
  regs->lcdcon5 &= ~S3C2410_LCDCON5_HWSWP;
  break;
case 16:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT16BPP;
  regs->lcdcon5 &= ~S3C2410_LCDCON5_BSWP;
  regs->lcdcon5 |= S3C2410_LCDCON5_HWSWP;
  break;
case 32:
  regs->lcdcon1 |= S3C2410_LCDCON1_TFT24BPP;
  regs->lcdcon5 &= ~(S3C2410_LCDCON5_BSWP |
                                  S3C2410_LCDCON5_HWSWP |
                                  S3C2410_LCDCON5_BPP24BL);
  break;
default:
  /* invalid pixel depth */
  dev_err(fbi->dev, "invalid bpp %d\n",
  var->bits_per_pixel);
}
/* update X/Y info */
dprintk("setting vert: up=%d, low=%d, sync=%d\n",
  var->upper_margin, var->lower_margin, var->vsync_len);

dprintk("setting horz: lft=%d, rt=%d, sync=%d\n",
  var->left_margin, var->right_margin, var->hsync_len);



regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
                          S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
                          S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
                          S3C2410_LCDCON2_VSPW(var->vsync_len - 1);

regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
                           S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
                           S3C2410_LCDCON3_HOZVAL(var->xres - 1);

regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
}

regs->lcdcon2 = S3C2410_LCDCON2_LINEVAL(var->yres - 1) |
                          S3C2410_LCDCON2_VBPD(var->upper_margin - 1) |
                          S3C2410_LCDCON2_VFPD(var->lower_margin - 1) |
                          S3C2410_LCDCON2_VSPW(var->vsync_len - 1);

regs->lcdcon3 = S3C2410_LCDCON3_HBPD(var->right_margin - 1) |
                           S3C2410_LCDCON3_HFPD(var->left_margin - 1) |
                           S3C2410_LCDCON3_HOZVAL(var->xres - 1);

regs->lcdcon4 = S3C2410_LCDCON4_HSPW(var->hsync_len - 1);
与参考参数比较
       .lcdcon2 =    S3C2410_LCDCON2_VBPD(1) | \
                            S3C2410_LCDCON2_LINEVAL(319) | \
                            S3C2410_LCDCON2_VFPD(5) | \
                            S3C2410_LCDCON2_VSPW(1),
        .lcdcon3 =    S3C2410_LCDCON3_HBPD(36) | \
                            S3C2410_LCDCON3_HOZVAL(239) | \
                            S3C2410_LCDCON3_HFPD(19),
        .lcdcon4 =    S3C2410_LCDCON4_MVAL(13) | \
                            S3C2410_LCDCON4_HSPW(5),

这样就可以得到:upper_margin =1+1 =2
                            lower_margin  =5+1 =6
                            vsync_len        =1+1 =2
                            hsync_len         =5+1 =6
                            right_margin     =36+1=37
                            left_margin        =19+1=20

HCLK 可以在开发板启动时在串口终端上得到:
……………………

CPU S3C2440A (id 0x32440001)
S3C244X: core 400.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
S3C24XX Clocks, (c) 2004 Simtec Electronics

……………………
100.000 MHz就是HCLK
.pixclock = 1/(HCLK/(CLKVAL*2))=1/(100MHz/(4*2))=8/(100MHz)
                                                    =80000*10^(-12)s
                                                    =80000ps(飞秒)

4配置内核,启用graphic device里面的frambuffer.并打开boot logo重新编译内核,看看启动信息
……
io scheduler cfq registered
Console: switching to colour frame buffer device 30x40
fb0: s3c2410fb frame buffer device
……

同时可以看到LCD上出现了小企鹅,不过出乎意料的是本应该只出现一只小企鹅的,结果出现了两只,且光标下移。以此可断定是参数长宽设置反了。最后作如下修改(红色部分 )
static struct s3c2410fb_display s3c2440_lcd_cfg[] __initdata = {
            {
              /* Config for 240x320 LCD */
              .lcdcon5 = S3C2410_LCDCON5_FRM565 |
                               S3C2410_LCDCON5_INVVLINE |
                               S3C2410_LCDCON5_INVVFRAME |
                               S3C2410_LCDCON5_PWREN |
                               S3C2410_LCDCON5_HWSWP,



              .type             = S3C2410_LCDCON1_TFT,
              .width            = 240

              .height          = 320

              .pixclock       = 125000, /* HCLK/(CLKVAL*2) */
              .xres              = 240

              .yres             = 320

              .bpp              = 16,
              .left_margin   = 20,
              .right_margin       = 37,
              .hsync_len    = 6,
              .upper_margin     = 2,
              .lower_margin      = 6,
              .vsync_len    = 2,
    }
};

重新编译下载,正常了。
注:本人以前的出现在lcd不亮的情况,好像背光的驱动也有问题。但没去管。在arch/arm /mach-s3c2440/mach_smdk2440.c中,lcd初始化函数smdk2440_machine_iniit()中加下这两句就可以了。
s3c2410_gpio_cfgpin(S3C2410_GPG4, S3C2410_GPG4_OUTP);
s3c2410_gpio_setpin(S3C2410_GPG4, 1);
阅读(2213) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~