4. USB控制器设备树绑定:通用USB控制器节点、EHCI/OHCI/xHCI绑定示例

设备树(Device Tree)是嵌入式Linux系统中描述硬件拓扑结构的核心机制。对于USB控制器而言,正确的设备树绑定是驱动能够识别硬件、完成PHY初始化、分配DMA资源以及注册USB总线的前提。本章将深入解析通用USB控制器节点的属性规范,并分别给出EHCI、OHCI、xHCI三种主流控制器的绑定示例。

核心要点: 设备树中的USB控制器节点必须包含 compatible、reg、interrupts 三大基本属性,并根据控制器类型和PHY接口添加 phys、phy-names、dr_mode、maximum-speed 等扩展属性。

4.1 通用USB控制器节点属性

无论哪种USB控制器,其设备树节点都遵循一套通用的属性规范。下表列出了最核心的通用属性及其说明:

属性名 类型 必需 说明
compatible stringlist 是 匹配驱动,如 "generic-ehci"、"snps,dwc3"
reg prop-encoded-array 是 控制器寄存器基地址和长度
interrupts prop-encoded-array 是 中断号及触发类型
phys phandle-array 否 引用PHY提供者节点
phy-names stringlist 否 PHY名称,与 phys 一一对应
dr_mode string 否 DRD模式:"host"、"peripheral"、"otg"
maximum-speed string 否 限制最高速率:"high-speed"、"super-speed"
dma-ranges prop-encoded-array 否 DMA地址映射范围,用于IOMMU/SMMU场景
经验提示: 在编写USB控制器节点时,compatible 字符串的优先级顺序应为“具体型号在前,通用兼容在后”。例如:"fsl,imx6q-usb", "fsl,imx27-usb"。这能确保驱动在匹配时获得最精确的硬件参数。

4.2 EHCI控制器绑定示例

EHCI(Enhanced Host Controller Interface)是USB 2.0高速主控制器的标准接口。在设备树中,EHCI节点通常需要配合一个外部PHY或集成PHY使用。以下是一个典型的EHCI绑定示例:

/* 基于i.MX6Q平台的EHCI控制器设备树节点 */
usbh1: usb@02184200 {
    compatible = "fsl,imx6q-usb", "fsl,imx27-usb";
    reg = <0x02184200 0x200>;
    interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6QDL_CLK_USBOH3>;
    fsl,usbphy = <&usbphy1>;
    phy_type = "utmi_wide";
    dr_mode = "host";
    status = "okay";
};

/* USB PHY节点 */
usbphy1: usbphy@020c9000 {
    compatible = "fsl,imx6q-usbphy", "fsl,imx23-usbphy";
    reg = <0x020c9000 0x1000>;
    interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&clks IMX6QDL_CLK_USBPHY1>;
    fsl,anatop = <&anatop>;
};

上述示例中,fsl,usbphy 是Freescale平台特有的PHY引用方式。对于通用EHCI驱动,更推荐使用标准的 phys 和 phy-names 属性。

避坑指南: 部分SoC的EHCI控制器要求PHY时钟必须与控制器时钟同步。如果设备树中未正确配置 clocks 属性,或者PHY的时钟源与控制器不一致,会导致USB枚举失败或速率降级。务必检查SoC参考手册中的时钟树关系。

4.3 OHCI控制器绑定示例

OHCI(Open Host Controller Interface)主要用于USB 1.1全速/低速设备。在大多数现代SoC中,OHCI与EHCI共享同一个USB端口,但使用不同的寄存器基址。以下是一个OHCI绑定示例:

/* 基于TI AM335x平台的OHCI控制器设备树节点 */
usb_ohci: usb@47400000 {
    compatible = "ti,am335x-ohci", "usb-ohci";
    reg = <0x47400000 0x1000>;
    interrupts = <76 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&l4ls_clkctrl AM3_L4LS_USB0_OHCI_CLKCTRL 0>;
    clocks-names = "usb_ohci";
    phys = <&usb0_phy>;
    phy-names = "usb";
    status = "okay";
};

/* 共享的USB PHY节点 */
usb0_phy: usb-phy@47401300 {
    compatible = "ti,am335x-usb-phy";
    reg = <0x47401300 0x100>;
    clocks = <&l4ls_clkctrl AM3_L4LS_USB0_PHY_CLKCTRL 0>;
    clock-names = "phy";
    #phy-cells = <0>;
};

注意:OHCI和EHCI通常共享同一个PHY。在设备树中,两个控制器节点应引用同一个PHY节点,但驱动初始化时会分别对PHY进行配置。

4.4 xHCI控制器绑定示例

xHCI(eXtensible Host Controller Interface)是USB 3.0及以后版本的标准控制器,同时支持USB 3.0、2.0和1.1设备。xHCI的设备树绑定通常更复杂,因为它可能涉及多个PHY(例如SuperSpeed PHY和HighSpeed PHY)。以下是一个基于Synopsys DWC3核心的xHCI绑定示例:

