首页 > 系统相关 >TQ2440(S3C2440)移植Linux-4.0.1内核全过程

TQ2440(S3C2440)移植Linux-4.0.1内核全过程

时间:2023-02-01 22:37:16浏览次数:68  
标签:led struct TQ2440 S3C2410 mini2440 static Linux 4.0 features


TQ2440(S3C2440)移植Linux-4.0.1内核全过程


文件系统yaffs2下载地址:https://yaffs.net/get-yaffs​​
linux内核下载地址:https://mirror.bjtu.edu.cn/kernel/linux/kernel/


构建根文件系统在这里:​​嵌入式Linux构建yaffs根文件系统​​


(一)初步移植启动linux内核

解压linux内核源码:

tar xvf linux-4.0.1.tar.xz

获取yaffs2文件系统源码并向linux内核打包使内核支持yaffs2文件系统:

git clone git://www.aleph1.co.uk/yaffs2
cd yaffs2
./patch-ker.sh c m ../linux-4.0.1

进入linux内核源码目录并修改顶层Makefile:

cd ../linux-4.0.1
gedit Makefile

找到:

ARCH        ?= $(SUBARCH)
CROSS_COMPILE ?= $(CONFIG_CROSS_COMPILE:"%"=%)

改为:

ARCH        ?= arm
CROSS_COMPILE ?= arm-linux-

加载mini2440的配置项:

make mini2440_defconfig

打开图形化配置内核:

make menuconfig

相关配置如下:

Device Drivers  --->
Input device support --->
[*] Touchscreens --->
<*> Samsung S3C2410/generic touchscreen input driver # 开启触摸屏支持
[*] Watchdog Timer Support --->
< > S3C2410 Watchdog # 关闭看门狗,要不然系统会一直重启
Graphics support --->
[*] Bootup logo --->
[*] Standard 16-color Linux logo # 选中该项,取消其他项
<*> Memory Technology Device (MTD) support --->
< > FTL (Flash Translation Layer) support # 取消选中,要不然会出现警告:ftl_cs: FTL header not found
< > NFTL (NAND Flash Translation Layer) support # 取消选中,要不然会出现警告:ftl_cs:
< > INFTL (Inverse NAND Flash Translation Layer) support # 取消选中,要不然会出现警告:ftl_cs:
<*> NAND Device Support --->
<*> NAND Flash support for Samsung S3C SoCs
[*] Samsung S3C NAND Hardware ECC # 开启NAND的硬件ECC校验
File systems --->
[*] Miscellaneous filesystems --->
<*> yaffs2 file system support # 开启yaffs2文件系统支持

注:开启NAND的硬件ECC校验是选做,如果不开启那么默认使用软件ECC,也可以手动修改文件drivers/mtd/nand/s3c2410.c中的​s3c2410_nand_init_chip​函数,将图片框出的一行的宏改为​NAND_ECC_NONE​,即不适用ECC功能:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_制作根文件系统

修改mini2440的机器码:

gedit arch/arm/tools/mach-types

找到:

mini2440    MACH_MINI2440   MINI2440    1999

改为:

mini2440    MACH_MINI2440   MINI2440    168

168是我的u-boot里的,这个机器码需要跟u-boot中的机器码相对应,要不然u-boot无法引导启动内核,如果你不知道uboot中的机器码是多少,在uboot命令行中输入命令bdinfo查看:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_移植linux-4.0_02

进行初次编译:

make -j4

说明:参数4表示4个核心,是CPU的核数,目的为了加快编译速度。

出错:fs/yaffs2/yaffs_vfs.c:321: error: 'struct file' has no member named 'f_dentry'​​
看错误信息是说结构体file没有名为f_dentry的成员,我们查看一下fs/yaffs2/yaffs_vfs.c这个文件,定位到第321行是这么一句​obj = yaffs_dentry_to_obj(Y_GET_DENTRY(f));​,也就是说出错的是这个宏Y_GET_DENTRY,我们在定位到这个宏的定义位置:*

#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 4, 0))
#define PAGE_CACHE_SIZE PAGE_SIZE
#define PAGE_CACHE_SHIFT PAGE_SHIFT
#define Y_GET_DENTRY(f) ((f)->f_path.dentry)
#define YAFFS_NEW_XATTR 1
#define YAFFS_NEW_GET_LINK 1
#else
#define Y_GET_DENTRY(f) ((f)->f_dentry)
#define YAFFS_NEW_XATTR 0
#define YAFFS_NEW_GET_LINK 0
#endif

