在上一篇中记录了编译u-boot的过程。现在来构建支持SPI-NOR-Flash的linux内核。
我手边的V3s核心板使用的接口比较少,包括以太网口、三个串口和USB口,LCD,MIPI,摄像头、GPIO等接口都没有用到。因此编译内核时主要考虑以下三个要点。
- 支持16MB以上容量的SPI-NOR-Flash,需要修改设备树
- 使能uart0/1/2三个串口,默认使能uart0,在构建内核时要把uart1和uart2都配置好
- 配置好USB接口
获取linux内核源码
参考上一篇所作的分区,编译好的内核尺寸要小于4MB才好。而最新版本的linux内核(例如5.2.y)体积较大,编译好以后会超过4MB,因此我使用了参考资料较多的4.13.y内核。后面可以看到使用4.13.y编译后得到的zImag的大小是3.3MB左右。
使用
cd .../v3s/
git clone -b zero-4.13.16 --depth 1 https://github.com/Lichee-Pi/linux.git
可以把4.13.16版本的linux源码拉取到本地,拉取完毕后,会在当前目录下生成一个linux文件夹。
在编译linux内核之前,注意安装好所有的依赖项,如下。
sudo apt install git wget make gcc flex bison libssl-dev bc kmod
配置内核
装载licheepi的defconfig
cd linux
make licheepi_zero_defconfig
menuconfig
使用 make ARCH=arm menuconfig 配置内核。
General Setup
在第一级菜单中,选中“General Setup”,然后回车进入该级菜单,设置好
- 交叉编译器:arm-linux-gnueabihf-,注意最后一个减号“-”不能少
- 给核心板取个名字:Default hostname,我设置成了 ctm-gateway,可以根据自己的喜好起个名字
- 选中“Support for paging of anonymous memory (swap)
- 选中”System V IPC“,可以根据将来应用场景的需要选择是否需要这一项。我的项目中需要用到,因此就选中了
- 选中”POSIX Message Queues“,理由同上
General Setup中的其它选项没有做变更。设置好参数后的Genera Setup结果如下图。
Networking support
由于我的核心板没用到无线网络部分,因此我把Networking support里面的Wireless支持里面的所有无线芯片的支持都删掉了。
如果需要一些网络芯片的驱动,可以根据自己的需要选中。
Device Drivers
首先选中 <*>Memory Technology Device (MTD) support,然后进入到这一级菜单中,选中 <*> Command line partition table parsing和 <*> SPI-NOR device support --->,在SPI-NOR device support中选中 [*] Use small 4096 B erase sectors,其它两项都清除掉。
File systems ---> Miscellaneous filesystems
在这个菜单中确保选中 <*> Journalling Flash File System v2 (JFFS2) support。
修改设备树
增加spi节点
修改 .../v3s/linux/arch/arm/boot/dts/sun8i-v3s-licheepi-zero.dts。在 &uart0 {...}节点前增加一个 &spi节点,内容如下。
&i2c0 {
......
......
};
&ohci0 {
......
......
};
&spi0 {
status ="okay";
mx25l25645g:mx25l25645g@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
spi-max-frequency = <50000000>;
#address-cells = <1>;
#size-cells = <1>;
};
};
&uart0 {
pinctrl-0 = <&uart0_pins_a>;
pinctrl-names = "default";
status = "okay";
};
设备节点似乎不应该有顺序的问题,我把spi节点加在uart0节点之前纯粹是习惯。
在m25p80.c中增加mx25l25645g的注册项
打开 .../v3s/linux/drivers/mtd/devices/m25p80.c,找到 static const struct spi_device_id m25p_ids[] = {...} 的定义(大约在332行),在代码中找到 mx25l25635e,然后在它的前面加上
{"mx25l25645g"},
修改好的结果如下图所示。
static const struct spi_device_id m25p_ids[] = {
/*
* Allow non-DT platform devices to bind to the "spi-nor" modalias, and
* hack around the fact that the SPI core does not provide uevent
* matching for .of_match_table
*/
{"spi-nor"},
/*
* Entries not used in DTs that should be safe to drop after replacing
* them with "spi-nor" in platform data.
*/
{"s25sl064a"}, {"w25x16"}, {"m25p10"}, {"m25px64"},
/*
* Entries that were used in DTs without "jedec,spi-nor" fallback and
* should be kept for backward compatibility.
*/
{"at25df321a"}, {"at25df641"}, {"at26df081a"},
{"mx25l4005a"}, {"mx25l1606e"}, {"mx25l6405d"}, {"mx25l12805d"},
{"mx25l25645g"},{"mx25l25635e"},{"mx66l51235l"},
{"n25q064"}, {"n25q128a11"}, {"n25q128a13"}, {"n25q512a"},
{"s25fl256s1"}, {"s25fl512s"}, {"s25sl12801"}, {"s25fl008k"},
{"s25fl064k"},
{"sst25vf040b"},{"sst25vf016b"},{"sst25vf032b"},{"sst25wf040"},
{"m25p40"}, {"m25p80"}, {"m25p16"}, {"m25p32"},
{"m25p64"}, {"m25p128"},
{"w25x80"}, {"w25x32"}, {"w25q32"}, {"w25q32dw"},
{"w25q80bl"}, {"w25q128"}, {"w25q256"},
/* Flashes that can't be detected using JEDEC */
{"m25p05-nonjedec"}, {"m25p10-nonjedec"}, {"m25p20-nonjedec"},
{"m25p40-nonjedec"}, {"m25p80-nonjedec"}, {"m25p16-nonjedec"},
{"m25p32-nonjedec"}, {"m25p64-nonjedec"}, {"m25p128-nonjedec"},
/* Everspin MRAMs (non-JEDEC) */
{ "mr25h256" }, /* 256 Kib, 40 MHz */
{ "mr25h10" }, /* 1 Mib, 40 MHz */
{ "mr25h40" }, /* 4 Mib, 40 MHz */
{ },
};
我在修改中发现这一步并非必须,在设备树中使用 mx25l25635e 这个型号也是可以正常读写 mx25l25645g 的flash的。
增加对uart1和uart2的使能
修改 .../v3s/linux/arch/arm/boot/dts/sun8i-v3s.dtsi,增加 uart1 和 uart2 的定义,如下。
uart0: serial@01c28000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28000 0x400>;
interrupts = <GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu CLK_BUS_UART0>;
resets = <&ccu RST_BUS_UART0>;
status = "disabled";
};
uart1: serial@01c28400 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28400 0x400>;
interrupts = <GIC_SPI 1 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu CLK_BUS_UART1>;
resets = <&ccu RST_BUS_UART1>;
status = "disabled";
};
uart2: serial@01c28800 {
compatible = "snps,dw-apb-uart";
reg = <0x01c28800 0x400>;
interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu CLK_BUS_UART2>;
resets = <&ccu RST_BUS_UART2>;
status = "disabled";
};
编译内核
完成了上述配置后,使用
make ARCH=arm -j16
make ARCH=arm dtbs
编译完成后,zImage 存放在 .../v3s/linux/arch/arm/boot/中,sun8i-v3s-licheepi-zero-dock.dtb 和 sun8i-v3s-licheepi-zero.dtb 存放在 .../v3s/linux/arch/arm/boot/dts中。