/* 基于Qualcomm平台的DWC3 xHCI控制器设备树节点 */
usb_ss: usb@a600000 {
    compatible = "qcom,dwc3", "snps,dwc3";
    reg = <0x0a600000 0x10000>;
    interrupts = <0 138 IRQ_TYPE_LEVEL_HIGH>;
    clocks = <&gcc GCC_USB30_MASTER_CLK>,
             <&gcc GCC_USB30_MOCK_UTMI_CLK>,
             <&gcc GCC_USB30_PIPE_CLK>;
    clock-names = "core", "mock_utmi", "pipe";
    phys = <&usb_ss_phy>, <&usb_hs_phy>;
    phy-names = "usb3-phy", "usb2-phy";
    dr_mode = "host";
    maximum-speed = "super-speed";
    snps,dis_u2_susphy_quirk;
    snps,dis_enblslpm_quirk;
    status = "okay";
};

/* SuperSpeed PHY */
usb_ss_phy: phy@a700000 {
    compatible = "qcom,usb-ss-phy";
    reg = <0x0a700000 0x1000>;
    clocks = <&gcc GCC_USB3_PHY_PIPE_CLK>;
    clock-names = "pipe";
    #phy-cells = <0>;
};

/* HighSpeed PHY */
usb_hs_phy: phy@a710000 {
    compatible = "qcom,usb-hs-phy";
    reg = <0x0a710000 0x1000>;
    clocks = <&gcc GCC_USB2_PHY_CLK>;
    clock-names = "ref";
    #phy-cells = <0>;
};
关键差异: xHCI节点通常需要两个PHY:一个用于USB 3.0 SuperSpeed信号(usb3-phy),另一个用于USB 2.0 HighSpeed/FullSpeed信号(usb2-phy)。此外,xHCI驱动还支持多种 snps,* 厂商属性,用于关闭特定电源管理优化,以解决兼容性问题。

4.5 USB控制器与PHY的绑定关系图

下图展示了通用USB控制器节点与PHY节点之间的绑定关系,以及驱动初始化时的数据流:

USB控制器设备树绑定与PHY初始化关系图 设备树(Device Tree) USB控制器节点 compatible = "snps,dwc3" reg = <0xa600000 0x10000> interrupts = <0 138 4> phys = <&ss_phy>, <&hs_phy> phy-names = "usb3-phy", "usb2-phy" SuperSpeed PHY compatible = "qcom,usb-ss-phy" reg = <0xa700000> #phy-cells = <0> HighSpeed PHY compatible = "qcom,usb-hs-phy" reg = <0xa710000> #phy-cells = <0> 驱动初始化流程 步骤1:of_match_node() 匹配 compatible 找到对应的USB控制器驱动 步骤2:of_platform_populate() 解析子节点 创建platform_device 步骤3:devm_phy_get() 获取PHY句柄 通过phys属性查找PHY提供者 步骤4:phy_init() + phy_power_on() 初始化PHY并上电 步骤5:usb_add_hcd() 注册USB主机控制器 说明:PHY的初始化顺序由phy-names决定,usb3-phy通常先于usb2-phy

4.6 绑定属性对比表

为了帮助开发者快速区分三种控制器的设备树绑定差异,下表从关键属性维度进行了对比:

对比维度 EHCI OHCI xHCI
兼容字符串 "generic-ehci" 或厂商定制 "generic-ohci" 或厂商定制 "snps,dwc3" 或 "generic-xhci"
PHY数量 通常1个(UTMI/ULPI) 通常1个(与EHCI共享) 通常2个(SS PHY + HS PHY)
PHY名称规范 "usb" 或 "phy" "usb" 或 "phy" "usb3-phy" + "usb2-phy"
最大速率 High-Speed (480 Mbps) Full-Speed (12 Mbps) Super-Speed (5 Gbps) 及以上
DMA需求 通常不需要额外配置 通常不需要额外配置 可能需要 dma-ranges 或 iommus
电源管理属性 较少 较少 较多(如 snps,dis_u2_susphy_quirk)

4.7 常见绑定错误与调试方法

在实际开发中,USB控制器设备树绑定错误是导致驱动加载失败的主要原因之一。以下列出三种最常见的错误场景及对应的调试方法:

  • 错误1:PHY节点未定义 #phy-cells 属性
    驱动调用 devm_phy_get() 时返回 -EPROBE_DEFER 或 -EINVAL。
    调试方法: 检查PHY节点是否包含 #phy-cells = <0>;使用 ls /sys/kernel/debug/device_component/ 查看组件绑定状态。
  • 错误2:时钟名称与驱动不匹配
    驱动调用 clk_get() 失败,导致PHY初始化超时。
    调试方法: 在驱动中增加 dev_dbg() 打印时钟名称;对照SoC参考手册确认 clock-names 的字符串值。
  • 错误3:中断号配置错误
    控制器无法响应中断,USB枚举卡在“New USB device found”阶段。
    调试方法: 使用 cat /proc/interrupts 确认中断是否被触发;检查 interrupts 属性中的触发类型(如 IRQ_TYPE_LEVEL_HIGH)。
调试利器: 在Linux内核启动参数中添加 dyndbg="file drivers/usb/* +p" 可以动态开启USB子系统所有调试信息。配合 devicetree/unittest 框架,可以验证设备树节点属性的正确性。

4.8 小结

本章详细介绍了USB控制器设备树绑定的通用规范,并给出了EHCI、OHCI、xHCI三种主流控制器的完整绑定示例。开发者需要重点掌握 compatible、reg、interrupts 三大基本属性,以及 phys、phy-names、dr_mode 等与PHY初始化相关的扩展属性。在实际项目中,建议始终参考SoC厂商提供的设备树绑定文档,并结合内核源码中的 Documentation/devicetree/bindings/usb/ 目录下的YAML绑定文件进行验证。