编译工具:arm-linux-gcc 4.3.3
使用源码包:linux-2.6.31.tar.bz2(ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.31.9.tar.bz2)(过程中还从别的源码包复制文件)
使用平台:radhet5.5服务器版
使用开发板:TQ2440
参考资料:《linux2.6.31移植》天祥电子 《LINUX移植之Sept By Sept》天嵌科技
实验步骤:
支持架构:
1、解压源码包到/opt/EmbedSky/linux-2.6.30,解压后自动新建目录为linux-2.6.31.9。以下步骤中所说根目录基于该文件夹,工具与环境变量设置详见我以前报告或百度。
2、打开跟目录下的Makefile,找到
ARCH ? = arm
CROSS_COMPILE ? = arm-linux-
注意,红色字体为工具设置。
在1243行后加上rm zImage(distclean命令内)如下
-type f –print | xargs rm –f rm zImage
这样,以后执行# make distclean 会把根目录内的内核镜像删除,本来生成的zImage是不在根目录下的,等下通过修改相应文件把它设置复制到根目录
3、修改arch/arm/mach-s3c2440/mach-smdk2440.c
static void __init smdk2440_map_io(void)
{
s3c24xx_init_io(smdk2440_iodesc, ARRAY_SIZE(smdk2440_iodesc));
s3c24xx_init_clocks(12000000);
s3c24xx_init_uarts(smdk2440_uartcfgs, ARRAY_SIZE(smdk2440_uartcfgs));
}
注意:这数值错了,串口打印乱码
4、修改 arch/arm/tools/mach-types 的379行找到
s3c2440 ARCH_S3C2440 S3C2440 XXX
把XXX改为你的机器码,和之前的bootloader的机器码一样数值,我的机器码为168.
5、使用命令#make menuconfig
进入Load an Alternate Configuration File
输入2440的默认配置文件:arch/arm/configs/s3c2410_defconfig选择OK
在System Type选单下,s3c24XX Machine(XX表示随机字符)那部分,只选中以下一样的选项(空格选中),s3c24XX Machine其他选项都关了
SMDK2410/A9M2410
SMDK2440
SMDK2440 with S3C2440 cpu moudle
还有配置Kernel Features 选单下
[*] Use the ARM EABI to compile the kernel
[*] Allow old ABI binaries to run with this kernel
这样,内核就支持EABI编译了,不然系统可能会出错。
6、修改arch/ram/boot/下的Makefile文件,在第57行下面添加:
@cp –f arch/arm/boot/zImage zImage
即在@echo ` Kernel: $@ is ready`上方。这就是前面提到的把生成的内核镜像复制到根目录。
7、使用命令# make zImage 开始编译内核zImage文件,会生成在根目录下。
8、编译成功后烧进NAND FLASH里,看看运行是否成功,成功会打印一大堆启动代码。注:最好不要轻易使用#make distclean 这样配置文件得重新配置,或者在使用命令前先备份。
支持NAND FLASH:
9、static struct mtd_partition smdk_default_nand_part[] = {
#if defined(CONFIG_64M_NAND)
[0] = {
.name = "boot", /*分区名*/
.offset = 0, /*起始地址*/
.size = SZ_1M, /*分区大小*/
},
[1] = {
.name = "kernel",
.offset = SZ_1M + SZ_128K,
.size = SZ_4M,
},
[2] = {
.name = "yaffs2",
.offset = SZ_1M + SZ_128K + SZ_4M,
.size = SZ_64M - SZ_4M - SZ_1M - SZ_128K,
}
#elif defined(CONFIG_256M_NAND)
[0] = {
.name = "boot",
.offset = 0,
.size = SZ_1M,
},
[1] = {
.name = "kernel",
.offset = SZ_1M + SZ_128K,
.size = SZ_4M,
},
[2] = {
.name = "yaffs2",
.offset = SZ_1M + SZ_128K + SZ_4M,
.size = SZ_256M - SZ_4M - SZ_1M - SZ_128K,
}
#endif
};
之前由于直接辅助,有一个符号是全角的,搞了大半天,不过这代码改正的了。以上分区名可自行更改。
修改下面的数值,用于NAND的读写延时,一般不重要,可不改。
static struct s3c2410_platform_nand smdk_nand_info = {
.tacls = 10,
.twrph0 = 25,
.twrph1 = 10,
.nr_sets = ARRAY_SIZE(smdk_nand_sets),
.sets = smdk_nand_sets,
};
10、修改driver/mtd/nand/Kconfig,在172行(即config MTD_NAND_NDFC
上方),添加:
choice
prompt "Nand Flash Capacity Select"
depends on MTD
config 64M_NAND
boolean "64M NAND For TX-2440A"
depends on MTD
config 256M_NAND
boolean "256M NAND For TX-2440A"
depends on MTD
endchoice
11、修改配置表,使得内核支持NAND FLASH。
Device Drivers --->
<*> Memory Technology Device (MTD) support --->
[*] MTD partitioning support
<*> NAND Device Support --->
<*> NAND Flash support for S3C2410/S3C2440 SoC
[*] S3C2410 NAND Hardware ECC //这个一定要选上
Nand Flash Capacity Select(256M Nand For TX-2440A)--->
12、编译#make zImage ,烧进系统。成功后打印的启动代码包含如下内容如下:
Creating 3 MTD partitions on "NAND 256MiB 3,3V 8-bit":
0x000000000000-0x000000100000 : "boot"
0x000000120000-0x000000520000 : "kernel"
0x000000520000-0x000010000000 : "yaffs2"
支持yaffs2系统:
13、下载yaffs2源码(在光盘资料/源码包/其他软件源码/目录下)
解压,进入yaffs2目录,执行:
#./patch-ker.sh c /………/linux-2.6.31/
这个是你的内核源码目录
这时内核源码fs目录下多了一个yaffs2目录,同时Makefile文件和Kconfig文件也增加了yaffs2的配置和编译条件。这里,如果你不想下载,也可以从你配套开发板的内核中的/fs/yaffs2直接拷贝这文件夹过来,还有/fs/目录下的Makefile和Kconfig替换原来的文件。
14、使用#make menuconfig进入配置。
File systems --->
Miscellaneous filesystems --->
<*> YAFFS2 file system support
[*] Autoselect yaffs2 format
其它默认或根据需要配置。
15、编译内核,烧写进开发板,成功后启动代码包含以下信息:
yaffs: dev is 32505858 name is "mtdblock2"
yaffs: passed flags ""
yaffs: Attempting MTD mount on 31.2, "mtdblock2"
yaffs: auto selecting yaffs2
block 736 is bad
block 1016 is bad
yaffs_read_super: isCheckpointed 0
VFS: Mounted root (yaffs filesystem) on device 31:2.
移植LCD驱动:
16、内核里已经有很完善的LCD驱动了,只要根据所用的LCD进行简单的修改,在内核源码drivers/video/s3c2410fb.c是LCD驱动的源码,首先要设置LCD的时钟频率,有一个计算公式,很复杂,不用管它,直接修改程序实现。
在第365行开始的函数:
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 = 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);
这几句是在s3c2410fb_display结构体中加入了setclkval变量,我们需要在结构体原型中加入这个变量,在arch/arm/mach-s3c2410/include/mach/fb.h中第40行加入:unsigned setclkval; /*clkval*/
17、修改arch/arm/mach-s3c2440/mach-smdk2440.c中第107行的结构体,我修改的参数如下(具体参数请查阅配套的芯片手册,不同的LCD参数有所不同):
107 static struct s3c2410fb_display smdk2440_lcd_cfg __initdata = {
108
109 .lcdcon5 = S3C2410_LCDCON5_FRM565 |
110 S3C2410_LCDCON5_INVVLINE |
111 S3C2410_LCDCON5_INVVFRAME |
112 S3C2410_LCDCON5_PWREN |
113 S3C2410_LCDCON5_HWSWP,
114
115 .type = S3C2410_LCDCON1_TFT,
116
117 .width = 480,
118 .height = 272,
119
120 .pixclock = 400, /* HCLK 100 MHz, divisor 10 */
121 .setclkval = 0x4,
122 .xres = 480,
123 .yres = 272,
124 .bpp = 16,
125 .left_margin = 19,
126 .right_margin = 10,
127 .hsync_len = 30,
128 .upper_margin = 4,
129 .lower_margin = 2,
130 .vsync_len = 8,
131 };
屏蔽掉第150行的语句:
// .lpcsel = ((0xCE6) & ~7) | 1<<4,
18、配置内核,支持LCD:
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
19、编译内核,运行,正常情况下显示包含如下:
配置内核,支持LCD:
Console: switching to colour frame buffer device 60x34
fb0: s3c2410fb frame buffer device
LCD参数不同,打印数据有所不同。
DM9000网卡移植:
20、修改arch/arm/mach-s3c2440/mach-smdk2440.c 160行
Platform_device结构体中,加入:
&s3c_device_dm9000,
21、修改arch/arm/plat-s3c24xx/devs.c 在最前面38行加入:
#include <linux/dm9000.h> //别忘加这个头文件
/*DM9000*/
static struct resource s3c_dm9000_resource[] = {
[0] = {
.start = S3C2410_CS4,
.end = S3C2410_CS4 + 3,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = S3C2410_CS4 + 4,
.end = S3C2410_CS4 + 4 + 3,
.flags = IORESOURCE_MEM,
},
[2] = {
.start = IRQ_EINT18, /*use eint18 GPG10*/
.end = IRQ_EINT18,
.flags = IORESOURCE_IRQ,
}
};
static struct dm9000_plat_data s3c_dm9000_platdata = {
.flags = DM9000_PLATF_16BITONLY,
};
static struct platform_device s3c_device_dm9000 = {
.name = "dm9000",
.id = 0,
.num_resources = ARRAY_SIZE(s3c_dm9000_resource),
.resource = s3c_dm9000_resource,
.dev = {
.platform_data = &s3c_dm9000_platdata,
}
};
EXPORT_SYMBOL(s3c_device_dm9000);
注意:编译时只出现一个warning
把devs.c中的这句:
static struct platform_device s3c_device_dm9000 = {
的static改成extern,就可以了
22、在arch/arm/plat-s3c/include/plat/devs.h中加入一行:
extern struct platform_device s3c_device_dm9000;
23、下面修改dm9000.c源码,在drivers/net/dm9000.c中:
添加头文件,在第43行加入:
#if defined(CONFIG_ARCH_S3C2410)
#include <mach/regs-mem.h>
#endif
指定注册时的中断触发方式,在第1019行加入:
static int dm9000_open(struct net_device *dev)
{
…………
irqflags |= IRQF_SHARED;
#if defined (CONFIG_ARCH_S3C2410)
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED|IRQF_TRIGGER_RISING,dev->name,dev))
#else
if(request_irq(dev->irq,&dm9000_interrupt,IRQF_SHARED,dev->name,dev))
#endif
//if (request_irq(dev->irq, &dm9000_interrupt, irqflags, dev->name, dev))
return -EAGAIN;
…………
}
设置BANK4, 设置MAC地址,在1215行,dm9000_probe函数中加入:
int ret = 0;
int iosize;
int i;
u32 id_val;
#if defined(CONFIG_ARCH_S3C2410)
unsigned int oldval_bwscon = *(volatile unsigned int *)S3C2410_BWSCON;
unsigned int oldval_bankcon4 = *(volatile unsigned int *)S3C2410_BANKCON4;
#endif
/* Init network device */
ndev = alloc_etherdev(sizeof(struct board_info));
if (!ndev) {
dev_err(&pdev->dev, "could not allocate device.\n");
return -ENOMEM;
}
在1231行加入:
SET_NETDEV_DEV(ndev, &pdev->dev);
dev_dbg(&pdev->dev, "dm9000_probe()\n");
#if defined(CONFIG_ARCH_S3C2410)
*((volatile unsigned int *)S3C2410_BWSCON) = (oldval_bwscon & ~(3<<16)) | S3C2410_BWSCON_DW4_16 | S3C2410_BWSCON_WS4 | S3C2410_BWSCON_ST4;
*((volatile unsigned int *)S3C2410_BANKCON4) = 0x1f7c;
#endif
在1390行加入:
db->mii.mdio_read = dm9000_phy_read;
db->mii.mdio_write = dm9000_phy_write;
#if defined(CONFIG_ARCH_S3C2410)
printk("Now use the default MAC address: 08:90:90:90:90:90 ");
mac_src = "www.";
ndev->dev_addr[0] = 0x08;
ndev->dev_addr[1] = 0x90;
ndev->dev_addr[2] = 0x90;
ndev->dev_addr[3] = 0x90;
ndev->dev_addr[4] = 0x90;
ndev->dev_addr[5] = 0x90;
#else
mac_src = "eeprom";
/* try reading the node address from the attached EEPROM */
for (i = 0; i < 6; i += 2)
dm9000_read_eeprom(db, i / 2, ndev->dev_addr+i);
if (!is_valid_ether_addr(ndev->dev_addr) && pdata != NULL) {
mac_src = "platform data";
memcpy(ndev->dev_addr, pdata->dev_addr, 6);
}
if (!is_valid_ether_addr(ndev->dev_addr)) {
/* try reading from mac */
mac_src = "chip";
for (i = 0; i < 6; i++)
ndev->dev_addr[i] = ior(db, i+DM9000_PAR);
}
if (!is_valid_ether_addr(ndev->dev_addr))
dev_warn(db->dev, "%s: Invalid ethernet MAC address. Please " "set using ifconfig\n", ndev->name);
#endif
platform_set_drvdata(pdev, ndev);
ret = register_netdev(ndev);
if (ret == 0)
printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n",
ndev->name, dm9000_type_to_char(db->type),
db->io_addr, db->io_data, ndev->irq,
ndev->dev_addr, mac_src);
return 0;
out:
#if defined(CONFIG_ARCH_S3C2410)
*(volatile unsigned int *)S3C2410_BWSCON = oldval_bwscon;
*(volatile unsigned int *)S3C2410_BANKCON4 = oldval_bankcon4;
#endif
24、配置内核支持DM9000:
配置内核,支持网卡:
Device Drivers --->
[*] Network device support --->
[*] Ethernet(10 or 100 Mbit) --->
<*> DM9000 support
(4) DM9000 maximum debug level
25、烧写成功,启动内核,打印包含如下:
dm9000 Ethernet Driver, V1.31
Now use the default MAC address: 08:90:90:90:90:90
eth0: dm9000e at c486e000,c4872004 IRQ 62 MAC: 08:90:90:90:90:90
移植SD卡驱动:
26、在arch/arm/mach-s3c2440/mach-smdk2440.c plat_device结构体中加入:
&s3c_device_sdi,
27、修改drivers/mmc/host/s3cmci.c 在1335行加入
host->irq_cd = IRQ_EINT16;
s3c2410_gpio_cfgpin(S3C2410_GPG(8), S3C2410_GPG8_EINT16);
这两句指定SD的中断为EINT16
修改同文件,屏蔽掉1358-1359行:
if (s3c2410_dma_request(S3CMCI_DMA, &s3cmci_dma_client, NULL) < 0) {
dev_err(&pdev->dev, "unable to get DMA channel.\n");
// ret = -EBUSY;
// goto probe_free_irq_cd;
}
再将1147-1148行输出的多余信息屏蔽掉:
if ((ios->power_mode == MMC_POWER_ON) ||
(ios->power_mode == MMC_POWER_UP)) {
// dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
// host->real_rate/1000, ios->clock/1000);
} else {
dbg(host, dbg_conf, "powered down.\n");
}
28、配置内核支持SD,如下:
Device Drivers --->
<*> MMC/SD/SDIO card support --->
<*> MMC block device driver
<*> Use bounce buffer for simple hosts
<*> Sumsung S3C SD/MMC Card Interface support
同时还要配置支持SD文件系统,以免挂载时出错,配置如下:
File systems --->
DOS/FAT/NT Filesystems --->
<*> MSDOS fs support
<*> VFAT (Windows-95) fs support
29、编译内核,烧写到开发板,打印信息包含如下:
s3c2440-sdi s3c2440-sdi: powered down.
s3c2440-sdi s3c2440-sdi: initialisation done.
USB设备驱动移植:
30、由于内核中给出的USB驱动已经非常完整,所以我们只需修改下配置,如下:
Device drivers --->
SCSI Device support --->
<*> SCSI device support
[*] legacy /proc/scsi/ support
<*> SCSI disk support
[*] HID Devices --->
<*> USB Human Interface Device (full HID) support
[*] /dev/hiddev raw HID device support
[*] USB support --->
<*> Support for Host-side USB
[*] USB device filesystem
[*] USB device class-devices(DEPRECATED)
<*> USB Monitor
<*> OHCI HCD support
<*> USB Mass Storage support
USB Human Interface Device (full HID) support 是对USB鼠标键盘的支持
SCSI disk support 和USB Mass Storage support 是对U盘的支持
31、编译内核,烧写开发板,成功后打印包含如下:
usb usb1: configuration #1 chosen from 1 choice
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 2 ports detected
usbcore: registered new interface driver libusual
usbcore: registered new interface driver usbserial
USB Serial support registered for generic
usbcore: registered new interface driver usbserial_generic
usbserial: USB Serial Driver core
USB Serial support registered for FTDI USB Serial Device
usbcore: registered new interface driver ftdi_sio
ftdi_sio: v1.5.0:USB FTDI Serial Converters Driver
USB Serial support registered for pl2303
usbcore: registered new interface driver pl2303
如果我们插入U盘,可以看到如下信息:
usb 1-1: new full speed USB device using s3c2410-ohci and address 2
usb 1-1: configuration #1 chosen from 1 choice
scsi0 : SCSI emulation for USB Mass Storage devices
scsi 0:0:0:0: CD-ROM Lenovo USB Flash Drive 1100 PQ: 0 ANSI: 2
scsi 0:0:0:1: Direct-Access Lenovo USB Flash Drive 1100 PQ: 0 ANSI: 0 CCS
scsi 0:0:0:0: Attached scsi generic sg0 type 5
sd 0:0:0:1: [sda] 7874560 512-byte logical blocks: (4.03 GB/3.75 GiB)
sd 0:0:0:1: [sda] Write Protect is off
sd 0:0:0:1: [sda] Assuming drive cache: write through
sd 0:0:0:1: Attached scsi generic sg1 type 0
sd 0:0:0:1: [sda] Assuming drive cache: write through
sda: sda4
sd 0:0:0:1: [sda] Assuming drive cache: write through
sd 0:0:0:1: [sda] Attached SCSI removable disk
FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
FAT: IO charset utf8 not found
上面的sda4为U盘所在目录名字,我们可以用# mount /dev/sda4 /mnt/udisk 把U盘挂载到udisk/目录,就可以查看编辑文件了。
RTC驱动移植:
32、由于内核自带了RTC驱动,所以只需做小修改。
在arch/arm/mach-s3c2440/mach-smdk2440.c中添加RTC设备,在plat_device结构体中加入:
&s3c_device_rtc,
33、对RTC驱动配置,如下:
Device Drivers --->
<*>Real Time Clock --->
[*]Set system time from RTC on startup and resume
(rtc0) rtc used to set the system time
[*]/sys/class/rtc/rtcN(sysfs)
[*]/proc/driver/rtc(procfs for rtc0)
[*]/dev/rtcN(character drivers)
<*>Samsung S3C series SoC RTC
34、编译内核,烧写开发板,成功后打印包含如下:
S3C24XX Clocks, (c) 2004 Simtec Electronics
S3C244X: core 400.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
注:不同内核打印可能有所不同。不过基本都包含(c) 2004 Simtec Electronics。
#date 输入命令
Thu Jan 1 00:01:36 UTC 1970 显示时间
#date –s date -s 2013.07.30-15:35:40 设置时间格式:年.月.日-时:分:秒
Tue Jul 30 15:35:40 UTC 2013
#hwclock –w 保存时间
触摸屏驱动移植:
35、由于自带触摸屏驱动和开发板触摸屏驱动有较大差别,故需要使用合适的驱动(我的开发板为TQ2440,故以天嵌的资料作参考)。从天嵌配套的源码中的 drivers/input/touchsreen/目录下拷贝tq2440_ts.c到你自己修改的内核相应的目录下。修改该文件的41行如下:
//extern struct semaphore ADC_LOCK ; //这是原来的内容
DECLARE_MUTEX(ADC_LOCK); //修改后内容
这里修改主要是因为原来提供的包含了ADC驱动的ADC_LOCK,而这里没移植ADC,故做出修改。
36、修改该目录下Kconfig文件,在第468行加入:
config TOUCHSCREEN_TQ2440
tristate "EmbedSky TQ2440 TouchScreen input driver"
depends on ARCH_S3C2410 && INPUT && INPUT_TOUCHSCREEN
help
Say Y here if you have the tq2410 TouchScreen.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called tq2410_ts.
37、在Makefile中的最后添加:
obj-$(CONFIG_TOUCHSCREEN_TQ2440) += tq2440_ts.o
38、配置内核,支持触摸屏:
Device Drivers --->
Character devices --->
[*] ADC driver for S3C2440 development boards
Input devices support --->
<*> Event interface
[*] Touchscreens --->
<*> Samsung S3C2410 touchscreen input driver
39、编译内核,烧写进开发板,如果成功则打印包含如下:
TQ2440 TouchScreen successfully loaded
input: TQ2440 TouchScreen as /class/input/input0
心得与体会:过了几天了,天天不停的编译,不停的改错,不停的烧写。现在终于告一段落了。这次内核移植,大多数都是跟着教程做,不过还是那样,讲的人不会错,听的人就难说了。其实内核移植两天前就完成了,不过少了些必要的驱动,于是又根据教程移植了一些必要的驱动。-。-不过声卡驱动有问题(PS:这个驱动花了我一天也没搞出来),可以编译,运行时出现问题,具体问题我也查不出,还没到那能力。在内核移植过程中,能力又有所提高,开始体会到驱动的感觉了,有了大概的思路。不同公司的教程、视频、板子、源码,搞得我又看这个又看那个,晕头转向的。
总的来说,这次内核移植还是相当有意义的,让我知道了驱动和内核大概的雏形。接下来这几天准备看看一些基础的内容,学得太快,基础相当不稳。然后如果有心思就开始进入编写简单驱动了。