00.Uboot Linux rootfs
说明¶
该系列笔记是在学习了正点原子和韦东山的Linux驱动开发后,摘取的部分我觉得相对比较重要的点,方便自己后来查询
一块开发板最开始的工作应该就是移植UBOOT,编译相关Linux内核,然后制作根文件系统,以下步骤是将正点原子的教程文档做了一个简化,只取配置相关。下面部分步骤的前提是已经配置好了开发环境,包括但不限于NFS、TFTP等环境的搭建。使用的交叉编译器是arm-linux-gnueabihf-
Uboot¶
U-boot 官网:https://www.denx.de/wiki/U-Boot
源码下载页面:http://ftp.denx.de/pub/u-boot/
NXP 官方 uboot 源码 Git 地址:nxp-imx/uboot-imx: i.MX U-Boot (github.com)
先复制一份官方源码,一般都是使用芯片厂商提供的源码,我们使用的是NXP修改过后的UBOOT源码, 这里的版本是uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2然后解压。
添加开发板默认配置文件¶
在configs中找到参考的配置文件,复制一份
修改mx6ull_alientek_emmc_defconfig为
CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y
添加开发板对应的头文件¶
在include/configs下添加开发板头文件,我们这里直接复制一份参考
拷贝完成将前面修改为以下
添加开发板对应的板级文件夹¶
先到官方IMX6ILL的文件夹,并且复制一份参考文件夹
然后在该文件夹中,修改.c文件
还要修改该文件夹下的Makefile文件
将第六行的目标文件改为
修改imximage.cfg文件
将
改为
修改Kconfig文件
if TARGET_MX6ULL_ALIENTEK_EMMC
config SYS_BOARD
default "mx6ull_alientek_emmc"
config SYS_VENDOR
default "freescale"
config SYS_SOC
default "mx6" //这个实际没有用
config SYS_CONFIG_NAME
default "mx6ull_alientek_emmc"
endif
修改MAINTAINERS 文件
MX6ULL_ALIENTEK_EMMC BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_alientek_emmc/
F: include/configs/mx6ull_alientek_emmc.h
修改图形配置文件¶
在arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件,但是我没找到),
在207行添加以下内容
config TARGET_MX6ULL_ALIENTEK_EMMC
bool "Support mx6ull_alientek_emmc"
select MX6ULL
select DM
select DM_THERMAL
在最后一行的endif的前面添加,这里注意多加一个空行,用两个空行
使用新添加的板子编译配置uboot¶
新建一个mx6ull_alientek_emmc.sh文件
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
给可执行权限,然后运行脚本
检查该头文件是否被引用,如果有很多引用就对了
LCD驱动修改¶
打开文件 mx6ull_alientek_emmc.c,找到以下
struct display_info_t const displays[] = {{
.bus = MX6UL_LCDIF1_BASE_ADDR,
.addr = 0,
.pixfmt = 24,//像素格式 RGB565->16 888->24
.detect = NULL,
.enable = do_enable_parallel_lcd,
.mode = {
.name = "TFT43AB",//lcd名字
.xres = 480,//x轴像素
.yres = 272,
.pixclock = 108695,
.left_margin = 8,
.right_margin = 4,
.upper_margin = 2,
.lower_margin = 4,
.hsync_len = 41,
.vsync_len = 10,
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
如果名字修改了,在 mx6ull_alientek_emmc.h找到
panel=TFT43AB,全部修改为对应的
还要在uboot命令行中将panel值修改,改成对应的
底板网络驱动修改¶
修改PHY地址和驱动,在mx6ull_alientek_emmc.h中
mini新版用的芯片不用改地址,只需要将
改成
在mx6ull_alientek_emmc.c文件中删除74LV595相关的东西。
将以下
#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)
改成
删除static iomux_v3_cfg_t const iox_pads[] 数组,static void iox74lv_init(void)函数,void iox74lv_set(int index)函数
在board_init中,删除以下
添加复位引脚驱动
static iomux_v3_cfg_t const fec1_pads[] = {
···
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
}
static iomux_v3_cfg_t const fec2_pads[] = {
···
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
}
找到函数setup_iomux_fec修改为
static void setup_iomux_fec(int fec_id)
{
if (fec_id == 0)
{
imx_iomux_v3_setup_multiple_pads(fec1_pads,
ARRAY_SIZE(fec1_pads));
gpio_direction_output(ENET1_RESET, 1);
gpio_set_value(ENET1_RESET, 0);
mdelay(20);
gpio_set_value(ENET1_RESET, 1);
}
else
{
imx_iomux_v3_setup_multiple_pads(fec2_pads,
ARRAY_SIZE(fec2_pads));
gpio_direction_output(ENET2_RESET, 1);
gpio_set_value(ENET2_RESET, 0);
mdelay(20);
gpio_set_value(ENET2_RESET, 1);
}
mdelay(150); /* 复位结束后至少延时 150ms 才能正常使用*/
}
修改drivers/net/phy/phy.c中文件 ,找到genphy_update_link函数(这一步不需要)
int genphy_update_link(struct phy_device *phydev)
{
unsigned int mii_reg;
#ifdef CONFIG_PHY_REALTEK
static int lan8720_flag = 0;
int bmcr_reg = 0;
if (lan8720_flag == 0) {
bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {
udelay(100);
}
phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
lan8720_flag = 1;
}
#endif
/*
* Wait if the link is up, and autonegotiation is in progress
* (ie - we're capable and it's not done)
*/
mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
......
return 0;
}
修改完成后编译下载
设置网络环境变量,可以ping一下
setenv ipaddr 192.168.10.50 //开发板 IP 地址
setenv ethaddr b8:ae:1d:01:00:00 //开发板网卡 MAC 地址
setenv gatewayip 192.168.10.1 //开发板默认网关
setenv netmask 255.255.255.0 //开发板子网掩码
setenv serverip 192.168.10.100 //服务器地址,也就是 Ubuntu 地址
saveenv //保存环境变量
其他修改的地方¶
启动信息,将checkboard函数修改
if (is_mx6ull_9x9_evk())
puts("Board: MX6ULL 9x9 EVK\n");
else
puts("Board: MX6ULL ALIENTEK EMMC\n");
bootcmd 和 bootargs, CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值
bootargs保存着环境变量,bootcmd就是uboot倒计时后执行的命令
比如从EMMC启动,
setenv bootcmd 'mmc dev 1;fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'
setenv bootargs 'console= ttymxc0, 115200 root= /dev/mmcblk1p2 rootwait rw'
从网络启动
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz
80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/lqh/linux/nfs/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
ubuntu18 nfs有兼容性问题,板子一般用的2,但是电脑是3这里要改点配置
下面是复制的bootcmd的基础配置:
bootcmd=run findfdt;mmc dev ${mmcdev};mmc dev ${mmcdev}; if mmc rescan; then if run loadbootscript; then run bootscript; else if run loadimage; then run mmcboot; else run netboot; fi; fi; else run netboot; fi
Linux¶
添加开发板默认配置文件¶
复制一份linux源码,也是下载nxp修改过的,这里的版本是linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2,也在他的git仓库里面可以下载。
在顶层makefile中,第 252 和 253 行分别设置了 ARCH 和 CROSS_COMPILE 这两个变量的值,这样在编译的时候就不用输入很长的命令了。
复制一份配置文件
打开imx_alientek_emmc_defconfig
屏蔽掉CONFIG_ARCH_MULTI_V6=y
执行以下命令配置内核
添加开发板对应的设备树文件¶
dts是设备树源码文件,后面会编译成dtb
修改arch/arm/boot/dts/Makefile,找到dtb-$(CONFIG_SOC_IMX6ULL)
在下面加上imx6ull-alientek-emmc.dtb
创建一个编译脚本imx6ull_alientek_emmc.sh
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
#make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #这个如果不使用的话可以不编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j4
给可执行权限
chmod 777 imx6ull_alientek_emmc.sh //给予可执行权限
./imx6ull_alientek_emmc.sh //执行 shell 脚本编译内核
//编译可能会不通过,报错没有lzop
sudo apt-get install lzop
sudo apt-get install libssl-dev
然后就会生成zImage和dtb文件,将这两个文件拷贝到tftp目录下
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb /home/lqh/armlinux/tftpboot/ -f
cp arch/arm/boot/zImage ~/armlinux/tftpboot/ -f
测试一下
修改EMMC驱动¶
1、在imx6ull-alientek-emmc.dts改为8线
将&usdhc2中内容修改为
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
status = "okay";
};
2、关闭EMMC1.8V供电
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
no-1-8-v;
status = "okay";
};
网络驱动修改¶
找到pinctrl_spi4: spi4grp,删去两行我们在网络上要用的两个引脚,改为
pinctrl_spi4: spi4grp {
fsl,pins = <
MX6ULL_PAD_BOOT_MODE0__GPIO5_IO10 0x70a1
MX6ULL_PAD_BOOT_MODE1__GPIO5_IO11 0x70a1
>;
};
找到大约120几行的spi4,删除以下两项
找到&iomuxc_snvs,在imx6ul-evk部件中添加两项新的
pinctrl_enet1_reset: enet1resetgrp {
fsl,pins = <
/* used for enet1 reset */
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
>;
};
/*enet2 reset zuozhongkai*/
pinctrl_enet2_reset: enet2resetgrp {
fsl,pins = <
/* used for enet2 reset */
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
>;
};
找到pinctrl_enet1: enet1grp和pinctrl_enet2: enet2grp,在最后添加,但是这里默认不用改
找到名为“fec1”和“fec2”的这两个节点
修改pinctrl-0属性
pinctrl-0 = <&pinctrl_enet1
&pinctrl_enet1_reset>;
pinctrl-0 = <&pinctrl_enet2
&pinctrl_enet2_reset>;
修改 SR8201F 的PHY 地址
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1
&pinctrl_enet1_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2
&pinctrl_enet2_reset>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@2 {
compatible = "ethernet-phy-ieee802.3-c22";
smsc,disable-energy-detect;
reg = <2>;
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
smsc,disable-energy-detect;
reg = <1>;
};
};
};
修改drivers/net/ethernet/freescale/fec_main.c文件,找到fec_reset_phy
在最后添加msleep(200)
然后就可以编译运行测试了
然后就会生成zImage和dtb文件,将这两个文件拷贝到tftp目录下
cp arch/arm/boot/dts/imx6ull-alientek-emmc.dtb ~/linux/tftpboot/ -f
cp arch/arm/boot/zImage ~/linux/tftpboot/ -f
测试一下
Rootfs之BusyBox¶
Busybox使用¶
使用的是,busybox-1.29.0.tar.bz2,打开顶层Makefile,添加下列修改
164行 CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
190行 ARCH ?= arm
修改中文字符支持,打开busybox-1.29.0/libbb/printable_string.c找到 printable_string
大概31行,注释以下
大概45行,注释原来条件,并添加新条件
接着打开文件 busybox-1.29.0/libbb/unicode.c,找到unicode_conv_to_printable2
大概1023行,注释并修改
大概1033行,注释原来条件,并添加新条件
图形化配置
配置方式如下
Location:
-> Settings
-> Build static binary (no shared libs) 这个不要选中
Location:
-> Settings
-> vi-style line editing commands 这个选中
Location:
-> Linux Module Utilities
-> Simplified modutils 这个不选
Location:
-> Linux System Utilities
-> mdev (16 kb) //确保下面的全部选中,默认都是选中的
Location:
-> Settings
-> Support Unicode //选中
-> Check $LC_ALL, $LC_CTYPE and $LANG environment variables //选中
编译busybox
根文件添加库文件
mkdir lib
//进入libc/lib目录
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp *so* *.a /home/lqh/linux/nfs/rootfs/lib/ -d
在rootfs/lib目录下
cd ~/linux/nfs/rootfs/lib
rm ld-linux-armhf.so.3
然后进入libc/lib目录
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp ld-linux-armhf.so.3 /home/lqh/linux/nfs/rootfs/lib/
//进入lib
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
cp *so* *.a /home/lqh/linux/nfs/rootfs/lib/ -d
//进入usr/lib
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a /home/lqh/linux/nfs/rootfs/usr/lib/ -d
cd rootfs //进入根文件系统目录
du ./lib ./usr/lib/ -sh //查看 lib 和 usr/lib 这两个目录的大小
一个57一个67
在根文件系统中创建其他文件夹,如 dev、proc、mnt、sys、tmp 和 root 等
初步测试
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/lqh/armlinux/nfs/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
saveenv
完善根文件系统¶
创建/etc/init.d/rcS 文件
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
给可执行权限
在 rootfs 中创建/etc/fstab 文件
#<file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
也创建一个/etc/inittab
#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
测试运行
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.10.100:/home/lqh/linux/nfs/rootfs,proto=tcp rw ip=192.168.10.50:192.168.10.100:192.168.10.1:255.255.255.0::eth0:off'
saveenv
Rootfs之Buildroot¶
基础配置¶
下载源码
下载路径:https://buildroot.org/download.html
将 buildroot 源码 buildroot-2023.02.8.tar.gz 拷贝到 ubuntu 中。拷贝完成以后对其进行解压,命令如下:
然后进入图形配置界面
每个地方的配置选项如下
首先配置 Target options 选项,需要配置的项目和其对应的内容如下(“=”号后面是配置项 要选择的内容!):
Target options
-> Target Architecture = ARM (little endian)
-> Target Binary Format = ELF
-> Target Architecture Variant = cortex-A7
-> Target ABI = EABIhf
-> Floating point strategy = NEON/VFPv4
-> ARM instruction set = ARM
Toolchain此配置项用于配置交叉编译工具链,也就是交叉编译器,这里设置为我们自己所使用的交叉编译器即可。buildroot 其实是可以自动下载交叉编译器的,但是都是从国外服务器下载的,鉴于国内的网络环境,强烈推荐大家设置成自己所使用的交叉编译器。需要配置的项目和其对应的内容如下:
Toolchain
-> Toolchain type = External toolchain
-> Toolchain = Custom toolchain //用户自己的交叉编译器
-> Toolchain origin = Pre-installed toolchain //预装的编译器
-> Toolchain path =/usr/local/arm/gcc-arm-linux-gnueabihf
-> Toolchain prefix = $(ARCH)-linux-gnueabihf //前缀
-> External toolchain gcc version = 4.9.x
-> External toolchain kernel headers series = 4.0.x
-> External toolchain C library = glibc
-> [] Toolchain has SSP support? (NEW) //选中
-> [] Toolchain has RPC support? (NEW) //选中
-> [] Toolchain has C++ support? //选中
-> [] Enable MMU support (NEW) //选中,发现最新的没有这个选项
Toolchain 下几个比较重要的选项需要说明一下,如下所示:
Toolchain:设置为 Custom toolchain,表示使用用户自己的交叉编译器。
Toolchain origin:设置为 Pre-installed toolchain,表示使用预装的交叉编译器。
Toolchain path:设置自己安装的交叉编译器绝对路径!buildroot 要用到。
Toolchain prefix:设置交叉编译器前缀,要根据自己实际所使用的交叉编译器来设置,比如我们使用的是 arm-linux-gnueabihf-gcc,因此前缀就是$(ARCH)-linux-gnueabihf,其中 ARCH我们前面已经设置为了 arm。
System configuration此选项用于设置一些系统配置,比如开发板名字、欢迎语、用户名、密码等。需要配置的项目和其对应的内容如下:
System configuration
-> System hostname = fire_imx6ull //平台名字,自行设置
-> System banner = Welcome to fire imx6ull //欢迎语
-> Init system = BusyBox //使用 busybox
-> /dev management = Dynamic using devtmpfs + mdev //使用 mdev
-> [*] Enable root login with password (NEW) //使能登录密码
-> Root password = 123 //登录密码为 123
Filesystem images此选项配置我们最终制作的根文件系统为什么格式的,配置如下:
-> Filesystem images
-> [] ext2/3/4 root filesystem //如果是 EMMC 或 SD 卡的话就用 ext3/ext4
-> ext2/3/4 variant = ext4 //选择 ext4 格式
-> [] ubi image containing an ubifs root filesystem //如果使用 NAND 的话就用 ubifs
禁止编译 Linux 内核和 uboot
配置完成以后就可以编译 buildroot 了,编译完成以后 buildroot 就会生成编译出来的根文件系统压缩包,我们可以直接使用。输入如下命令开始编译:
等待编译完成,编译完成以后就会在 buildroot-2023.02.8/output/images 下生成根文件系统。buildroot 制作出来的根文件系统已经准备好了,接下来就是对其进行测试。先将制作的根文件系统buildroot-2023.02.8/output/images/rootfs.tar 解压到nfs目录下,并改名为:rootfs
设置好后重启开发板,就可以输入root用户和密码进入了
会发现没有/lib/modules目录,这个需要自己创建
会发现没有显示当前路径,执行以下代码。
buildroot下的busybox配置¶
使能depmod
然后重新编译解压