这里根据linux的版本宏定义了Y_GET_DENTRY,如果linux版本低于4.4那么使用f->f_dentry,否则使用f->f_path.dentry,执行的出错的原因是找不到f_dentry,现在就要去看一下linux-4.0.1内核中的struct fle结构体的成员中有关键字dentry的是什么,因为这是文件系统相关的,所以我们到​include/linux/fs.h​中去找:

struct file {
union {
struct llist_node fu_llist;
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;

/*
* Protects f_ep_links, f_flags.
* Must not be taken from IRQ context.
*/
spinlock_t f_lock;
atomic_long_t f_count;
unsigned int f_flags;
fmode_t f_mode;
struct mutex f_pos_lock;
loff_t f_pos;
struct fown_struct f_owner;
const struct cred *f_cred;
struct file_ra_state f_ra;

u64 f_version;
#ifdef CONFIG_SECURITY
void *f_security;
#endif
/* needed for tty driver, and maybe others */
void *private_data;

#ifdef CONFIG_EPOLL
/* Used by fs/eventpoll.c to link all the hooks to this file */
struct list_head f_ep_links;
struct list_head f_tfile_llink;
#endif /* #ifdef CONFIG_EPOLL */
struct address_space *f_mapping;
} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */

struct file_handle {
__u32 handle_bytes;
int handle_type;
/* file identifier */
unsigned char f_handle[0];
};

没有发现dentry的字样,但是看到了struct path f_path;,再去这个结构体中看看:

struct path {
struct vfsmount *mnt;
struct dentry *dentry;
};

果然找到了dentry成员!那么就将文件fs/yaffs2/yaffs_vfs.c中的宏:

#define Y_GET_DENTRY(f) ((f)->f_dentry)

改为:

#define Y_GET_DENTRY(f) ((f)->f_path.dentry)

重新make一下,编译顺利通过!

接下来编译出用于u-boot引导的内核镜像:

make uImage

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_linux_03


成功!

下面开始修改内核代码:

gedit arch/arm/mach-s3c24xx/mach-mini2440.c

修改NAND默认分区表为:

/* NAND Flash on MINI2440 board */

static struct mtd_partition mini2440_default_nand_part[] __initdata = {
[0] = {
.name = "u-boot-spl",
.size = SZ_128K,
.offset = 0,
},
[1] = {
.name = "u-boot",
.offset = SZ_128K,
.size = SZ_1M - SZ_128K,
},
[2] = {
.name = "u-boot-env",
.offset = SZ_1M,
.size = SZ_256K,
},
[3] = {
.name = "kernel",
.offset = SZ_1M + SZ_256K,
.size = SZ_4M,
},
[4] = {
.name = "yaffs2",
.offset = SZ_4M + SZ_1M + SZ_256K,
.size = MTDPART_SIZ_FULL,
},
};

下面运行内核进行测试一下,这里我提前做好了yaffs2文件系统(制作方法见本博客首部链接),启动内核后开发板使用nfs的方式挂载文件系统。

首先设置uboot启动参数为:

setenv bootargs noinitrd console=ttySAC0,115200 rootfstype=yaffs2 init=/linuxrc root=/dev/nfs rw nfsroot=192.168.166.254:/opt/embeded/yaffs2 ip=192.168.166.253:192.168.166.254:192.168.166.1:255.255.255.0::eth0:off

保存环境变量并重启:

saveenv
reset

参数说明:

  • ​nfsroot=192.168.166.254:/opt/embeded/yaffs2​​:这是ubuntu的IP地址以及制作的yaffs2文件系统的目录
  • ​ip=192.168.166.253:192.168.166.254:192.168.166.1:255.255.255.0::eth0:off​​:ip=[开发板IP地址]:[ubuntu的IP地址]:[网关]:[掩码]:eth0:off

使用tftp下载系统内核镜像并启动:

tftp 0x32000000 uImage; bootm 0x32000000

成功启动:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_04

但是通过nfs挂载不上根文件系统,出现了问题:

