宿主机环境:
Linux version 2.6.32-24, Ubuntu10.04
gcc version 4.1.3, Thread model: posix;
GNU Make 3.81
arm-linux-gcc 3.4.5
开发板环境:
CPU: S3C2410X
SDRAM: HY57V561620(32MB)
FLASH: K9F1208(64MB)
Linux Kernel: 2.6.23.8
移植步骤:
运行kernel的时候,我们会发现如下的错误:
JFFS2 version 2.2. (NAND) .. 2001-2006 Red Hat, Inc.
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
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
ppdev: user-space parallel port driver
Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
s3c2410-uart.0: s3c2410_serial0 at MMIO 0×50000000 (irq = 70) is a S3C2410
s3c2410-uart.1: s3c2410_serial1 at MMIO 0×50004000 (irq = 73) is a S3C2410
s3c2410-uart.2: s3c2410_serial2 at MMIO 0×50008000 (irq = 76) is a S3C2410
RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
表示与LCD相关的平台信息没有找到,因此没法加载LCD。 我们所要做的就是将对LCD设备的初始化加入到整个S3C2410的初始化过程中。
通过对arch/arm/mach-smdk2410/mach-smdk2410.c与arch/arm/mach-smdk2440/mach-smdk2440.c进行对比后,可以发现在smdk2440上存在着对结构体s3c2410fb_mach_info的初始化,而smdk2410则不存在,所以我们所要做的是把smdk2440上的初始化操作复制到smdk2410上,并做一定的修改。
rookiesean@rookiesean-desktop:~/workspace/linux-2.6.23.8$ vim arch/arm/mach-s3c2410/mach-smdk2410.c
#include <asm/plat-s3c24xx/common-smdk.h>
#include <asm/arch/smdk2410.h> // sean chi 18Aug2010, added.
#include <asm/arch/fb.h> // sean chi 31Aug2010, added.
static struct map_desc smdk2410_iodesc[] __initdata = {
{ vSMDK2410_ETH_IO , pSMDK2410_ETH_IO, SZ_1M, MT_DEVICE }, // sean chi 18Aug2010, added.
/* nothing here yet */
};// sean chi 31Aug2010, added.
static struct s3c2410fb_mach_info nano2410_fb_info __initdata = {
.fixed_syncs = 1,
.type = S3C2410_LCDCON1_TFT,
.width = 240,
.height = 320,
.xres = {
.min = 240,
.max = 240,
.defval = 240,
},.yres = {
.min = 320,
.max = 320,
.defval = 320,
},.bpp = {
.min = 16,
.max = 16,
.defval = 16,
},
.regs = {.lcdcon1 = S3C2410_LCDCON1_TFT16BPP |
S3C2410_LCDCON1_TFT |
S3C2410_LCDCON1_CLKVAL(0×04),.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,
},
#if 1
.gpccon =0xaaaaaaaa,
.gpccon_mask =0xffffffff,
.gpcup =0xffffffff,
.gpcup_mask =0xffffffff,.gpdcon =0xaaaaaaaa,
.gpdcon_mask =0xffffffff,
.gpdup =0xffffffff,
.gpdup_mask =0xffffffff,#endif
.lpcsel = 0×01,
};……
…….
static void __init smdk2410_init(void)
{
s3c24xx_fb_set_platdata(&nano2410_fb_info); // sean chi 31Aug2010, added.
platform_add_devices(smdk2410_devices, ARRAY_SIZE(smdk2410_devices));
smdk_machine_init();
}
在对源代码进行修改了以后,配置内核,将Device Driver->Graphic support下的Support for frame buffer devices, S3C2410 LCD framebuffer support和Bootup logo勾选上。
rookiesean@rookiesean-desktop:~/workspace/linux-2.6.23.8$ make menuconfig
Device Driver –>
Graphics support ->
<*>Support for frame buffer devices
<*>S3C2410 LCD framebuffer support
<*>Bootup logo
对于其他版本来说,在这里可以重新编译内核,加载到开发板上运行就可以了,但在linux kernel 2.6.23上,这还不够,这时候如果编译加载的话,会在开发板上显示如下结果:
io scheduler noop registered
io scheduler anticipatory registered (default)
io scheduler deadline registered
io scheduler cfq registered
Unable to handle kernel NULL pointer dereference at virtual address 00000014
pgd = c0004000
[00000014] *pgd=00000000
Internal error: Oops: 805 [#1]
Modules linked in:
CPU: 0 Not tainted (2.6.23.8 #18)
PC is at s3c2410fb_set_lcdaddr+0×94/0xb4
LR is at 0xc02fdb48
pc : [] lr : [] psr: 60000013
sp : c03ebe24 ip : c02fdb48 fp : c03ebe40
r10: c02fc714 r9 : c0333d60 r8 : c02fc70c
r7 : c0305358 r6 : 19e80000 r5 : 19e92c00 r4 : 000000f0
r3 : 00000014 r2 : 00000001 r1 : 00000001 r0 : 00000025
Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel
Control: c000717f Table: 30004000 DAC: 00000017
Process swapper (pid: 1, stack limit = 0xc03ea258)
Stack: (0xc03ebe24 to 0xc03ec000)
be20: c3c4025c c4a00000 c0305358 c0333d60 c03ebe60 c03ebe44 c014f03c
be40: c014e500 00000000 c3c4025c c3c40000 00000000 c03ebe9c c03ebe64 c001afa0
be60: c014ef7c c3c4025c c3c400a8 00000020 c03dd454 c02fc714 00000000 c03052c8
be80: c03052c8 c0337038 c0024860 00000000 c03ebeac c03ebea0 c0179df0 c001aad4
bea0: c03ebed0 c03ebeb0 c0177f30 c0179de0 c02fc7d4 c02fc714 c0178090 c03052c8
bec0: c03ea000 c03ebee8 c03ebed4 c0178110 c0177e58 00000000 c03ebeec c03ebf14
bee0: c03ebeec c0176f44 c01780a0 c0309250 c0309250 c02fc75c 00000000 c03052c8
bf00: c03052d0 c0309164 c03ebf24 c03ebf18 c0178190 c0176f04 c03ebf4c c03ebf28
bf20: c017770c c0178180 c03052c8 00000000 00000000 c0023410 c03ea000 00000000
bf40: c03ebf60 c03ebf50 c017860c c01776a8 00000000 c03ebf70 c03ebf64 c0179f04
bf60: c017859c c03ebf80 c03ebf74 c014f284 c0179ea8 c03ebff4 c03ebf84 c0008c3c
bf80: c014f280 e1a00007 e89da9f0 00000000 00000001 e24cb004 00000000 00000000
bfa0: 00000000 c03ebfb0 c002cec4 c0044b38 00000000 00000000 c0008b5c c004aee8
bfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
bfe0: 00000000 00000000 00000000 c03ebff8 c004aee8 c0008b6c 1580302c e5943018
Backtrace:
[] (s3c2410fb_set_lcdaddr+0×0/0xb4) from [] (s3c2410fb_init_registers+0xd0/0×144)
r7:c0333d60 r6:c0305358 r5:c4a00000 r4:c3c4025c
[] (s3c2410fb_init_registers+0×0/0×144) from [] (s3c2410fb_probe+0x4dc/0x5e8)
r7:00000000 r6:c3c40000 r5:c3c4025c r4:00000000
[] (s3c2410fb_probe+0×0/0x5e8) from [] (platform_drv_probe+0×20/0×24)
[] (platform_drv_probe+0×0/0×24) from [] (driver_probe_device+0xe8/0x18c)
[] (driver_probe_device+0×0/0x18c) from [] (__driver_attach+0×80/0xe0)
r8:c03ea000 r7:c03052c8 r6:c0178090 r5:c02fc714 r4:c02fc7d4
[] (__driver_attach+0×0/0xe0) from [] (bus_for_each_dev+0×50/0×84)
r5:c03ebeec r4:00000000
[] (bus_for_each_dev+0×0/0×84) from [] (driver_attach+0×20/0×28)
r7:c0309164 r6:c03052d0 r5:c03052c8 r4:00000000
[] (driver_attach+0×0/0×28) from [] (bus_add_driver+0×74/0x1b0)
[] (bus_add_driver+0×0/0x1b0) from [] (driver_register+0×80/0×88)
[] (driver_register+0×0/0×88) from [] (platform_driver_register+0x6c/0×88)
r4:00000000
[] (platform_driver_register+0×0/0×88) from [] (s3c2410fb_init+0×14/0x1c)
[] (s3c2410fb_init+0×0/0x1c) from [] (kernel_init+0xe0/0x29c)
[] (kernel_init+0×0/0x29c) from [] (do_exit+0×0/0×748)
Code: e3530000 e1a01004 1bfbec4f e3a03014 (e4836004)
Kernel panic – not syncing: Attempted to kill init!
通过上面错误信息中的Backtrace,可以看到问题出在一个名为s3c2410fb_lcd_setaddr的函数上。在源代码中找到这个函数,存在于drivers/video/s3c2410fb.c文件里,通过对Linux 2.6.22, 2.6.23, 2.6.24的对比,发现对这段函数做如下代码修改即可,原因末知,发了邮件给写这部分代码的Ben Dooks大神询问,末回。。。
static void s3c2410fb_set_lcdaddr(struct s3c2410fb_info *fbi)
{
struct fb_var_screeninfo *var = &fbi->fb->var;
void __iomem *regs = fbi->io; // sean chi 31Aug2010, added.
unsigned long saddr1, saddr2, saddr3;saddr1 = fbi->fb->fix.smem_start >> 1;
saddr2 = fbi->fb->fix.smem_start;
saddr2 += (var->xres * var->yres * var->bits_per_pixel)/8;
saddr2>>= 1;saddr3 = S3C2410_OFFSIZE(0) | S3C2410_PAGEWIDTH((var->xres * var->bits_per_pixel / 16) & 0x3ff);
dprintk(“LCDSADDR1 = 0x%08lx\n”, saddr1);
dprintk(“LCDSADDR2 = 0x%08lx\n”, saddr2);
dprintk(“LCDSADDR3 = 0x%08lx\n”, saddr3);writel(saddr1, regs + S3C2410_LCDSADDR1); // sean chi 31Aug2010, was writel(saddr, S3C2410_LCDSADDR1);
writel(saddr2, regs + S3C2410_LCDSADDR2);
writel(saddr3, regs + S3C2410_LCDSADDR3);
}
除此之外,还要把drivers/video/fbmem.c中的register_framebuffer做如下修改:
/**
* register_framebuffer – registers a frame buffer device
* @fb_info: frame buffer info structure
*
* Registers a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
*/int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
struct fb_videomode mode;if (num_registered_fb == FB_MAX)
return -ENXIO;
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++) if (!registered_fb[i]) break; fb_info->node = i;fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), “fb%d”, i);
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING “Unable to create device for framebuffer %d; errno = %ld\n”, i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);if (fb_info->pixmap.addr == NULL) {
fb_info->pixmap.addr = kmalloc(FBPIXMAPSIZE, GFP_KERNEL);
if (fb_info->pixmap.addr) {
fb_info->pixmap.size = FBPIXMAPSIZE;
fb_info->pixmap.buf_align = 1;
fb_info->pixmap.scan_align = 1;
fb_info->pixmap.access_align = 32;
fb_info->pixmap.flags = FB_PIXMAP_DEFAULT;
}
}
fb_info->pixmap.offset = 0;if (!fb_info->pixmap.blit_x)
fb_info->pixmap.blit_x = ~(u32)0;if (!fb_info->pixmap.blit_y)
fb_info->pixmap.blit_y = ~(u32)0;if (!fb_info->modelist.prev || !fb_info->modelist.next)
INIT_LIST_HEAD(&fb_info->modelist);fb_var_to_videomode(&mode, &fb_info->var);
fb_add_videomode(&mode, &fb_info->modelist);
registered_fb[i] = fb_info;event.info = fb_info;
// sean chi 31Aug2010, removed. fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);return 0;
}
否则将会出现kernel的启动过程hang掉的情况,至于为什么这么改的原因。。。我也不知道,同样问了Ben Dooks大神,没回。。。
对Linux2.6.23进行这样的修改将会导致启动后LCD屏上不会显示LOGO, 原因在于Linux启动时LOGO的加载是由fb_notifier_call_chain调用的,但由于我们之前把fb_notifier_call_chain从启动过程中去掉了,因此我们不会看到LOGO,但通过编写应用程序对/dev/fb0进行读写依然可以在LCD屏上画出图像。

Comments