4. Layerscape Linux内核裁剪与设备树定制

Layerscape 系列 SoC(如 LS1046A、LS1028A、LX2160A)在出厂 BSP 中提供的 Linux 内核与设备树是"全功能"版本:它同时使能了几乎所有外设驱动、文件系统、调试选项和网络协议栈,镜像体积大、启动时间长,且包含大量目标板并不使用的节点。边缘路由平台通常资源受限、启动时间敏感,因此必须做两件事:一是通过内核配置裁剪掉无关功能,二是通过设备树精确描述本板实际存在的硬件资源。本节围绕这两条主线展开。

内核配置:从 defconfig 到最小可用集

Layerscape 内核源码位于 NXP 官方 GitHub 的 linux 仓库,常用分支如 lf-6.1.y。配置入口是 arch/arm64/configs/defconfig,它已经包含了 Layerscape 平台的基础选项。裁剪时不要直接改 defconfig,而是用 make menuconfig 生成 .config,再通过 make savedefconfig 导出精简后的 defconfig 片段,便于版本管理。

裁剪的核心判断依据是"目标板是否真的需要"。以 LS1046A 边缘路由板为例,典型裁剪方向包括:关闭 CONFIG_DEBUG_* 系列调试选项、关闭未使用的文件系统(如 CONFIG_EXT2_FS、CONFIG_NTFS_FS)、关闭 CONFIG_SOUND、CONFIG_DRM 等显示音频子系统、关闭 CONFIG_BLK_DEV_* 中不用的块设备驱动。但有几类选项必须保留:CONFIG_FSL_DPAA、CONFIG_FSL_DPAA_ETH、CONFIG_FSL_DPAA2(若使用 DPAA2)、CONFIG_FSL_QBMAN、CONFIG_FSL_PAMU,以及 CONFIG_ARM_SMMU_V3(若启用 SMMU)。这些是 DPAA 网络加速的基础,一旦裁掉,网口将无法工作。

裁剪后应验证:make Image 能成功编译,生成的 arch/arm64/boot/Image 体积明显减小(示例:从约 28 MB 降到 18 MB 左右,具体取决于配置),且启动后 dmesg 中不再出现无关驱动的探测日志。若启动失败,优先检查是否误关了 CONFIG_SERIAL_8250、CONFIG_FSL_IFC 等启动必需项。

设备树结构:从 SoC 到板级

Layerscape 设备树采用"SoC 公共部分 + 板级差异"的分层结构。以 LS1046A 为例,arch/arm64/boot/dts/freescale/ 下存在:

  • fsl-ls1046a.dtsi:描述 SoC 内部所有控制器,包括 CPU、内存控制器、串口、I2C、SPI、PCIe、DPAA 相关节点。
  • fsl-ls1046a-rdb.dts:NXP 参考板设备树,#include "fsl-ls1046a.dtsi" 后覆盖板级差异。
  • 自定义板卡设备树:通常命名为 fsl-ls1046a-myboard.dts,只写与参考板不同的部分。

这种结构的价值在于:SoC 级节点只写一次,板级文件只关心"哪些控制器被引出、地址是多少、接了什么器件"。修改时优先改板级 dts,避免动 dtsi。

CPU、内存、串口、网口节点

CPU 节点在 dtsi 中定义为 cpu@0 到 cpu@3(LS1046A 为四核 A72),每个节点包含 reg、device_type = "cpu"、enable-method = "psci"。若板卡只使用部分核心,可在板级 dts 中用 /delete-node/ 删除,或通过内核启动参数 maxcpus= 限制。

内存节点由 memory@80000000 描述,reg = <0x0 0x80000000 0x0 0x80000000> 表示从 0x80000000 起 2 GB。若板卡实际只有 1 GB,必须改为 0x40000000,否则内核会访问不存在的内存导致崩溃。

串口节点为 serial@21c0500(UART0),关键属性是 status = "okay" 和 current-speed = <115200>。调试串口必须保持 okay,否则无法看到启动日志。

网口节点分两类:MAC 控制器(如 ethernet@1d10000)和 PHY。MAC 节点中 phy-handle = <&phy0> 指向 PHY 节点,PHY 节点通过 MDIO 总线挂载,reg = <0x1> 表示 PHY 地址。若 PHY 地址接错,网口会 link down。

DPAA 相关节点

DPAA 是 Layerscape 网络加速的核心,设备树中必须正确描述以下节点:

  • fman@1a00000:Frame Manager,包含 fsl,fman-ports、fsl,fman-muram 等子节点。
  • bman@1ac0000:Buffer Manager,管理数据缓冲区。
  • qman@1ad0000:Queue Manager,管理帧队列。
  • fman0-port@0 等:FMan 的 MAC 端口,与 ethernet 节点通过 fsl,fman-port 关联。

这些节点的 reg 地址和中断号必须与 SoC 手册一致,通常直接沿用 dtsi 中的定义。板级只需确认 status = "okay" 以及 PHY 连接关系正确。若使用 DPAA2(如 LS1088A),则对应 fsl-mc 节点和 dpmac 节点,配置方式不同。

LS1046A 设备树节点关系与内核裁剪关注点 fsl-ls1046a.dtsi(SoC 公共) CPU 节点 cpu@0~3 / psci 内存节点 memory@80000000 串口节点 serial@21c0500 I2C/SPI/PCIe 板级外设总线 DPAA 加速子系统 FMan fman@1a00000 BMan bman@1ac0000 QMan qman@1ad0000 FMan MAC 端口 fman0-port@0 PHY 节点 mdio / phy-handle fsl-ls1046a-myboard.dts(板级) #include "fsl-ls1046a.dtsi" 继承 SoC 公共节点,仅覆盖差异 内存大小修正 reg = <0x0 0x80000000 0x0 0x40000000> 串口使能 status = "okay"; current-speed = <115200> 网口 PHY 关联 phy-handle = <&phy0>; phy-mode = "sgmii" 内核裁剪必须保留 CONFIG_FSL_DPAA / QBMAN / PAMU 覆盖

编译与更新

设备树编译使用 make dtbs,生成 arch/arm64/boot/dts/freescale/fsl-ls1046a-myboard.dtb。内核编译使用 make Image。两者可并行执行。

更新到目标板有三种方式:

  1. U-Boot 下 tftp 更新:将 Image 和 .dtb 放到 tftp 服务器,在 U-Boot 中执行 tftp 0x80000000 Image、tftp 0x90000000 fsl-ls1046a-myboard.dtb,然后 booti 0x80000000 - 0x90000000 启动。
  2. 写入 eMMC/SD:将镜像写入 /boot 分区,修改 extlinux.conf 或 U-Boot 环境变量指向新文件。
  3. OTA 更新:在运行系统中通过 dd 或专用工具写入备用分区,重启切换。

更新后必须验证:串口输出显示内核版本和编译时间正确、dmesg | grep -i fman 能看到 FMan 初始化成功、ip link 能看到网口且 ethtool 显示 link up。若网口未出现,优先检查设备树中 status 和 phy-handle 是否正确。

裁剪内核时建议保留一份"最小可用配置"作为基线,每次修改后对比 dmesg 差异,避免误删关键驱动导致启动失败。
修改内存节点 reg 时务必与板卡实际 DDR 容量一致。若声明大于实际容量,内核启动阶段可能因访问不存在内存而挂死,且现象不易定位。