  • ​nfs: server 192.168.166.254 not responding, still trying​
  • ​mount: server 192.168.166.254 not responding, timed out​

原因:BWSCON和BANKCON4寄存器关于网卡的配置项有问题。

修改代码:

gedit arch/arm/mach-s3c24xx/mach-mini2440.c

添加头文件:

#include "regs-mem.h"
#include <linux/platform_data/touchscreen-s3c2410.h>

定位到mini2440_init函数,在该函数尾部添加以下代码:

/* 清除bank4的总线宽度设置 */
*((volatile unsigned int *)S3C2410_BWSCON) &= ~(3 << 16);

/* 设置BANK4的总线宽度为16bits、设置开启BANK4等待状态、设置SRAM使用BANK4的UB/LB */
*((volatile unsigned int *)S3C2410_BWSCON) |= (1 << 16) | (1 << 18) | (1 << 19);

/* 设置BANK4控制寄存器 */
*((volatile unsigned int *)S3C2410_BANKCON4) = 0X1F7C;

重新编译后使用tftp下载内核并运行:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_linux_05


成功挂载!

(二)驱动修改

TQ2440板载一个AT24C02,接在I2C0上。

gedit arch/arm/mach-s3c24xx/mach-mini2440.c

找到I2C设备的相关配置,替换为:

/*
* I2C devices
*/
static struct at24_platform_data at24c02 = {
.byte_len = SZ_2K / 8, /* 2Kbits / 8 = 256bytes */
.page_size = 8, /* at24c02 page size = 8 */
.flags = 0,
};

static struct i2c_board_info mini2440_i2c_devs[] __initdata = {
{
/*
* at24c02的地址由8位组成,高四位固定为1010,低四位为A2A1A0R/W,
* A2A1A0三个引脚一般拉低与高四位组成7bit的地址码,R/W位为读写控制位,
* 为0时表示芯片写操作,组合起来的地址就是0xA0(写)和0xA1(读),
* 但是在Linux系统中I2C设备地址的最高位为1,而剩余7位地址就是去掉R/W位后的剩余7位,
* 所以就是0x50。
*/
I2C_BOARD_INFO("24c02", 0x50),
.platform_data = &at24c02,
},
};

TQ2440板载4个LED灯,位于GPB5-GPB8,找到LED设备的相关配置,替换为:

/* LEDS */

static struct s3c24xx_led_platdata mini2440_led1_pdata = {
.name = "led1",
.gpio = S3C2410_GPB(5),
.flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
.def_trigger = "heartbeat",
};

static struct s3c24xx_led_platdata mini2440_led2_pdata = {
.name = "led2",
.gpio = S3C2410_GPB(6),
.flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
.def_trigger = "nand-disk",
};

static struct s3c24xx_led_platdata mini2440_led3_pdata = {
.name = "led3",
.gpio = S3C2410_GPB(7),
.flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
.def_trigger = "mmc0",
};

static struct s3c24xx_led_platdata mini2440_led4_pdata = {
.name = "led4",
.gpio = S3C2410_GPB(8),
.flags = S3C24XX_LEDF_ACTLOW | S3C24XX_LEDF_TRISTATE,
.def_trigger = "",
};

static struct platform_device mini2440_led1 = {
.name = "s3c24xx_led",
.id = 1,
.dev = {
.platform_data = &mini2440_led1_pdata,
},
};

static struct platform_device mini2440_led2 = {
.name = "s3c24xx_led",
.id = 2,
.dev = {
.platform_data = &mini2440_led2_pdata,
},
};

static struct platform_device mini2440_led3 = {
.name = "s3c24xx_led",
.id = 3,
.dev = {
.platform_data = &mini2440_led3_pdata,
},
};

static struct platform_device mini2440_led4 = {
.name = "s3c24xx_led",
.id = 4,
.dev = {
.platform_data = &mini2440_led4_pdata,
},
};

并删除这两个结构,这两个结构数据未使用,编译的时候会出现警告,当然不删除也不影响:

static struct platform_device mini2440_led_backlight = {
.name = "s3c24xx_led",
.id = 5,
.dev = {
.platform_data = &mini2440_led_backlight_pdata,
},
};

static struct s3c24xx_led_platdata mini2440_led_backlight_pdata = {
.name = "backlight",
.gpio = S3C2410_GPG(4),
.def_trigger = "backlight",
};

修改LCD设备驱动(我的屏幕是W43),找到_LCD_DECLARE这个宏并删除,修改​mini2440_lcd_cfg​这个结构为:

/* LCD timing and setup */

static struct s3c2410fb_display mini2440_lcd_cfg[] __initdata = {

[0] = {
.lcdcon5 = S3C2410_LCDCON5_FRM565 |
S3C2410_LCDCON5_INVVLINE |
S3C2410_LCDCON5_INVVFRAME |
S3C2410_LCDCON5_PWREN |
S3C2410_LCDCON5_HWSWP,

.type = S3C2410_LCDCON1_TFT,
.width = 480,
.height = 272,
.pixclock = 40000, /* HCLK 60 MHz, divisor 10 */
.xres = 480,
.yres = 272,
.bpp = 16,
.left_margin = 19,
.right_margin = 10,
.hsync_len = 30,
.upper_margin = 4,
.lower_margin = 2,
.vsync_len = 8,
},
};

TQ2440板载一个蜂鸣器,接在了GPB0上,这里我们将beep以led平台设备驱动的方式进行注册,添加代码:

/* BEEP */

static struct s3c24xx_led_platdata mini2440_beep_pdata = {
.name = "beep",
.gpio = S3C2410_GPB(0),
.flags = S3C24XX_LEDF_TRISTATE,
};

static struct platform_device mini2440_beep = {
.name = "s3c24xx_led",
.id = 5,
.dev = {
.platform_data = &mini2440_beep_pdata,
},
};

TQ2440板载4个按键,位于GPF0、1、2、4,将按键相关配置改为:

/* KEYS */

static struct gpio_keys_button mini2440_buttons[] = {
{
.gpio = S3C2410_GPF(1),
.code = KEY_UP,
.desc = "Button Up",
.active_low = 0,
},
{
.gpio = S3C2410_GPF(4),
.code = KEY_DOWN,
.desc = "Button Down",
.active_low = 0,
},
{
.gpio = S3C2410_GPF(2),
.code = KEY_LEFT,
.desc = "Button Left",
.active_low = 0,
},
{
.gpio = S3C2410_GPF(0),
.code = KEY_RIGHT,
.desc = "Button Right",
.active_low = 0,
},
};

修改触摸屏驱动,添加这个结构:

/* Tcouch Screen  */

static struct s3c2410_ts_mach_info mini2440_ts_info __initdata = {
.delay = 10000,
.presc = 49,
.oversampling_shift = 2,
};

删除:

/*
* mini2440_features string
*
* t = Touchscreen present
* b = backlight control
* c = camera [TODO]
* 0-9 LCD configuration
*
*/
static char mini2440_features_str[12] __initdata = "0tb";

static int __init mini2440_features_setup(char *str)
{
if (str)
strlcpy(mini2440_features_str, str, sizeof(mini2440_features_str));
return 1;
}

__setup("mini2440=", mini2440_features_setup);

#define FEATURE_SCREEN (1 << 0)
#define FEATURE_BACKLIGHT (1 << 1)
#define FEATURE_TOUCH (1 << 2)
#define FEATURE_CAMERA (1 << 3)

struct mini2440_features_t {
int count;
int done;
int lcd_index;
struct platform_device *optional[8];
};

static void __init mini2440_parse_features(
struct mini2440_features_t * features,
const char * features_str )
{
const char * fp = features_str;

features->count = 0;
features->done = 0;
features->lcd_index = -1;

while (*fp) {
char f = *fp++;

switch (f) {
case '0'...'9': /* tft screen */
if (features->done & FEATURE_SCREEN) {
printk(KERN_INFO "MINI2440: '%c' ignored, "
"screen type already set\n", f);
} else {
int li = f - '0';
if (li >= ARRAY_SIZE(mini2440_lcd_cfg))
printk(KERN_INFO "MINI2440: "
"'%c' out of range LCD mode\n", f);
else {
features->optional[features->count++] =
&s3c_device_lcd;
features->lcd_index = li;
}
}
features->done |= FEATURE_SCREEN;
break;
case 'b':
if (features->done & FEATURE_BACKLIGHT)
printk(KERN_INFO "MINI2440: '%c' ignored, "
"backlight already set\n", f);
else {
features->optional[features->count++] =
&mini2440_led_backlight;
}
features->done |= FEATURE_BACKLIGHT;
break;
case 't':
printk(KERN_INFO "MINI2440: '%c' ignored, "
"touchscreen not compiled in\n", f);
break;
case 'c':
if (features->done & FEATURE_CAMERA)
printk(KERN_INFO "MINI2440: '%c' ignored, "
"camera already registered\n", f);
else
features->optional[features->count++] =
&s3c_device_camif;
features->done |= FEATURE_CAMERA;
break;
}
}
}

找到mini2440_init函数,删除以下部分:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_移植linux-4.0_06


在for循环下添加设置触摸屏和显示的平台数据:

s3c24xx_fb_set_platdata(&mini2440_fb_info);
s3c24xx_ts_set_platdata(&mini2440_ts_info);

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_编译busybox_07


找到mini2440_devices这个结构,添加:

&s3c_device_lcd,
&s3c_device_adc,
&s3c_device_ts,
&mini2440_beep,

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_08

修改内核自带的触摸屏驱动:

gedit drivers/input/touchscreen/s3c2410_ts.c

找到touch_timer_fire函数,定位到上报触摸事件这一句:

input_report_key(ts.input, BTN_TOUCH, 1);

下方添加按压事件上报:

input_report_abs(ts.input, ABS_PRESSURE, 1);

找到:

input_report_key(ts.input, BTN_TOUCH, 0);

下放添加:

input_report_abs(ts.input, ABS_PRESSURE, 0);

如下图所示:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_09


找到s3c2410ts_probe函数,将:

ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);

