操作系统的内核是应用程序赖以运行的环境,内核可以说是操作系统的核心部分。因为Linux是开源的操作系统,可以将不需要的功能进行裁剪,所以本设计将需要的功能添加,不需要的功能将删除,本设计的内核采用Linux2.6.35版本。
本人的开发环境是window10、VMWare 12.5.2和Ubuntu 16.04,交叉编译器是arm-2009q3具体的裁剪如下:
1.修改Makefile为:
export KBUILD_BUILDHOST := $(SUBARCH)
ARCH ?= arm
CROSS_COMPILE ?=/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)
2.进行配置生成.config文件
make smdkv210_android_defconfig
3.进一步配置, # make menuconfig
如果说你缺少ncurses libraries,则输入apt-get install ncurses-devc
串口配置,选择串口0
System Type --->
(0) S3C UART to use for low-level messages
Kernel hacking --->
(0) S3C UART to use for low-level debug
4.确定机器码
vi arch/arm/tools/mach-types
在433行可以看出,SMDKV210评估板的机器码是2456(16进制是0x998):
433 smdkv210 MACH_SMDKV210 SMDKV210 2456
可在末行加入,在uboot那里set machid 270f,或者把上面那行注释掉,加入下面那行,然后机器码改成2456.
gec210 MACH_GEC210 GEC210 9999
5.确定内核的加载地址与参数地址
vim arch/arm/mach-s5pv210/Makefile.boot
因为我们之前uboot的DDRch0内存 0x20000000~0x30000000,映射到了 0x30000000~0x40000000,所以我们要修改内核的加载地址和参数地址。
可以看出,内核的加载地址和参数地址分别为0x30008000和0x30000100,bootloader启动内核前应该将内核拷贝到0x30008000,并将参数放到0x30000100。
改为:
zreladdr-y += 0x30008000
params_phys-y := 0x30000100
6.移除max8698模块。Max8698是SMDKV210开发板上使用的电源管理芯片,而我们的开发板上并未使用。因此之前在移植uboot时我们屏蔽了该PMIC相关代码,现在移植kernel,也需要做相应处理,即在make menuconfig中去掉max8698模块。
make menuconfig
Device Drivers --->
[*] Multifunction device drivers --->
[ ] Maxim Semiconductor MAX8698 PMIC Support
[*] Voltage and Current Regulator Support --->
< > Maxim 8698 voltage regulator
7.修改Nand分区
drivers\mtd\nand\s3c_nand.c定义好了NandFlash的分区表,需要修改drivers\mtd\nand\s3c_nand.c文件:
vi drivers/mtd/nand/s3c_nand.c
struct mtd_partition s3c_partition_info[] = {
{
.name = "uboot",
.offset = 0, /* for bootloader */
.size = (1*SZ_1M),
.mask_flags = MTD_CAP_NANDFLASH,
},
{
.name = "recovery",
.offset = MTDPART_OFS_APPEND,
.size = (5*SZ_1M),
},
{
.name = "kernel",
.offset = MTDPART_OFS_APPEND,
.size = (5*SZ_1M),
},
{
.name = "ramdisk",
.offset = MTDPART_OFS_APPEND,
.size = (3*SZ_1M),
},
{
.name = "rootfs",
.offset = MTDPART_OFS_APPEND,
.size = MTDPART_SIZ_FULL,
},
};
我们把256MB的分成了以下几个区,每个分区用于存放不同的内容:
分区名 |
起始地址 |
结束地址 |
大小 |
Uboot |
0x000000000000 |
0x000000100000 |
0x000000100000 1MB |
Recovery |
0x000000100000 |
0x000000600000 |
0x000000500000 5MB |
Kernel |
0x000000600000 |
0x000000b00000 |
0x000000500000 5MB |
Ramdisk |
0x000000b00000 |
0x000000e00000 |
0x000000300000 3MB |
Root |
0x000000e00000 |
0x000020000000 |
0x00001F200000 498MB |
8.加入开发板GEC210
(1)复制mach-smdkc110.c为mach-gec210.c
cp arch/arm/mach-s5pv210/mach-smdkc110.c arch/arm/mach-s5pv210/mach-gec210.c
(2)修改机器型号
$vim arch/arm/mach-s5pv210/mach-gec210.c
将arch/arm/mach-s5pv210/mach-gec210.c文件的末尾修改成如下(就是将SMDKV210改成GEC210):
#ifdef CONFIG_MACH_SMDKC110
MACHINE_START(SMDKC110, "SMDKC110")
#elif CONFIG_MACH_GEC210
MACHINE_START(GEC210, "GEC210")
#endif
/* Maintainer: Kukjin Kim */
.phys_io = S3C_PA_UART & 0xfff00000,
.io_pg_offst = (((u32)S3C_VA_UART) >> 18) & 0xfffc,
.boot_params = S5P_PA_SDRAM + 0x100,
.init_irq = s5pv210_init_irq,
.map_io = smdkc110_map_io,
.init_machine = smdkc110_machine_init,
.timer = &s5p_systimer,
MACHINE_END
(3)添加机器码,上面已经做了。
(4)在KBuild系统中增加GEC210开发板的配置菜单
vi arch/arm/mach-s5pv210/Kconfig
在menu "S5PV210 Machines"下面加入:
config MACH_GEC210
bool "GEC210"
select CPU_S5PV210
select ARCH_SPARSEMEM_ENABLE
select S3C_DEV_WDT
select HAVE_S3C2410_WATCHDOG
select S3C_DEV_I2C1
select S3C_DEV_I2C2
select HAVE_PWM
select S3C_DEV_HSMMC
select S3C_DEV_HSMMC1 if !S5PV210_SD_CH0_8BIT
select S3C_DEV_HSMMC3 if !S5PV210_SD_CH2_8BIT
select S5PV210_SETUP_SDHCI
select S5PV210_POWER_DOMAIN
help
Machine support for GEC210
(5)修改arch/arm/mach-s5pv210/Makefile文件
vi arch/arm/mach-s5pv210/Makefile
在“# machine support”下面加入:
obj-$(CONFIG_MACH_GEC210) += mach-gec210.o smdkc110-rtc.o
选上下面一项,加入GEC210开发板的支持:
System Type --->
Board selection (SMDKV210) --->
[*] GEC210
9.修改内存物理地址
vi arch/arm/mach-s5pv210/include/mach/memory.h
修改第16行为:
#if defined(CONFIG_MACH_SMDKV210) || defined(CONFIG_MACH_GEC210)
#define PHYS_OFFSET UL(0x30000000)
#else
#define PHYS_OFFSET UL(0x30000000)
#endif
10.修改内存映射
vi arch/arm/mach-s5pv210/include/mach/map.h
修改第156行,增加GEC210
#if defined(CONFIG_MACH_SMDKV210) || defined(CONFIG_MACH_GEC210)
#define S5PV210_PA_SDRAM (0x30000000)
#else
#define S5PV210_PA_SDRAM (0x30000000)
#endif
11.添加LCD支持(如果不添加会导致启动时内核OOPS错误)
vi drivers/video/samsung/Kconfig
修改第77行,增加MACH_GEC210
config FB_S3C_LTE480WV
bool "LTE480WV"
depends on (MACH_SMDKV210 || MACH_SMDKC110 || MACH_GEC210)
---help---
This enables support for Samsung LTE480WV 4.8\" WVGA LCD panel
然后 make menuconfig,确认driver中LTE480WV被选中。
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
Select LCD Type (LTE480WV) --->
12.修改网卡配置
GEC210原理图中DM9000网卡芯片的部分原理图。重要的信息如下:
1、CS(37脚)连接了Xm0CSn1
2、CMD(32脚)连接了Xm0ADDR2
3、INT(34脚)连接了XEINT7
(1)修改网卡物理地址,对应上面1
vi arch/arm/mach-s5pv210/include/mach/map.h
改为:
#define S5PV210_PA_DM9000 (0x88000000)
(2)修改命令线和外部中断配置,分别对应上面2和3
vi arch/arm/plat-s5p/devs.c
static struct resource s5p_dm9000_resources[] = {
[0] = {
.start = S5P_PA_DM9000,
.end = S5P_PA_DM9000,
.flags = IORESOURCE_MEM,
},
[1] = {
#if defined(CONFIG_DM9000_16BIT)
//.start = S5P_PA_DM9000 + 2,
//.end = S5P_PA_DM9000 + 2,
.start = S5P_PA_DM9000 + 8,
.end = S5P_PA_DM9000 + 8,
.flags = IORESOURCE_MEM,
#else
.start = S5P_PA_DM9000 + 1,
.end = S5P_PA_DM9000 + 1,
.flags = IORESOURCE_MEM,
#endif
},
[2] = {
//.start = IRQ_EINT9,
//.end = IRQ_EINT9,
.start = IRQ_EINT7,
.end = IRQ_EINT7,
.flags = IORESOURCE_IRQ | IORESOURCE_IRQ_HIGHLEVEL,
}
};
13.配置NFS服务 make menuconfig
(1)、配置网络部分,主要是使能CONFIG_IP_PNP以在2中能够看到Root file system on NFS选项
[*] Networking support
Networking options
[*] TCP/IP networking
[*] IP: kernel level autoconfiguration
[*] IP: DHCP support
[*] IP: BOOTP support
(2)、配置开启nfs服务
File systems --->
[*]Network File Systems --->
<*> NFS client support
[*] NFS client support for NFS version 3
[*] NFS client support for the NFSv3 ACL protocol extension
[*] NFS client support for NFS version 4 (EXPERIMENTAL)
[*] NFS client support for NFSv4.1 (DEVELOPER ONLY)
[*] Root file system on NFS
(3)在uboot下配置:
set bootcmd tftp 30008000 zImage\;bootm 30008000
set machid 270f
set bootargs root=/dev/nfs init=/linuxrc nfsroot=192.168.1.141:/workdir/rootfs ip=192.168.1.20:192.168.1.141:192.168.1.1:255.255.255.0::eth0:on console=ttySAC0,115200
save
14.LCD驱动移植
(1)修改LCD参数
# vi arch/arm/mach-s5pv210/mach-gec210.c
将#ifdef CONFIG_FB_S3C_LTE480WV(该宏在 676 行) 与 #endif 之间的代码改
成:
static struct s3cfb_lcd wvga_s70 = {
.width = 800,
.height = 480,
.p_width = 800,
.p_height = 480,
.bpp = 32,
.freq = 30,
.timing = {
.h_fp = 80,
.h_bp = 36,
.h_sw = 10,
.v_fp = 22,
.v_fpe = 1,
.v_bp = 15,
.v_bpe = 1,
.v_sw = 8,
},
.polarity = {
.rise_vclk = 0,
.inv_hsync = 1,
.inv_vsync = 1,
.inv_vden = 0,
},
};
static void lcd_cfg_gpio(struct platform_device *pdev)
{
int i;
for (i = 0; i < 8; i++) {
s3c_gpio_cfgpin(S5PV210_GPF0(i), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPF0(i), S3C_GPIO_PULL_NONE);
}
for (i = 0; i < 8; i++) {
s3c_gpio_cfgpin(S5PV210_GPF1(i), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPF1(i), S3C_GPIO_PULL_NONE);
}
for (i = 0; i < 8; i++) {
s3c_gpio_cfgpin(S5PV210_GPF2(i), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPF2(i), S3C_GPIO_PULL_NONE);
}
for (i = 0; i < 4; i++) {
s3c_gpio_cfgpin(S5PV210_GPF3(i), S3C_GPIO_SFN(2));
s3c_gpio_setpull(S5PV210_GPF3(i), S3C_GPIO_PULL_NONE);
}
/* mDNIe SEL: why we shall write 0x2 ? */
writel(0x2, S5P_MDNIE_SEL);
/* drive strength to max */
writel(0xaaaaaaaa, S5PV210_GPF0_BASE + 0xc);
writel(0xaaaaaaaa, S5PV210_GPF1_BASE + 0xc);
writel(0xaaaaaaaa, S5PV210_GPF2_BASE + 0xc);
writel(0x000000aa, S5PV210_GPF3_BASE + 0xc);
}
#define S5PV210_GPD_0_0_TOUT_0 (0x2)
#define S5PV210_GPD_0_1_TOUT_1 (0x2 << 4)
#define S5PV210_GPD_0_2_TOUT_2 (0x2 << 8)
#define S5PV210_GPD_0_3_TOUT_3 (0x2 << 12)
static int lcd_backlight_on(struct platform_device *pdev)
{
int err;
err = gpio_request(S5PV210_GPD0(3), "GPD0");
if (err) {
printk(KERN_ERR "failed to request GPD0 for "
"lcd backlight control\n");
return err;
}
gpio_direction_output(S5PV210_GPD0(3), 1);
s3c_gpio_cfgpin(S5PV210_GPD0(3), S5PV210_GPD_0_3_TOUT_3);
gpio_free(S5PV210_GPD0(3));
return 0;
}
static int lcd_backlight_off(struct platform_device *pdev, int onoff)
{
int err;
err = gpio_request(S5PV210_GPD0(3), "GPD0");
if (err) {
printk(KERN_ERR "failed to request GPD0 for "
"lcd backlight control\n");
return err;
}
gpio_direction_output(S5PV210_GPD0(3), 0);
gpio_free(S5PV210_GPD0(3));
return 0;
}
static int lcd_reset_lcd(struct platform_device *pdev)
{
int err;
err = gpio_request(S5PV210_GPH0(6), "GPH0");
if (err) {
printk(KERN_ERR "failed to request GPH0 for "
"lcd reset control\n");
return err;
}
gpio_direction_output(S5PV210_GPH0(6), 1);
mdelay(100);
gpio_set_value(S5PV210_GPH0(6), 0);
mdelay(10);
gpio_set_value(S5PV210_GPH0(6), 1);
mdelay(10);
gpio_free(S5PV210_GPH0(6));
return 0;
}
static struct s3c_platform_fb s5pv210_fb_data __initdata = {
.hw_ver = 0x62,
.nr_wins = 5,
.default_win = CONFIG_FB_S3C_DEFAULT_WINDOW,
.swap = FB_SWAP_WORD | FB_SWAP_HWORD,
.lcd = &wvga_s70,
.cfg_gpio = lcd_cfg_gpio,
.backlight_on = lcd_backlight_on,
.backlight_onoff = lcd_backlight_off,
.reset_lcd= lcd_reset_lcd,
};
在 static void __init smdkc110_machine_init(void)函数里修改
ifdef CONFIG_FB_S3C_LTE480WV(该宏定义在 1549 行) :
#ifdef CONFIG_FB_S3C_LTE480WV
s3cfb_set_platdata(<e480wv_fb_data);
改成:
s3cfb_set_platdata(&s5pv210_fb_data);
#endif
(2)确认开机logo是否打开
为了检验LCD是否已正常工作,我们同时打开开机logo显示功能。这样只要开机能看到屏幕左上角的启动画面小企鹅,即可证明LCD已正常工作。
为了打开启动画面功能,需要在make menuconfig中做如下配置:
Device Drivers --->
Graphics support --->
[*] Bootup logo --->
[*] Standard black and white Linux logo
[*] Standard 16-color Linux logo
[*] Standard 224-color Linux logo
15.在uboot那配置好后,检测ubantu的NFS和rootfs有没准备好,还有网络是否ping得通,都准备好启动就行了。
16.蜂鸣器修改(蜂鸣器一直响)
vim arch/arm/mach-s5pv210/mach-gec210.c
842 struct s3c_pwm_data pwm_data[] = {
843 {
844 #if 0
845 .gpio_no = S5PV210_GPD0(0),
846 .gpio_name = "GPD",
847 .gpio_set_value = S5PV210_GPD_0_0_TOUT_0,
848 }, {
849 #endif
17.让内核支持热插拔
General setup --->
[*] Configure standard kernel features (for small systems) --->
[*] Support for hot-pluggable devices
18.让内核支持USB设备
Device Drivers --->
[*] USB support --->
Support for Host-side USB-->
[*] USB verbose debug messages
[*] USB announce new devices
*** Miscellaneous USB options ***
[*] USB device filesystem (DEPRECATED)
[*] USB device class-devices (DEPRECATED) (NEW)
<*> USB Monitor
<*> EHCI HCD (USB 2.0) support
<*> USB Mass Storage support
SCSI device support --->
<*> SCSI device support
[*] Probe all LUNs on each SCSI device
[*] Block devices --->
<*> Low Performance USB Block driver
19.添加USB摄像头支持
Device Drivers -->
<*>Multimedia support --->
<*>Video For Linux
<*>Video capture adapters --->
<*>V4L USB devices --->
<*>USB Video Class
<*>UVC input events device support
20.TSC2007触摸屏驱动移植
Device Drivers -->
Input device spport-->
[*]Touchscreen driver
< >S3C touchscreen device //去掉S3C触摸屏驱动
<*>TSC2007 base touchscreens
23.修改arch/arm/mach-s5pv210/mach-gec210.c内容
$vi arch/arm/mach-s5pv210/mach-gec210.c
#include
#include
#include
#include
static int ts_get_pendown_state(void)
{
int val=0;
val=gpio_get_value(S5PV210_GPH1(6));
return val?0:1;
}
static struct tsc2007_platform_data tsc2007_info=
{
.model=2007,
.x_plate_ohms=180,
.get_pendown_state=ts_get_pendown_state,
};
修改i2c_board_info结构体,加入TS2007芯片的设备信息
static struct i2c_board_info i2c_devs2[] __initdata = {
{
#if defined(CONFIG_SMDKC110_REV03) || defined(CONFIG_SMDKV210_REV02)
/* The address is 0xCC used since SRAD = 0 */
I2C_BOARD_INFO("max8998", (0xCC >> 1)),
.platform_data = &max8998_pdata,
#else
/* The address is 0xCC used since SRAD = 0 */
I2C_BOARD_INFO("max8698", (0xCC >> 1)),
.platform_data = &max8698_pdata,
#endif
},
{
I2C_BOARD_INFO("ts2007",(0x48)),
.type="ts2007",
.platform_data=&tsc2007_info,
.irq=IRQ_EINT14,
},
};
修改drivers/input/touchscreen/tsc2007.c文件内容,在tsc2007_probe()函数中添加并修改以下内容。
添加部分
ts->client=client;
ts->irq = client->irq;
ts->input=input_dev;
client->flag & = ~ I2C_M_TEN;
修改部分
err = request_irq(ts->irq, tsc2007_irq, IRQF_TRIGGER_FALLING|IRQF_DISABLED,client->dev.driver->name, ts);
make //将arch/arm/boot/下的zImage拷贝到tftp的目录下(/tftpboot目录)