从一块树莓派4B出发:手把手拆解Linux内核里的BSP与驱动是如何协作的

树莓派4B作为全球最受欢迎的嵌入式开发板之一,其开源的Linux内核实现为我们提供了一个绝佳的学习样本。当你第一次打开树莓派官方内核源码仓库时,可能会被 arch/arm/boot/dts/bcm2711-rpi-4-b.dts 这样的文件吸引——这就是理解BSP与驱动协作的关键入口。本文将带你用工程师的视角,从设备树文件出发,逐步揭示Linux内核如何通过精妙的架构设计,让硬件描述与功能实现既分离又协作。

1. 设备树:BSP的硬件描述语言

在树莓派4B的Linux内核源码中, bcm2711-rpi-4-b.dts 这个设备树文件就像一份硬件"地图"。打开它,你会看到这样的结构:

/ {
    compatible = "raspberrypi,4-model-b", "brcm,bcm2711";
    model = "Raspberry Pi 4 Model B";
    
    memory@0 {
        device_type = "memory";
        reg = <0x0 0x3b400000>;
    };

    soc {
        ranges = <0x7e000000 0x7e000000 0x1000000>;
        gpio@7e200000 {
            compatible = "brcm,bcm2835-gpio";
            reg = <0x7e200000 0xb4>;
            interrupts = <2 17>;
        };
    };
};

这份"地图"精确描述了:

  • CPU架构 :Broadcom BCM2711(ARM Cortex-A72)
  • 内存布局 :起始地址0x0,大小约948MB
  • 外设寄存器 :GPIO控制器位于0x7e200000

为什么需要设备树? 在ARM体系结构中,硬件配置无法像x86那样自动探测。设备树的出现解决了"同一内核镜像适配不同硬件"的难题。树莓派基金会只需维护不同的 .dts 文件,就能让同一内核支持从Zero到4B的所有型号。

BSP工程师的工作重点就是维护这些硬件描述。当你在树莓派上连接新的外设时,可能需要:

  1. 确认硬件连接方式(如I2C地址、中断引脚)
  2. 在设备树中添加相应节点描述
  3. 重新编译并加载设备树二进制(.dtb)

提示:使用 dtc -I dtb -O dts /boot/bcm2711-rpi-4-b.dtb > current.dts 可以反编译当前运行的设备树

2. 驱动如何"读懂"设备树

让我们以树莓派4B的USB控制器驱动为例。在内核源码中搜索 compatible = "brcm,bcm2835-usb" ,你会找到驱动代码如何与设备树交互:

static const struct of_device_id bcm2835_usb_of_match[] = {
    { .compatible = "brcm,bcm2835-usb" },
    {}
};
MODULE_DEVICE_TABLE(of, bcm2835_usb_of_match);

static struct platform_driver bcm2835_usb_driver = {
    .probe = bcm2835_usb_probe,
    .driver = {
        .name = "bcm2835_usb",
        .of_match_table = bcm2835_usb_of_match,
    },
};

这个匹配过程揭示了Linux驱动的典型生命周期:

  1. 设备树解析 :内核启动时,将 .dtb 文件解析为设备节点树
  2. 驱动注册 :USB驱动通过 of_match_table 声明自己支持的设备
  3. 匹配触发 :当 compatible 属性匹配时,调用驱动的 probe() 函数
  4. 资源获取 :驱动从设备树节点中提取寄存器地址、中断号等
static int bcm2835_usb_probe(struct platform_device *pdev)
{
    struct resource *res;
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    usb->regs = devm_ioremap_resource(&pdev->dev, res);
    
    irq = platform_get_irq(pdev, 0);
    ret = devm_request_irq(&pdev->dev, irq, bcm2835_usb_isr, 0, "bcm2835_usb", usb);
}

关键设计哲学 :驱动代码不直接包含硬件参数,而是通过标准接口从设备树获取。这使得同一驱动可以适配不同硬件——只要设备树提供正确的描述。

3. BSP与驱动的分层协作模型

通过分析树莓派4B的GPU驱动,我们可以看到一个清晰的分层架构:

层级 组件 树莓派4B示例 跨平台性
硬件抽象层 BSP arch/arm/mach-bcm2835/ 板级特定
框架层 DRM/KMS drivers/gpu/drm/vc4/ 通用接口
设备驱动层 VC4驱动 drivers/gpu/drm/vc4/vc4_hdmi.c 芯片组特定

这种架构的优势在跨平台移植时尤为明显。比如要将树莓派的显示驱动移植到ROCK 5B(RK3588芯片):

  1. BSP层重写 :在 arch/arm64/boot/dts/rockchip/rk3588s-rock-5b.dts 中添加HDMI节点
  2. 驱动层适配 :使用Rockchip的DRM驱动替代Broadcom的VC4驱动
  3. 框架层不变 :上层应用依然通过标准的 /dev/dri/card0 接口访问

实际开发经验 :当我在为定制板卡移植驱动时,发现80%的工作都在BSP层:

  • 确认时钟树配置是否正确
  • 验证电源管理序列
  • 调试设备树中的DMA通道分配

注意:使用 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- bcm2835_defconfig 可以获取树莓派默认配置

4. 从编译系统看BSP与驱动的整合

树莓派内核的Kconfig系统展示了如何灵活组合BSP与驱动:

# arch/arm/mach-bcm2835/Kconfig
config ARCH_BCM2835
    bool "Broadcom BCM2835 family"
    select ARM_AMBA
    select ARM_TIMER_SP804
    select HAVE_ARM_TWD

# drivers/usb/dwc2/Kconfig
config USB_DWC2
    tristate "DesignWare USB2 DRD Core Support"
    depends on HAS_DMA
    select USB_COMMON

编译时的选择策略:

  • 必选 :BSP核心组件(如 ARCH_BCM2835 )必须静态链接
  • 可选 :大多数驱动可以编译为模块(如 USB_DWC2=m )
  • 动态加载 :通过 modprobe 在运行时添加驱动

查看树莓派实际加载的驱动:

# 列出已加载模块
lsmod | grep dwc2
# 查看模块依赖关系
modinfo dwc2 | grep depends

实用技巧 :当调试启动问题时,在 cmdline.txt 中添加 ignore_loglevel 可以显示所有早期启动信息,帮助诊断BSP初始化问题。

5. 调试实践:当BSP与驱动协作失败时

通过一个真实案例——调试树莓派4B的I2C设备不响应,展示如何排查BSP与驱动问题:

现象 : i2cdetect 显示设备存在但无法通信

排查步骤 :

  1. 确认设备树是否正确:

    dtc -I fs /proc/device-tree | grep i2c
    
  2. 检查时钟配置:

    vcgencmd measure_clock i2c
    
  3. 验证引脚复用:

    raspi-gpio get | grep 'GPIO2\|GPIO3'
    
  4. 分析驱动状态:

    dmesg | grep i2c
    cat /sys/kernel/debug/pinctrl/pinctrl-handles
    

根本原因 :设备树中缺少 i2c1 的 pinctrl 引用,导致引脚未正确初始化。修复方案:

&i2c1 {
    pinctrl-names = "default";
    pinctrl-0 = <&i2c1_pins>;
    status = "okay";
};

经验总结 :BSP问题通常表现为硬件无法访问,而驱动问题更多是功能异常。掌握 devmem2 等直接寄存器访问工具能极大提升调试效率。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