- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
本文聚焦 coreboot 仓库中针对 Cavium(现 Marvell)OcteonTX 系列 SoC 集成的 BDK(Board Development Kit)模块。你将从本文掌握:BDK 在 coreboot 启动流程中承担了哪些初始化职责(romstage 的 DRAM 初始化、ramstage 的 PCIe/QLM/PHY/BGX/SATA 等外设初始化)、它为何使用一套独立于 coreboot 的 devicetree 机制(key-value 存储与bdk_config_set_fdt()通告方式)、如何用devicetree_convert.py把 DTB 转换成静态 C 数组,以及在 menuconfig 中如何开启分阶段 verbose 日志辅助调试。
BDK 在 coreboot 中的角色与源码结构
根据 Documentation/vendorcode/cavium/bdk.md 的说明,Cavium BDK 的一部分被移植进 coreboot 的 vendorcode,位于 src/vendorcode/cavium/bdk 目录。它按启动阶段承担两类截然不同的初始化工作:
- romstage:DRAM 初始化——内存训练、SPD 读取、DLL 调优等都由 BDK 的
libbdk-dram与libdram子库完成; - ramstage:外设初始化——PCIe、QLM(Quad Lane Module,四通道串行收发模块)、SLI(System Level Interface)、PHY、BGX(以太网端口组)、SATA 等高速外设的初始化由
libbdk-hal与libbdk-boot子库完成。
从 src/vendorcode/cavium/Makefile.mk 的编译清单可以印证这一点:romstage-y只挂载了libbdk-arch(CSR 寄存器、CPU 型号、NUMA)、libbdk-dram(bdk-dram-config.c、bdk-dram-size.c、bdk-dram-test*.c)以及libdram下的一整套 DDR3 初始化与调优文件(dram-init-ddr3.c、dram-tune-ddr3.c、dram-spd.c、libdram-config-load.c等);而ramstage-y则挂载了bdk-qlm*.c、bdk-pcie*.c、bdk-sata.c、bdk-usb.c、bdk-ecam*.c、bdk-boot*.c、bdk-if-phy*.c等外设初始化代码,两者泾渭分明。
仓库中的 BDK 目录按功能划分为以下几个库:
| 子库 | 主要职责 | 典型文件 |
|---|---|---|
libbdk-arch | 架构抽象、CSR 访问、CPU 型号识别 | bdk-csr.c、bdk-model.c、bdk-numa.c |
libbdk-boot | 启动阶段的 QLM/PCIe/USB/GPIO 引导初始化 | bdk-boot-qlm.c、bdk-boot-pcie.c、bdk-boot.c |
libbdk-dram | DRAM 配置、地址映射、尺寸探测与测试 | bdk-dram-config.c、bdk-dram-size.c、bdk-dram-test-*.c |
libbdk-hal | 硬件抽象层:PCIe、QLM、SATA、USB、PHY、时钟、GPIO | bdk-pcie-cn8xxx.c、bdk-qlm.c、bdk-nic.c、bdk-config.c |
libbdk-os | BDK 自身初始化入口 | bdk-init.c |
libbdk-trust | 可信启动支持 | bdk-trust.c |
libdram | DDR3 底层初始化与调优算法 | dram-init-ddr3.c、dram-tune-ddr3.c、dram-spd.c |
此外,bdk/lame_string.c(字符串解析辅助)同时被 romstage 和 ramstage 引用,Makefile.mk 中用# FIXME: Get rid of lame_string.c标注了未来移除的意图。
BDK 为何使用自己的 devicetree
文档明确指出:BDK 使用它自己的一套 devicetree,因为与 coreboot 的 devicetree 不兼容。coreboot 自身的 devicetree 采用.cb文件 + 设备树语言(devicetree.cb)描述芯片组与板载设备的静态拓扑,而 BDK 的 devicetree 是纯粹的key-value 对存储——键与值都以字符串形式保存,用于描述板级制造信息、DRAM 配置、QLM/PCIe/USB/GPIO 等运行参数。
key-value 对的数据结构定义在 src/vendorcode/cavium/include/bdk/bdk-devicetree.h 中,极其精简:
struct bdk_devicetree_key_value { const char *key; const char *value; };数组以{0, 0}作为结束标志(即 key 为 NULL 表示表尾),这与 src/mainboard/cavium/cn8100_sff_evb/bdk_devicetree.c 末尾的{0, 0},终止行完全对应。
通告机制:bdk_config_set_fdt()
文档要求这些 key-value 对必须在 romstage 和 ramstage 中分别通告,使用的是bdk_config_set_fdt()方法。其声明位于 src/vendorcode/cavium/include/bdk/libbdk-hal/bdk-config.h:
int bdk_config_set_fdt(const struct bdk_devicetree_key_value *fdt);该函数的实现位于 src/vendorcode/cavium/bdk/libbdk-hal/bdk-config.c。从源码可以看出两个关键行为:
- 堆与无堆环境的差异处理:在
ENV_HAS_HEAP_SECTION(ramstage 等有堆环境)下,传入的 fdt 会被bdk_config_duplicate()完整复制一份,此后配置表归 BDK 所有;在没有堆的早期阶段(如部分 romstage 场景),则直接保存传入的指针。 - 运行期可改:
bdk_config_set_int()会以"0x%016llx"格式把整数写回配置表(通过set_value()),但注释明确说明这只修改内存中的配置,不会写入持久化存储。
实际的主板代码印证了“两阶段通告”的用法。以仓库内唯一的 Cavium 参考板cn8100_sff_evb为例:
- 在 src/mainboard/cavium/cn8100_sff_evb/romstage.c 中,
platform_romstage_main()先调用bdk_config_set_fdt(devtree),再调用sdram_init()执行 BDK 的 DRAM 初始化; - 在 src/mainboard/cavium/cn8100_sff_evb/mainboard.c 中,ramstage 的
mainboard_enable()再次调用bdk_config_set_fdt(devtree),随后进行 TWSI(I2C)总线、IO 扩展器、SFP+ 光模块 PHY 等板级硬件配置。
两个阶段引用的是同一个extern const struct bdk_devicetree_key_value devtree[],它定义在bdk_devicetree.c中,并且该文件同时被 romstage 与 ramstage 编译(见 src/mainboard/cavium/cn8100_sff_evb/Makefile.mk)。
配置项的命名与取值规则
BDK 的配置项种类由bdk_config_t枚举定义(见 bdk-config.h),覆盖板级制造数据、网络端口与 PHY 布线、BDK 运行参数、芯片特性、QLM、DRAM、USB、SGPIO、VRM 温控、可信启动等全部领域。每一项的实际 key 字符串、类型、默认值、取值范围都集中登记在config_info[]表中(bdk-config.c)。以下是从该表摘出的部分代表性配置项:
| 配置项枚举 | key 格式 | 类型/默认值 | 说明 |
|---|---|---|---|
BDK_CONFIG_BOARD_MODEL | BOARD-MODEL | 字符串,默认unknown | 板卡型号 |
BDK_CONFIG_BOARD_REVISION | BOARD-REVISION | 字符串,默认unknown | 板卡版本 |
BDK_CONFIG_DDR_SPEED | DDR-SPEED.N%d | 整数,0–2400(MT/s),默认 0 | DRAM 速率档位,0 表示由 SPD 自动决定 |
BDK_CONFIG_QLM_MODE | QLM-MODE.N%d.QLM%d | 字符串 | QLM 工作模式(如 PCIe/网络) |
BDK_CONFIG_QLM_FREQ | QLM-FREQ.N%d.QLM%d | 整数,0–10312(MHz) | QLM 频率 |
BDK_CONFIG_PHY_ADDRESS | PHY-ADDRESS.N%d.BGX%d.P%d | 整数,默认 -1 | 网口 PHY 的地址,-1 表示无 PHY |
BDK_CONFIG_BGX_ENABLE | BGX-ENABLE.N%d.BGX%d.P%d | 整数,0/1,默认 1 | 是否启用某 BGX 端口 |
BDK_CONFIG_NUM_PACKET_BUFFERS | BDK-NUM-PACKET-BUFFERS | 整数,0–1000000 | 数据包缓冲数量 |
BDK_CONFIG_PACKET_BUFFER_SIZE | BDK-PACKET-BUFFER-SIZE | 整数,128–32768,默认 1024 | 数据包缓冲字节数 |
BDK_CONFIG_BOOT_MENU_TIMEOUT | BDK-BOOT-MENU-TIMEOUT | 整数,0–300 秒,默认 10 | 启动菜单超时 |
BDK_CONFIG_MULTI_NODE | MULTI-NODE | 整数,0–2,默认 2(自动) | 多节点模式 |
BDK_CONFIG_USB_PWR_GPIO | USB-PWR-GPIO.N%d.PORT%d | 整数,默认 -1 | USB 电源控制 GPIO,-1 表示无 |
BDK_CONFIG_DRAM_SCRAMBLE | DDR-CONFIG-SCRAMBLE | 整数,0/1/2,默认 2 | 内存加扰:0 关、1 开、2 仅信任启动开启 |
参数化 key 中的N%d(节点)、QLM%d、BGX%d、LMC%d(内存控制器)、RANK%d、DIMM%d、PORT%d、LANE%d等占位符,由bdk_config_get_int()/bdk_config_get_str()的变参通过vsnprintf()按config_info[].format展开,例如PHY-ADDRESS.N0.BGX0.P0。
从实现细节看,bdk_config_get_int()(bdk-config.c)的取值过程很有参考价值:
- 若配置表未设置(
config_fdt为空),直接返回该项默认值; - 用
vsnprintf按 format 生成完整 key 并查找;get_value()还支持逐级去掉最后一段(按.切分)回退匹配的机制,例如查不到DDR-CONFIG-CUSTOM-OFFSET.UDIMM.LMC0.N0时依次回退尝试更短前缀; - 解析时对
0x前缀走str_to_hex(),否则走str_to_int(); - 解析失败或超出
min_value/max_value范围时,打印BIOS_WARNING并回退到默认值。
使用 devicetree_convert.py 转换 DTB
文档提到的转换工具是 util/cavium/devicetree_convert.py,其用途是把编译好的 DTB(devicetree blob)转换成静态 C 文件。需要说明的是,该脚本以 Python 2 编写并依赖pyfdt库(from pyfdt.pyfdt import FdtBlobParse),在当前仓库中属于辅助转换工具,需在具备相应 Python 环境的机器上运行。
命令行参数如下:
| 参数 | 含义 |
|---|---|
--indtb | 待解析的已编译 devicetree blob(DTB)路径 |
--out | 输出 C 文件的写入路径 |
--verbose | 开启详细输出,打印每个 key-value 对 |
脚本的核心行为(对照 devicetree_convert.py 的实现):
- 解析 DTB 后,遍历根节点下
cavium,bdk节点的所有子节点; - 节点路径中的
/会被去除,作为配置 key; - 每个节点的值必须是单一字符串(脚本中检查
type(i) is not unicode时报警跳过);若一个节点下挂多个值(数组/多值),脚本会打印Arrays aren't supported并不予转换——这是该工具的一个重要限制; - 输出文件自动生成文件头注释
// This file is automatically generated.、// DO NOT EDIT BY HAND.,并#include <bdk-devicetree.h>,随后逐项输出{"key", "value"},,最后以{0, 0},终止整个数组。
转换产物即上文提到的devtree[]数组。仓库中 src/mainboard/cavium/cn8100_sff_evb/bdk_devicetree.c 正是该工具风格的输出,文件头同样标注了“automatically generated / DO NOT EDIT BY HAND”。它的输入源头是 src/mainboard/cavium/cn8100_sff_evb/ddr4-common.dtsi 等 DTS 片段(其中以/ { cavium,bdk { ... } }组织节点),配合 sff8104-linux.dts 由dtc编译(见 Makefile.mk)。
针对 coreboot 的本地化修改
文档“Modifications”一节列出的四项修改,均能在仓库源码中找到对应证据:
- 适配 coreboot 工具链编译:全部 BDK 源文件直接以
romstage-y/ramstage-y的形式加入 src/vendorcode/cavium/Makefile.mk,由 coreboot 的标准构建系统编译,并在CPPFLAGS_common中追加-Isrc/vendorcode/cavium/include/bdk头文件搜索路径; - 移除 FDT devicetree 支持:coreboot 移植版仅保留上述纯 key-value 的
bdk_devicetree.h结构,不再携带完整 FDT 解析栈(bdk_config_set_fdt()的参数类型也从原版 FDT 指针改成了struct bdk_devicetree_key_value指针); - 裁剪与 SoC 启动无关的文件:vendorcode 目录下仅保留
libbdk-*与libdram中与 bringup 直接相关的子库,未纳入完整 SDK 中的其他组件; - 新增 Kconfig 调试选项:见下文“调试”一节。
此外可以观察到,部分源文件保留了 Cavium 原版 BSD-3-Clause 或修改后的版权注释(如bdk-config.c注明 “This file consists of data imported from bdk-config.c”,主板的mainboard.c注明 “Derived from Cavium's BSD-3 Clause OCTEONTX-SDK-6.2.0”),说明这些代码是从 Cavium SDK 定向导入并本地化后的产物。
调试:menuconfig 中的 verbose 开关
文档给出的调试入口是 menuconfig 的Chipset → BDK菜单,可为一个或多个阶段开启 verbose 控制台输出。这些选项对应 src/vendorcode/cavium/Kconfig 中if CAVIUM_BDK下的menu "BDK"配置块:
| Kconfig 选项 | 作用 | 备注 |
|---|---|---|
CAVIUM_BDK | 在 romstage 中构建 BDK(总开关) | def_bool n,并select HAVE_DEBUG_RAM_SETUP |
CAVIUM_BDK_VERBOSE_INIT | 输出 BDK 初始化过程的详细日志 | |
CAVIUM_BDK_VERBOSE_DRAM | 输出 DRAM 初始化的详细日志 | default y if DEBUG_RAM_SETUP,即开启 coreboot 通用 DRAM 调试开关时默认随动打开 |
CAVIUM_BDK_VERBOSE_DRAM_TEST | 输出 DRAM 测试(raminit tests)详细日志 | |
CAVIUM_BDK_VERBOSE_QLM | 输出 QLM 初始化详细日志 | |
CAVIUM_BDK_VERBOSE_PCIE_CONFIG | 输出 PCIe 配置阶段详细日志 | |
CAVIUM_BDK_VERBOSE_PCIE | 输出 PCIe 初始化阶段详细日志 | |
CAVIUM_BDK_VERBOSE_PHY | 输出 PHY 初始化详细日志 |
除调试开关外,同一菜单下还提供了三项 DRAM 自动调优选项,供内存稳定性调试时调整:
CAVIUM_BDK_DDR_TUNE_HW_OFFSETS:硬件辅助的 DLL 读偏移调优(默认关闭,开启时同时调优 ECC 字节);CAVIUM_BDK_DDR_TUNE_WRITE_OFFSETS:自动调优数据字节的 DLL 写偏移;CAVIUM_BDK_DDR_TUNE_ECC_ENABLE:自动调优 ECC 字节的 DLL 读偏移。
这些开关之所以能生效,是因为 BDK 的 DRAM 初始化代码内部通过BDK_CONFIG_DRAM_VERBOSE(DDR-VERBOSE,取值 0–255)等运行时配置项决定日志输出的详细程度,Kconfig 开关在构建期把这些 verbose 行为编译进对应阶段。
实战示例:cn8100_sff_evb 参考板的完整链路
仓库内实际使用 BDK 的主板为 src/mainboard/cavium/cn8100_sff_evb,对应BOARD_CAVIUM_CN8100_SFF_EVB(Kconfig 中select SOC_CAVIUM_CN81XX,Kconfig)。它在启动各阶段的 BDK 使用方式如下:
- bootblock(bootblock.c):完成串口控制台与 SPI flash(EM100 Pro 上验证)初始化,为后续阶段铺路;
- romstage(romstage.c):
bdk_config_set_fdt(devtree)通告配置 →sdram_init()执行 BDK 的 DRAM 初始化 →soc_mmu_init()建页表,全程以watchdog_poke(0)喂狗防超时复位; - ramstage(mainboard.c):
mainboard_enable()再次通告配置,随后完成 TWSI/IO 扩展器、SFP+ 发射器、VSC7224 重定时器(FSYNC、DFE、EQ 等寄存器配置)、PHY 复位 GPIO 等板级初始化,最后打印 trusted boot、boot method、REF/IO/CORE 时钟、CPU 核数与内存容量等信息。
而承载全部 BDK 配置的devtree[](bdk_devicetree.c)中可以看到实际生效的配置形态,例如:
const struct bdk_devicetree_key_value devtree[] = { {"DDR-TEST-BOOT", "1"}, {"DDR-CONFIG-WODT-MASK.RANKS2.DIMMS2", "0xc0c0303"}, {"DDR-CONFIG-MODE1-RTT-WR.RANKS2.DIMMS1.RANK0", "0x2"}, {"DDR-CONFIG-MODE2-VREF-VALUE.RANKS2.DIMMS1.RANK0", "0x19"}, {"DDR-CONFIG-CUSTOM-MIN-RTT-NOM-IDX", "0x1"}, {"PHY-ADDRESS.N0.BGX0.P0", "0xff000010"}, {"BGX-ENABLE.N0.BGX0.P0", "1"}, {"BDK-NUM-PACKET-BUFFERS", "0x1000"}, {"BDK-PACKET-BUFFER-SIZE", "0x400"}, {"MULTI-NODE", "0"}, {"QLM-DIP-AUTO-CONFIG", "1"}, {"DDR-CONFIG-SPD-ADDR.DIMM0.LMC0", "0x1050"}, {"USB-PWR-GPIO.N0.PORT0", "12"}, {0, 0}, };可以看到,DDR 的 RTT/ODT/VREF 等时序参数均按RANKS/DIMMS/RANK/LMC维度细分键控,PHY 地址与 BGX 使能按N/BGX/P维度描述,运行参数(包缓冲、多节点、QLM 自动配置)以全局键表达——这正是 BDK devicetree 以“可寻址字符串键 + 字符串值”承载复杂板级配置的典型形态,也是理解 BDK 配置体系的最佳入门素材。
总结
Cavium BDK 在 coreboot 中的集成遵循“vendorcode 托管 + 板级通告”的模式:BDK 提供 romstage 的 DRAM 初始化与 ramstage 的高速外设初始化能力,通过一套自有的字符串 key-value devicetree(结构见 bdk-devicetree.h、实现见 bdk-config.c)驱动配置,配置在 romstage 与 ramstage 中通过bdk_config_set_fdt()两次注入;DTB 到 C 数组的转换由 devicetree_convert.py 完成;调试时则在 menuconfig 的 Chipset → BDK 菜单下按阶段打开 verbose 输出(Kconfig 定义见 src/vendorcode/cavium/Kconfig)。对需要在新 Cavium OcteonTX 平台上做 bringup 的开发者而言,以cn8100_sff_evb为模板、按上述链路复用 BDK 是最直接的起步路径。
- 固件
- 嵌入式
- 操作系统
- 驱动开发
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
相关推荐
coreboot 对 Cavium CN81xx SoC 的移植深入解析:Bootflow、CAR、DRAM/PCI 初始化与平台工作区(quirks)
coreboot 对 Cavium CN81xx SoC 的移植深入解析:Bootflow、CAR、DRAM/PCI 初始化与平台工作区(quirks) 本文基
固件嵌入式操作系统驱动开发coreboot 中的 Intel DPTF 实现与 devicetree 配置指南
coreboot 中的 Intel DPTF 实现与 devicetree 配置指南 导读 Intel Dynamic Platform and Thermal
固件嵌入式操作系统驱动开发coreboot 通用 Super I/O SSDT 生成器完全指南:从 devicetree 配置到 ACPI 方法自动生成
coreboot 通用 Super I/O SSDT 生成器完全指南:从 devicetree 配置到 ACPI 方法自动生成 本文介绍 coreboot 中针
固件嵌入式操作系统驱动开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考