- 系统底层与硬件
- 嵌入式
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
USB4 高速信号对 PCB 走线长度与信号完整性提出了严苛要求,drivers/intel/usb4/retimer驱动的出现正是为了应对这一挑战:它在 coreboot 固件中为 USB4 Retimer(重定时器)生成 ACPI AML 代码,通过 GPIO 控制 Retimer 上下电,使操作系统能够安全更新其固件。本文以 Documentation/drivers/retimer.md 为骨架,结合src/drivers/intel/usb4/retimer/源码与真实主板配置,深入剖析其工作原理、设备树配置与_DSM实现细节。读完你将掌握在 coreboot 中启用该驱动、配置 GPIO 电源引脚、理解端口映射,以及如何在 SoC 层扩展 EC 命令与端口转换逻辑的完整方法。
Retimer 与 Redriver:信号完整性方案的两条路线
高速信号时代的走线难题
随着 USB 规范演进,速率从 5Gbps(USB 3.0)提升到 10Gbps(USB 3.1/3.2 Gen2),并在 USB4 中达到 20Gbps 甚至更高。高频信号通过 PCB 走线、连接器、CPU 封装等电路组件时,会受到严重的衰减(attenuation)与失真,长走线尤其明显。这直接推动了信号中继器件的普及。
Redriver:无协议感知的模拟放大
Redriver(重驱动器)是无协议感知的模拟器件,它放大信号中的高频成分以补偿衰减。因为不解析数据协议,它结构简单、成本低,但存在明显局限:
- 无法区分信号与噪声,对噪声同样放大;
- 无法恢复时钟或重建数据,只能做波形补偿;
- 在部分场景下效果有限甚至完全失效(如信号已严重劣化时)。
Retimer:协议感知的数字中继
Retimer(重定时器)则通过CDR(Clock and Data Recovery,时钟数据恢复)恢复时钟与数据,再重新发送一份"全新副本"的信号,即它是协议感知的数字器件。由于内部是数字逻辑,Retimer 往往带有自己的固件,这也解释了为何它需要电源控制与固件更新能力——这正是本驱动的核心使命。
驱动定位与编译条件
Kconfig 开关与代码归属
驱动源码位于 src/drivers/intel/usb4/retimer/:
- Kconfig 定义
DRIVERS_INTEL_USB4_RETIMER开关,depends on HAVE_ACPI_TABLES,说明它只在支持 ACPI 表的平台上可用; - Makefile.mk 在
CONFIG_DRIVERS_INTEL_USB4_RETIMER使能后,于ramstage编译retimer.c(ramstage-$(CONFIG_DRIVERS_INTEL_USB4_RETIMER) += retimer.c)。
从源码结构看,ramstage 阶段生成 SSDT 是 coreboot ACPI 驱动的标准做法,device_operations中的.acpi_fill_ssdt回调即由此接入(retimer.c)。
设备树配置:把 Retimer 挂到 PCI 设备下
最小配置示例
文档给出的典型写法是在 USB4 相关 PCI 设备(如 TCSS DMA/主机路由器)下挂载一个 generic 设备:
device pci 0.0 on chip drivers/intel/usb4/retimer register "power_gpio" = "ACPI_GPIO_OUTPUT_ACTIVE_HIGH(GPP_A0)" device generic 0 on end end end关键点:
power_gpio用于给 Retimer 供电的 GPIO,其有效电平(active state)必须是"通电"的那一档,即ACTIVE_HIGH表示高电平通电、ACTIVE_LOW表示低电平通电,需按实际电路选择;- 驱动会生成 ACPI AML 代码,在操作系统通过
_DSM方法请求时翻转该 GPIO。
完整参数模型:chip.h
chip.h 定义的配置结构比文档示例更丰富:
| 参数 | 类型 | 说明 |
|---|---|---|
num_dfps | uint8_t | 下游端口(DFP)数量,上限DFP_NUM_MAX(4);未配置时源码默认设为 2 |
dfp[i].power_gpio | struct acpi_gpio | 控制该 DFP 上 Retimer 供电的 GPIO |
dfp[i].typec_port | struct device * | 与该 Retimer 关联的 Type-C 端口 |
dfp[i].ec_port | enum ec_typec_port | 与 Retimer 关联的 EC Type-C 端口号;当 CPU Type-C 端口到 EC 端口映射非连续时必须正确配置 |
其中ec_port枚举在 chip.h 中定义为UNDEFINED=0、EC_TYPEC_PORT_0~EC_TYPEC_PORT_3。
真实主板配置对照
仓库中多块主板已实际启用该驱动,可作参考模板:
- Google Volteer(voxel):overridetree.cb 中两个 DFP 共用
GPP_H10,并通过use tcss_usb3_port1 as dfp[0].typec_port将 TCSS USB3 端口关联进来; - Intel MTL RVP(mtlrvp_p):devicetree.cb 在
tcss_dma1下为四个 DFP 分别注册,每个 DFP 绑定各自的 Type-C 端口; - 其他启用者还包括
src/mainboard/system76/adl/、src/mainboard/system76/tgl-u/、src/mainboard/framework/marigold/、src/mainboard/intel/ptlrvp/等变体。
这些实例展示了use语法与dfp[i].typec_port的配合方式:typec_port必须是 devicetree 中已定义的 USB 端口设备,驱动通过usb_device->path.usb.port_id读取端口号,再映射到 EC 端口。
ACPI 生成流程:从 devicetree 到 SSDT
入口:usb4_retimer_fill_ssdt
retimer.c 的usb4_retimer_fill_ssdt是核心生成函数,流程如下:
- 取设备 ACPI scope,无 scope 或无配置则直接返回;
num_dfps缺省时置为 2(源码注释说明所有现有主板都是 2 个 DFP);- 写入
Scope与 Host Router 设备HR,_ADR为 0、_STA为全开; - 对每个 DFP:若未配置
power_gpio则打印BIOS_WARNING并跳过;用_ADR = dfp_port*2 + 1表示 lane adapter; - 若使能
DRIVERS_USB_ACPI,通过usb_acpi_get_pld()为 Type-C 连接器填充_PLD(物理位置描述),失败时打印BIOS_ERR; - 写入电源引用计数器
PWR(初值 0),随后生成Method (_DSM, 4, Serialized); _DSM内先做 UUID 匹配检查,不匹配返回Buffer(One){0x0},匹配后按 Arg2(Function Index)分发到三个回调。
_DSM接口:UUID 与函数索引
驱动使用的 UUID 定义于 retimer.c:
E0053122-795B-4122-8A5E-57BE1D26ACB3_DSM的 ACPI 调用约定(Arg0~Arg3):
| 参数 | 含义 |
|---|---|
| Arg0 | UUID |
| Arg1 | Revision ID(本驱动为 1) |
| Arg2 | Function Index(0/1/2) |
| Arg3 | 参数包,set_power_state取Arg3[0] |
三个回调注册于 retimer.c:
| Function Index | 回调 | 行为 |
|---|---|---|
| 0 | usb4_retimer_cb_standard_query | 返回支持的功能位图:Revision 1 返回0x7(支持 0/1/2 三个函数),其他 Revision 返回0x1 |
| 1 | usb4_retimer_cb_get_power_state | 读取HR.DFPx.PWR引用计数,>0 返回 1,否则返回 0 |
| 2 | usb4_retimer_cb_set_power_state | 依据Arg3[0](0 关/1 开)增减PWR并执行对应的在线状态切换 |
电源状态机:引用计数与在线状态切换
PWR引用计数语义
set_power_state的核心是引用计数PWR(retimer.c):
Arg3[0] == 0且PWR > 0:PWR--,当PWR降到 0 时调用disable_retimer_online_state;Arg3[0] == 1且PWR == 0:调用enable_retimer_online_state后PWR++;- 其余情况返回 0;结束时
PWR == 1返回 1,否则返回 0。
引用计数保证多次"上电请求"下,只有最后一个请求释放时才真正断电,避免固件更新中途被意外切断电源。
使能在线状态:enable_retimer_online_state
retimer.c 的注释列出了 NDA 约束下的六步流程:
- Force power on:
acpigen_enable_tx_gpio将power_gpio置为有效电平(供电); - 检查是否有设备连接:执行
GET_MUX命令,期望USB_PD_MUX_NONE(0); - Suspend PD:
SUSPEND_PD命令,期望返回值 0; - Set Mux to USB mode:
SET_USB命令,期望USB_PD_MUX_USB_ENABLED; - Set Mux to Safe mode:
SET_SAFE命令,期望USB_PD_MUX_SAFE_MODE; - Set Mux to TBT mode:
SET_TBT命令,期望USB_PD_MUX_USB4_ENABLED或USB_PD_MUX_TBT_COMPAT_ENABLED。
禁用在线状态:disable_retimer_online_state
retimer.c 执行三步逆操作:
- Set Mux to disconnect:
DISCONNECT命令,期望 0; - Resume PD:
RESUME_PD命令,期望 1; - Force power off:
acpigen_disable_tx_gpio将 GPIO 置为非有效电平。
EC 命令轮询:usb4_retimer_execute_ec_cmd
每个 EC 命令的执行由 retimer.c 的usb4_retimer_execute_ec_cmd生成 AML 轮询逻辑:
- 命令字节 =
cmd << USB_RETIMER_FW_UPDATE_OP_SHIFT(4) | port,通过ec_retimer_fw_update(data)下发; - 最多轮询
USB4_RETIMER_ITERATION_NUM(12)次,每轮USB4_RETIMER_POLL_CYCLE_MS(25ms)睡眠,即单命令最长约 300ms; RFWU返回0xfe(USB_RETIMER_FW_UPDATE_ERROR)时立即返回 -1;GET_MUX返回0xff(USB_RETIMER_FW_UPDATE_INVALID_MUX)则视为无效 MUX 状态继续轮询;- 超时(轮询次数耗尽)或 MUX 掩码校验失败时关闭 GPIO 并返回 -1。
相关常量集中在 retimer.h:MUX 状态标志(USB_PD_MUX_NONE=0、USB_PD_MUX_USB_ENABLED=BIT(0)、USB_PD_MUX_DP_ENABLED=BIT(1)、USB_PD_MUX_SAFE_MODE=BIT(5)、USB_PD_MUX_TBT_COMPAT_ENABLED=BIT(6)、USB_PD_MUX_USB4_ENABLED=BIT(7))、USB_RETIMER_FW_UPDATE_MUX_MASK掩码,以及 1~7 号固件更新操作码。
SoC 层扩展点:弱符号与端口映射
弱符号 EC 钩子
驱动通过两个__weak函数与平台 EC 解耦(retimer.c):
ec_retimer_fw_update_path():返回 EC Retimer 固件更新命令返回寄存器(RFWU)的 ACPI 路径,默认 NULL(此时轮询逻辑退化为仅按超时判断);ec_retimer_fw_update(uint8_t data):向 EC 下发命令字节,默认空实现。
SoC/板级代码需提供强实现才能驱动真实 EC。从源码注释可推断,RFWU路径通常形如\\_SB.PCI0.TDMx.ARG(见 retimer.c 的路径拼接逻辑)。
物理端口到 EC 端口的映射
retimer_get_index_for_typec()是另一个__weak函数(retimer.c),负责将 CPU 物理 Type-C 端口号转换为抽象的 EC 端口号,默认返回原值。
源码注释给出了需要覆盖的典型场景:主板可能仅使能物理 TCSS 端口 1 和 3,EC 会将其编号为端口 0 和 1;若 coreboot 仍以物理号 3 下发命令,EC 将因索引错误而报错。因此每个使用该驱动的 SoC 代码都应实现此函数。此外,若设备树显式配置了dfp[i].ec_port(非UNDEFINED),则优先使用该显式值(config->dfp[dfp_port].ec_port - EC_TYPEC_PORT_0),否则调用retimer_get_index_for_typec()推导。
启用驱动的完整步骤清单
综合以上分析,在自定义主板上启用 USB4 Retimer 驱动的步骤如下:
- 确认硬件:主板上存在 USB4 Retimer(通常靠近 USB4 端口),且平台支持 ACPI 表(
HAVE_ACPI_TABLES); - 配置 Kconfig:在板级或 SoC 配置中使能
DRIVERS_INTEL_USB4_RETIMER; - 编写 devicetree:在 USB4 主机路由器(如
tcss_dma类 PCI 设备)下挂载chip drivers/intel/usb4/retimer,为每个 DFP 配置power_gpio、typec_port(用use引用已定义的 USB 端口),必要时配置ec_port与num_dfps; - 实现 EC 钩子:在 SoC 或板级代码中提供
ec_retimer_fw_update_path()、ec_retimer_fw_update()的强实现,让生成的 AML 能真正与 EC 交互; - 实现端口映射:实现
retimer_get_index_for_typec()处理物理端口到 EC 端口的非连续映射; - 验证:编译后检查 SSDT 中是否生成
HR/DFPx设备与_DSM方法,确认PWR引用计数、GPIO 翻转与 EC 轮询逻辑符合预期(ramstage 日志中的USB Type-C %d mapped to EC port %d可辅助调试)。
总结
coreboot 的drivers/intel/usb4/retimer是一个典型的"固件驱动 + ACPI 生成"二合一组件:它在 ramstage 阶段把 devicetree 中的 GPIO 与端口配置翻译为宿主操作系统可调用的_DSM接口,配合引用计数与 EC 命令轮询,在确保 MUX 状态正确、PD 挂起的前提下安全切换 Retimer 电源,为固件更新创造条件。理解其chip.h参数模型、_DSM回调分发与弱符号扩展点,即可在任意支持 USB4 的 coreboot 平台上快速集成并排查问题。
- 系统底层与硬件
- 嵌入式
【免费下载链接】coreboot
Read-only mirror of https://review.coreboot.org/coreboot.git. Synced every hour. We don't handle Pull Requests.
相关推荐
coreboot 平台无关设备驱动框架全解析:从 Devicetree 绑定到 ACPI 生成
coreboot 平台无关设备驱动框架全解析:从 Devicetree 绑定到 ACPI 生成 导读 coreboot 将大量板载与外插设备(I2C 触摸板、风
系统底层与硬件嵌入式Coreboot:重定义固件世界的开源先锋
Coreboot:重定义固件世界的开源先锋 项目基础介绍与编程语言 Coreboot,一个致力于替换传统BIOS/UEFI固件的自由软件项目,以其源代码的形式存
系统底层与硬件嵌入式grepWin:Windows平台上最强大的正则表达式搜索替换工具终极指南
grepWin:Windows平台上最强大的正则表达式搜索替换工具终极指南 还在为Windows系统中海量文件的文本查找和替换而烦恼吗?grepWin正则表达式
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考