1. 课程导入

欢迎进入《Qualcomm Linux BSP 开发工程》课程。在嵌入式 Linux 领域,BSP(Board Support Package,板级支持包)是连接芯片硬件与上层操作系统的关键桥梁。对于 Qualcomm 平台而言,BSP 开发不仅涉及传统的引导加载、内核移植与驱动适配,还需要理解高通特有的固件加载机制、电源管理框架、子系统(如 ADSP、CDSP、Modem)协同以及 Yocto/OpenEmbedded 构建体系。本课程将围绕这些核心内容,帮助学习者建立从硬件上电到系统启动、从驱动开发到镜像发布的完整工程能力。

一、学习目标

完成本课程后,学习者应能够独立完成 Qualcomm Linux BSP 的主要开发任务,具体目标包括:

  • 理解 Qualcomm 平台启动链路:从 PBL、XBL、ABL 到 Linux Kernel 与用户空间的关键阶段。
  • 掌握 BSP 源码结构:bootloader、kernel、device tree、firmware、rootfs 与构建系统之间的关系。
  • 能够配置和编译 Yocto 镜像,生成可烧录的 boot 与 system 镜像。
  • 能够修改设备树,适配外设接口,如 I2C、SPI、UART、GPIO、PCIe、USB 等。
  • 能够编写、编译和调试 Linux 内核驱动,并理解 Qualcomm 平台特有的驱动模型。
  • 掌握常见启动问题定位方法,包括串口日志分析、fastboot 烧录、分区表检查与 dmesg 排查。

二、核心概念

在进入具体开发之前,需要先建立几个贯穿全课程的核心概念。BSP 不是单一软件,而是一组按启动顺序和功能层次组织的软件集合。Qualcomm Linux BSP 通常包含以下关键组成部分:

  • Bootloader 链:PBL 是芯片内部固化的初级引导,XBL 负责更复杂的硬件初始化,ABL 则负责加载 Linux 内核并传递启动参数。
  • Device Tree:以 .dts/.dtsi 描述硬件资源,内核通过它识别外设、内存、时钟、电源域和引脚复用。
  • Kernel 与驱动:Linux 内核提供进程、内存、文件系统等基础能力,驱动负责与 Qualcomm 硬件模块交互。
  • Firmware 与子系统:ADSP、CDSP、Modem 等子系统需要独立固件,BSP 负责加载和通信。
  • Rootfs 与构建系统:Yocto/OpenEmbedded 负责生成根文件系统、软件包和最终镜像。

理解 BSP 的关键,不是记住每个目录,而是理解“谁在什么时候加载谁、谁向谁传递什么信息”。启动链路、设备树和构建系统是三条主线。

三、整体框架与开发流程概览

下图展示了 Qualcomm Linux BSP 从硬件上电到应用运行的典型分层结构,以及开发者在各层的主要工作对象。该图不是简单的流程图,而是按启动顺序和软件层次组织的架构关系图,便于建立全局视角。

Qualcomm Linux BSP 分层架构与启动链路 从硬件上电到应用运行,BSP 各层依次接管并传递控制权 硬件平台层 SoC / DDR / eMMC / UFS / PMIC / 时钟 / 引脚 / 外设控制器 上电复位起点 引导加载层 PBL → XBL → ABL → Linux Kernel 负责硬件初始化、镜像校验、启动参数传递 关键产物:xbl.elf / abl.elf boot.img / dtb / dtbo Linux 内核与驱动层 进程调度 / 内存管理 / 文件系统 / 设备模型 / 中断 / 电源管理 Qualcomm 特有驱动:RPMSG、GLINK、QMI、SMMU、Interconnect 关键产物:Image / modules *.ko / dtb 根文件系统与构建层 Yocto / OpenEmbedded / BitBake / 软件包 / systemd / 库与工具链 生成 rootfs 与 system.img 应用与中间件层 用户态服务 / 多媒体 / 网络 / 传感器 / 调试工具 / 业务应用 启动 驱动 构建 应用

从图中可以看出,BSP 开发并不是孤立地修改某一个文件,而是沿着“硬件 → 引导 → 内核 → 根文件系统 → 应用”的链路逐层推进。每一层都有明确的输入、输出和调试手段。例如,引导层关注镜像是否正确加载,内核层关注设备树是否匹配、驱动是否 probe 成功,根文件系统层关注服务是否正常启动。

四、典型开发流程与案例场景

以一个常见的开发任务为例:为某 Qualcomm 开发板新增一颗 I2C 温度传感器。完整的 BSP 开发流程通常包括以下步骤:

  1. 确认硬件连接:传感器挂载在哪一路 I2C,地址是多少,供电和中断引脚如何连接。
  2. 修改设备树:在对应 I2C 节点下增加传感器子节点,配置 reg、compatible、中断和电源属性。
  3. 确认内核驱动:检查内核是否已有对应驱动,若无则需要编写或移植驱动。
  4. 编译内核与设备树:使用 Yocto 或独立内核编译命令生成新的 Image 和 dtb。
  5. 烧录并启动:通过 fastboot 或 QDL 工具烧录 boot 分区,重启设备。
  6. 验证与调试:查看 dmesg、i2c-tools 输出和 sysfs 节点,确认驱动 probe 成功并能读取数据。

下面是一个设备树片段的示例,展示了如何在 I2C 总线下添加传感器节点:

&i2c_1 {
    status = "okay";
    clock-frequency = <400000>;

    temp_sensor: tmp112@48 {
        compatible = "ti,tmp112";
        reg = <0x48>;
        interrupt-parent = <&tlmm>;
        interrupts = <45 IRQ_TYPE_EDGE_FALLING>;
        vcc-supply = <&pm8350_l7>;
    };
};

对应的调试命令如下:

# 查看 I2C 总线上的设备
i2cdetect -y 1

# 查看内核日志中与传感器相关的信息
dmesg | grep -i tmp112

# 读取 sysfs 中的温度值
cat /sys/class/hwmon/hwmon0/temp1_input

在 Qualcomm 平台上,设备树修改后必须确认对应的 dtb 被正确打包进 boot.img 或独立分区,否则内核仍然使用旧硬件描述,驱动不会 probe。

五、常见误区与复盘

初学者在 BSP 开发中容易陷入以下误区:

误区 表现 正确做法
只改内核,不改设备树 驱动编译成功但无法 probe 先确认设备树节点、compatible 和资源描述是否正确
忽略启动链路顺序 镜像烧录后设备无输出 按 PBL→XBL→ABL→Kernel 顺序检查串口日志
直接修改生成目录 重新编译后修改丢失 修改源码层 recipe、dts 或驱动源文件,而非 build 临时目录
不区分 boot 与 system 分区 内核更新了但根文件系统仍旧 明确每个镜像对应的分区和烧录命令
缺少串口日志 问题定位靠猜 始终保留 UART 调试串口,记录完整启动日志

BSP 开发中最耗时的往往不是写代码,而是定位“哪一层没有把信息传对”。因此,建立分层思维和日志意识,比记住具体命令更重要。

本课程后续将沿着上述框架逐步展开:先理解启动链路和源码结构,再进入设备树、内核驱动、Yocto 构建、镜像烧录与系统调试。每一章都会围绕真实开发任务组织内容,帮助你把零散的知识点串成可复用的工程能力。