Linux-2.6.32.67内核裁剪与移植之LCD驱动的移植
作者:赵凯
QQ: 1205958201
注:转载请注明出处哦
内核源码中的“drivers/video/s3c2410fb.c”就是LCD的驱动了。
在该文件中找到函数static void s3c2410fb_activate_var(struct fb_info *info),修改如下:
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;
struct s3c2410fb_mach_info *mach_info = fbi->dev->platform_data;
struct s3c2410fb_display *default_display = mach_info->displays +
mach_info->default_display;
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);
fbi->regs.lcdcon1|=S3C2410_LCDCON1_CLKVAL(default_display->setclkval);
/* write new registers */
dprintk("new register set:\n");
dprintk("lcdcon[1] = 0x%08lx\n", fbi->regs.lcdcon1);
dprintk("lcdcon[2] = 0x%08lx\n", fbi->regs.lcdcon2);
dprintk("lcdcon[3] = 0x%08lx\n", fbi->regs.lcdcon3);
dprintk("lcdcon[4] = 0x%08lx\n", fbi->regs.lcdcon4);
dprintk("lcdcon[5] = 0x%08lx\n", fbi->regs.lcdcon5);
writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID,
regs + S3C2410_LCDCON1);
writel(fbi->regs.lcdcon2, regs + S3C2410_LCDCON2);
writel(fbi->regs.lcdcon3, regs + S3C2410_LCDCON3);
writel(fbi->regs.lcdcon4, regs + S3C2410_LCDCON4);
writel(fbi->regs.lcdcon5, regs + S3C2410_LCDCON5);
/* set lcd address pointers */
s3c2410fb_set_lcdaddr(info);
fbi->regs.lcdcon1 |= S3C2410_LCDCON1_ENVID,
writel(fbi->regs.lcdcon1, regs + S3C2410_LCDCON1);
}
这几句是在 s3c2410fb_display结构体中加入了setclkval变量,我们需要在结构体原型中加入这个变量,在arch/arm/mach-s3c2410/include/mach/fb.h中的s3c2410fb_display结构体中加入一行:
unsigned setclkval; /*clkval*/
然后需要修改LCD的参数设置
修改 arch/arm/mach-s3c2440/mach-smdk2440.c 文件中的static struct s3c2410fb_display smdk2440_lcd_cfg __initdata结构体:
修改结果如下:
static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
.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 = 100000, /* HCLK 60 MHz, divisor 10 */
.setclkval =0x3,
.xres = 320,
.yres = 240,
.bpp = 16,
.left_margin = 33,
.right_margin = 22,
.hsync_len = 44,
.upper_margin = 9,
.lower_margin = 3,
.vsync_len =15,
};
static struct s3c2410fb_mach_info smdk2440_fb_info __initdata = {
.displays = &smdk2440_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,
#endif
//.lpcsel = ((0xCE6) & ~7) | 1<<4,
};
然后配置内核,支持LCD:
键入:make menuconfig,然后配置如下:
Device Drivers:
Graphics Support --->
<*>support for frame buffer devices --->
[*] Enable frameware EDID
[*] Enable Vidoe Mode Handling Helpers
<*> S3C24X0 LCD framebuffer support
Console display driver support --->
<*> Framebuffer Console Support
[*] Bootup Logo --->
<*> Standard 224-color Linux logo
然后make uImage生成uImage文件,拷贝到tftp目录下:
[root@localhost linux-2.6.32.67]# cp arch/arm/boot/uImage /var/lib/tftpboot
下载到开发板中:
tftp 0x32000000 uImage;nand erase 0 400000
nand write.jffs2 0x32000000 0 $filesize
在输出结果中关于LCD出现以下错误:
s3c2410-lcd s3c2410-lcd: no platform data for lcd, cannot attach
s3c2410-lcd: probe of s3c2410-lcd failed with error -22
搜索下该错误:
[root@localhost linux-2.6.32.67]# grep 'no platform data for lcd, cannot attach' * -nR
得到的结果如下:
drivers/video/s3c2410fb.c:838: "no platform data for lcd, cannot attach\n");
进入该文件查看下上下文:
static int __init s3c24xxfb_probe(struct platform_device *pdev,
enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
struct s3c2410fb_display *display;
struct fb_info *fbinfo;
struct s3c2410fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
int i;
int size;
u32 lcdcon1;
mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
dev_err(&pdev->dev,
"no platform data for lcd, cannot attach\n");
return -EINVAL;
}
然后看下s3c2410fb_mach_info的定义:arch/arm/mach-s3c2410/include/mach/fb.h文件里面
struct s3c2410fb_mach_info {
struct s3c2410fb_display *displays; /* attached diplays info */
unsigned num_displays; /* number of defined displays */
unsigned default_display;
/* GPIOs */
unsigned long gpcup;
unsigned long gpcup_mask;
unsigned long gpccon;
unsigned long gpccon_mask;
unsigned long gpdup;
unsigned long gpdup_mask;
unsigned long gpdcon;
unsigned long gpdcon_mask;
/* lpc3600 control register */
unsigned long lpcsel;
};
再看下s3c2410fb_display的定义,也是在该文件中
/* LCD description */
struct s3c2410fb_display {
/* LCD type */
unsigned type;
/* Screen size */
unsigned short width;
unsigned short height;
/* Screen info */
unsigned short xres;
unsigned short yres;
unsigned short bpp;
unsigned setclkval; /*clkval*/
unsigned pixclock; /* pixclock in picoseconds */
unsigned short left_margin; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short right_margin; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short hsync_len; /* value in pixels (TFT) or HCLKs (STN) */
unsigned short upper_margin; /* value in lines (TFT) or 0 (STN) */
unsigned short lower_margin; /* value in lines (TFT) or 0 (STN) */
unsigned short vsync_len; /* value in lines (TFT) or 0 (STN) */
/* lcd configuration registers */
unsigned long lcdcon5;
};
。。。。。。
这个问题暂时无法解决,先放到一边。
添加对4.3寸LCD和7寸LCD的支持:
我们使用的3.5寸屏分辨率是320x240,4.3寸屏分辨率是480x272,7寸屏分辨率是800x480。同样修改arch/arm/mach-s3c2440/mach-smdk2440.c中第107行的结构体,加入4.3寸屏和7寸屏的配置参数。
static struct s3c2410fb_display smdk2440_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_W35)
.width = 320,
.height = 240,
.pixclock = 100000, /* HCLK 60 MHz, divisor 10 */
.setclkval =0x3,
.xres = 320,
.yres = 240,
.bpp = 16,
.left_margin = 33,
.right_margin = 22,
.hsync_len = 44,
.upper_margin = 9,
.lower_margin = 3,
.vsync_len =15,
#elif defined(CONFIG_FB_S3C2410_W43)
.width = 480,
.height = 272,
.pixclock = 40000,
.setclkval = 0x4,
.xres = 480,
.yres = 272,
.bpp = 16,
.left_margin = 19,
.right_margin = 10,
.hsync_len = 30,
.upper_margin = 4,
.lower_margin = 2,
.vsync_len = 8,
#elif defined(CONFIG_FB_S3C2410_Q70)
.width = 800,
.height = 480,
.pixclock = 40000,
.setclkval = 0x1,
.xres = 800,
.yres = 480,
.bpp = 16,
.left_margin = 40,
.right_margin = 40,
.hsync_len = 48,
.upper_margin = 13,
.lower_margin = 29,
.vsync_len = 3,
#endif
};
修改 drivers/video/Kconfig文件,在1923行加入:
choice
prompt "LCD size select"
depends on FB_S3C2410
help
s3c2410 lcd size select
config FB_S3C2410_W35
boolean"The 3.5 inch LCD with resolution 320X240"
depends on FB_S3C2410
help
3.5 inch LCD 320X240
config FB_S3C2410_W43
boolean "The 4.3 inch LCD with resolution 480X272"
depends on FB_S3C2410
help
4.3 inch LCD 480X272
config FB_S3C2410_Q70
boolean"The 7 inch LCD with resolution 800X480"
depends on FB_S3C2410
help
7 inch LCD 800X480
endchoice
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
配置内核,支持4.3寸LCD和7寸LCD:
Device Drivers:
Graphics Support --->
<*>support for frame buffer devices --->
<*> S3C24X0 LCD framebuffer support
LCD size select(The 3.5 inch LCD with resolution 320X240) --->
进入"LCD size select(The 3.5 inch LCD with resolution 320X240)--->"选项,在这里选择不同的LCD类型,按空格键即可选中,前面有"X"的表示选中的,如果我们要选择4.3寸屏,将光标移至第二行,按空格键,就选中了对4.3寸屏的支持。
( )The 3.5 inch LCD with resolution 320X240
(X)The 4.3 inch LCD with resolution 480X272(tq2440开发板使用的LCD大小)
( )The 7 inch LCD with resolution 800X480
然后将生成的uImage下载到开发板上运行。
同样的错误:
s3c2410-lcd s3c2410-lcd: no platform data for lcd, cannot attach
s3c2410-lcd: probe of s3c2410-lcd failed with error -22
说明内核没成功加载LCD驱动,为什么会出现这种情况呢,下面详细分析下:
首先看下LCD控制器的平台设备定义:arch/arm/plat-s3c24xx/devs.c文件
struct platform_device s3c_device_lcd = {
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = {
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};
这个s3c_device_lcd结构,在linux内核中已经分别加入了s3c2440、s3c2410开发板的设备列表中了。
在arch/arm/mach-s3c2410/mach-smdk2410.c文件中如下:
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
};
在arch/arm/mach-s3c2440/mach-smdk2440.c文件中如下:
static struct platform_device *smdk2440_devices[] __initdata = {
&s3c_device_usb,
&s3c_device_lcd,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_iis,
};
LCD控制器驱动程序drivers/video/s3c2410fb.c的入口函数为:
static struct platform_driver s3c2410fb_driver = {
.probe = s3c2410fb_probe,
.remove = s3c2410fb_remove,
.suspend = s3c2410fb_suspend,
.resume = s3c2410fb_resume,
.driver = {
.name = "s3c2410-lcd",
.owner = THIS_MODULE,
},
};
。。。。。
int __init s3c2410fb_init(void)
{
int ret = platform_driver_register(&s3c2410fb_driver);
if (ret == 0)
ret = platform_driver_register(&s3c2412fb_driver);
return ret;
}
从上面的代码段可以看出平台设备s3c_device_lcd和平台驱动s3c2410fb_drivers的名字都是“s3c2410-lcd”,所以当注册了s3c2410fb_drivers之后,它的s3c2410fb_probe函数将被调用来设置LCD控制器。
下面再看看刚刚出错的那段代码段:
static int __init s3c24xxfb_probe(struct platform_device *pdev,
enum s3c_drv_type drv_type)
{
struct s3c2410fb_info *info;
struct s3c2410fb_display *display;
struct fb_info *fbinfo;
struct s3c2410fb_mach_info *mach_info;
struct resource *res;
int ret;
int irq;
int i;
int size;
u32 lcdcon1;
mach_info = pdev->dev.platform_data;
if (mach_info == NULL) {
dev_err(&pdev->dev,
"no platform data for lcd, cannot attach\n");
return -EINVAL;
}
pdev就是指向了一个设备注册的指针,很明显该成员的dev.platform_data为空才会报错,这里需要配置一下内核,去掉与s3c2410相关的东东。。。
make menuconfig如下
System type-->
S3C2410 Machines-->
这个目录下的内容全部取消不选,然后生成uImage文件下载到开发板中即可看到美丽的切啦啦。
下一步制作开机启动LOGO:
这时候需要替换“drivers/video/logo/logo_linux_clut224.ppm”文件,首先复制开机的logo到linux系统中,然后使用GIMP工具进行编辑,由于我的redhat系统中没有该工具,需要安装。这里省去安装步骤。
图片的处理过程主要包括设置颜色数为224,保存为ppm文件,以ASII码的形式保存等等,具体可以参照tq开发板手册。
当图片处理完毕自后,将该文件复制到drivers/video/logo/文件夹下面替换原有的logo_linux_clut224.ppm文件即可。
然后重新生成uImage文件,下载到开发板上运行,即可看到我准备的开机LOGO。
总结:通过这次安装GIMP软件,我发现当安装一个软件需要另外安装许多依赖的时候,可以先到光盘里面找是否有这些依赖包,当然查询的依赖包的名字一定要正确,可以先到百度上搜下这个依赖包,然后再从光盘里面找;而从网上直接找该依赖包放到linux系统中安装是最后应该考虑的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)