改为:

ts.input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) | BIT(EV_SYN);

找到这一句:

input_set_abs_params(ts.input, ABS_Y, 0, 0x3FF, 0, 0);

下方添加:

input_set_abs_params(ts.input, ABS_PRESSURE, 0, 1, 0, 0);

如下图所示:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_移植linux-4.0_10

重新make编译一下然后下载到开发板运行,LCD屏幕会显示一个linux的企鹅logo,LED1会闪烁!

(三)驱动测试

(1)测试LED

LED是以平台总线设备驱动的方式进行注册的,LED的相关代码已经标明了ID是1-4,BEEP是以led平台设备驱动进行方式注册的,ID为5,linux的led子系统会在/sys/class目录下生成leds文件夹,进入该目录就可以看到我们以led平台总线驱动方式注册的所有设备:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_11


可以看到有led1-4和beep,我们使用led4进行测试,进入led4文件夹:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_linux_12


brightness这个文件就是led4的设备文件,操作这个文件就可以实现led4的亮和灭:

  • 点亮:echo 1 > brightness
  • 熄灭:echo 0 > brightness

(2)测试BEEP

同led,进入beep文件夹:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_linux_13


操作方式跟led一样:

  • 打开蜂鸣器:echo 1 > brightness
  • 熄灭蜂鸣器:echo 0 > brightness

(3)测试LCD显示

这里我使用Img2Lcd这个软件将衣服图片转成了bin文件,然后将该文件拷贝到了开发板文件系统上的/app/目录下:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_编译busybox_14


lcd帧缓冲的设备文件是/dev/fb0,在开发板上使用cat命令将图片bin输出到显示设备上:

cat /app/logo.bin > /dev/fb0

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_15

(4)测试触摸屏和按键

使用以下命令触摸屏幕或按下按键查看有无乱码输出:

cat /dev/event0
cat /dev/event1

注意:如果在内核代码中没有修改名字的话,输入设备文件的默认名就是/dev/eventX,X是数字,在本次移植中有两个输入设备:①触摸屏,②按键,所以在/dev目录下有event0和event1这两个设备文件。


(四)USB驱动:U盘、USB鼠标键盘

make meunconfig

关于USB键盘和U盘的配置如下

Device Drivers  ---> 
SCSI device support --->
<*> SCSI device support
[*] legacy /proc/scsi/ support
<*> SCSI disk support
[*] USB support --->
<*> Support for Host-side USB
[*] Dynamic USB minor allocation
<*> USB Monitor
<*> OHCI HCD (USB 1.1) support
<*> OHCI support for Samsung S3C24xx/S3C64xx SoC series
<*> USB Mass Storage support
HID support --->
USB HID support --->
<*> USB HID transport layer
[*] PID device support
[*] /dev/hiddev raw HID device support

除此之外还要将字符级编译进内核,你可以使用拿个就编译进哪个,我为了方便将基本的字符级全都编译进去了,缺点是内核大小大概增加了500KB的大小:

Device Drivers  ---> 
File systems --->
-*- Native language support --->

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_移植linux-4.0_16

启动内核,插入U盘后成功识别,可以看到设备节点是sda4,下面挂载U盘:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_17


我的U盘文件系统格式是FAT32,挂载U盘命令:

mount -t vfat -o iocharset=cp936 /dev/sda4 /mnt/udisk

命令解释:

  • -t:文件系统类型,vfat代表挂载的U盘格式为FAT/FAT32
  • -o:字符集
  • /dev/sda4:U盘的设备文件
  • /mnt/udisk:挂载点

注:一般情况下当有USB或者SD设备插入时,linux内核会首先扫描/etc/mdev.conf的配置文件,从其中获取挂载命令和挂载点从而实现自动挂载。

插入USB鼠标:

TQ2440(S3C2440)移植Linux-4.0.1内核全过程_嵌入式_18

测试usb鼠标:

cat /dev/mouseN

注意:/dev目录下可能有多个mouseN设备文件,N为数字,键入命令后移动鼠标查看有无乱码输出,若没有则不是鼠标的设备文件,挨个试试。


完!


标签:led,struct,TQ2440,S3C2410,mini2440,static,Linux,4.0,features
From: https://blog.51cto.com/u_15950551/6031932

相关文章