RK3588 USB3 Host 控制器依赖分析文档
概述
本文档记录 RK3588 SoC 上 USB3OTG1 (usb@fc400000) 主机控制器的完整依赖关系分析,包括寄存器基地址、电源域、时钟、复位和 PHY 依赖。
目标: 解决 DWC3 PHY 寄存器 (GUSB3PIPECTL, GUSB2PHYCFG) 无法写入的问题
分析日期: 2025-12-30
寄存器基地址映射
控制器和 PHY 寄存器
| 组件 | 基地址 | 大小 | 说明 |
|---|---|---|---|
| DWC3 控制器 | 0xfc400000 | 0x400000 (4MB) | USB3 DRD 控制器寄存器空间 |
| USBDP PHY | 0xfed90000 | 0x10000 (64KB) | USB3.0 Combo PHY 寄存器 |
| USB2 PHY | 0xfd5d8000 | 0x4000 (16KB) | USB2 PHY 寄存器 (USB2PHY1) |
GRF (General Register Files)
| GRF 名称 | 基地址 | 大小 | 用途 |
|---|---|---|---|
| USB GRF | 0xfd5ac000 | 0x4000 | USB3 OTG 端口配置 (U3_PORT_ENABLE) |
| USBDP PHY GRF | 0xfd5cc000 | 0x4000 | USBDP PHY 低功耗控制 (LOW_PWRN) |
| USB2PHY GRF | 0xfd5d4000 | 0x4000 | USB2 PHY 配置 (端口使能、挂起控制) |
| PIPE PHY GRF | 0xfd5c0000 | 0x100 | PIPE PHY 配置 |
系统控制寄存器
| 组件 | 基地址 | 大小 | 说明 |
|---|---|---|---|
| CRU | 0xfd7c0000 | 0x5c000 | 时钟和复位单元 (Clock & Reset Unit) |
| PMIC | 0xfd8d8000 | 0x1000 | 电源管理 IC (Power Domain Control) |
电源域依赖
必需的电源域
根据设备树 usb@fc400000 节点:
power-domains = <&power 31>; // USB power domain
| 电源域 ID | 名称 | 状态 | 说明 |
|---|---|---|---|
| 31 | USB | ✅ 已使能 | USB3 OTG 控制器电源域 |
| 32 | PHP | ✅ 已使能 | 高性能总线电源域(可选但推荐) |
电源域初始化代码
// 使能 USB 电源域 (domain 31)
pm.power_domain_on(rockchip_pm::PowerDomain(31))?;
// 可选:使能 PHP 电源域 (domain 32)
pm.power_domain_on(rockchip_pm::PowerDomain(32))?;
时钟依赖
DWC3 控制器时钟
| 时钟名称 | CRU ID | 寄存器地址 | 位 | 说明 |
|---|---|---|---|---|
| ACLK_USB3OTG1 | 420 | 0xfd7c0368 | 4 | AXI 总线时钟 |
| SUSPEND_CLK_USB3OTG1 | 421 | 0xfd7c0368 | 5 | 挂起时钟 |
| REF_CLK_USB3OTG1 | 422 | 0xfd7c0368 | 6 | 参考时钟 |
USBDP PHY 时钟
根据设备树 phy@fed90000 节点:
clocks = <&cru 694>, <&cru 640>, <&cru 617>, &u2phy1>;
clock-names = "refclk", "immortal", "pclk", "utmi";
| 时钟名称 | CRU ID | 寄存器地址 | 位 | 来源 | 说明 |
|---|---|---|---|---|---|
| refclk | 694 (0x2b6) | 0xfd7c03ac | 6 | CRU | 24MHz 参考时钟 |
| immortal | 640 (0x280) | 0xfd7c039c | 15 | CRU | 始终开启的时钟 |
| pclk | 617 (0x269) | 0xfd7c0398 | 9 | CRU | APB 外设时钟 |
| utmi | - | - | - | USB2 PHY | UTMI 480MHz 时钟 (关键!) |
USB2 PHY 时钟
根据设备树 usb2-phy@4000 节点:
clocks = <&cru 693>;
clock-names = "phyclk";
clock-output-names = "usb480m_phy1";
#clock-cells = <0>;
| 时钟名称 | CRU ID | 寄存器地址 | 位 | 输出 | 说明 |
|---|---|---|---|---|---|
| phyclk | 693 (0x2b5) | 0xfd7c03ac | 5 | 480MHz UTMI | USB2 PHY 参考时钟 |
时钟链完整性
CRU phyclk(693) → USB2 PHY → UTMI 480MHz → USBDP PHY utmi → DWC3 PHY 接口
↓
GUSB2PHYCFG/GUSB3PIPECTL
(可访问)
⚠️ 关键发现: USB2 PHY 必须正常工作并输出 UTMI 480MHz 时钟,USBDP PHY 的 PIPE 接口才能工作,DWC3 的 PHY 配置寄存器才能访问。
复位依赖
DWC3 控制器复位
根据设备树 usb@fc400000 节点:
resets = <&cru 679>;
reset-names = "usb3-otg";
| 复位名称 | CRU ID | 寄存器地址 | 位 | 说明 |
|---|---|---|---|---|
| SRST_A_USB3OTG1 | 679 (0x2a7) | 0xfd7c04a8 | 7 | DWC3 AXI/AHB 复位 |
USBDP PHY 复位
根据设备树 phy@fed90000 节点:
resets = <&cru 47>, <&cru 48>, <&cru 49>, <&cru 50>, <&cru 1154>;
reset-names = "init", "cmn", "lane", "pcs_apb", "pma_apb";
| 复位名称 | CRU ID | 寄存器地址 | 位 | 说明 |
|---|---|---|---|---|
| init | 40 (0x28) | 0xfd7c0408 | 8 | PHY 初始化复位 |
| cmn | 41 (0x29) | 0xfd7c0408 | 9 | 公共模块复位 |
| lane | 42 (0x2a) | 0xfd7c0408 | 10 | Lane 复位 |
| pcs_apb | 43 (0x2b) | 0xfd7c0408 | 11 | PCS APB 复位 |
| pma_apb | 1154 (0x482) | 0xfd7c0520 | 2 | PMA APB 复位 |
USB2 PHY 复位
根据设备树 usb2-phy@4000 节点:
resets = <&cru 0xc0048>, <&cru 0x489>;
reset-names = "phy", "apb";
| 复位名称 | CRU ID | 寄存器地址 | 位 | 说明 |
|---|---|---|---|---|
| apb | 1161 (0x489) | 0xfd7c0520 | 9 | USB2 PHY APB 总线复位 |
| phy | 未实现 | - | - | USB2 PHY 核心复位(特殊值 0xc0048) |
注: 0xc0048 是一个特殊值,可能需要特殊处理。
PHY 依赖关系
设备树 PHY 引用
/* usb@fc400000 */
phys = <&u2phy1_otg 0>, <&usbdp_phy1_u3 0>;
phy-names = "usb2-phy", "usb3-phy";
| PHY | 设备树节点 | 基地址 | 说明 |
|---|---|---|---|
| USB2 PHY | syscon@fd5d4000/usb2-phy@4000 | 0xfd5d8000 | 提供 UTMI 480MHz 时钟 |
| USB3 PHY | phy@fed90000 | 0xfed90000 | 提供 USB3.0 SuperSpeed 接口 |
PHY 初始化顺序
根据 TRM Fig. 14-4 和 u-boot 驱动,正确的初始化顺序:
1. USB2 PHY 初始化 (最优先!)
├── 使能 phyclk (693)
├── 解除 APB 复位 (1161)
├── 配置 USB2PHY GRF (端口使能)
└── 等待 PLL 锁定 (2ms)
↓
UTMI 480MHz 时钟开始输出
↓
2. USBDP PHY 初始化
├── 使能时钟 (694, 640, 617)
├── 退出低功耗模式 (GRF LOW_PWRN)
├── 解除 APB 复位 (43, 1154)
├── 配置初始化序列
├── 配置参考时钟 (24MHz)
├── 配置 lane mux
├── 解除 init/cmn/lane 复位 (40, 41, 42)
└── 等待 PLL 锁定 (LCPLL)
↓
3. DWC3 全局配置
├── 验证 SNPSID
├── 配置 GCTL
└── 设置 HOST 模式
↓
4. xHCI 主机控制器初始化
└── 执行 HCRST (使能 PHY 接口)
↓
5. DWC3 PHY 寄存器配置
├── GUSB3PIPECTL (USB3)
└── GUSB2PHYCFG (USB2)
GRF 寄存器配置
USB2PHY GRF 配置
地址: 0xfd5d4000
功能: USB2 PHY 端口控制和挂起管理
| 寄存器 | 偏移 | 位 | 说明 | 写入值 |
|---|---|---|---|---|
| CON | 0x00 | [1] | PORT_ENABLE | 1 << 1 | 1 << 17 |
| [0] | PORT_SUSPEND | 0 << 0 | 1 << 16 |
Rockchip GRF 格式:
Bit[31:16] - 写使能位(每 bit 独 立控制)
Bit[15:0] - 数据位
USBDP PHY GRF 配置
地址: 0xfd5cc000
功能: USBDP PHY 低功耗控制
| 寄存器 | 偏移 | 位 | 说明 | 写入值 |
|---|---|---|---|---|
| LOW_PWRN | 0x04 | [13] | LOW_PWRN (PowerUp) | 1 << 13 | 1 << 29 |
| [14] | RX_LFPS (Enable) | 1 << 14 | 1 << 30 |
USB GRF 配置
地址: 0xfd5ac000
功能: USB3 OTG 端口配置
| 寄存器 | 偏移 | 位 | 说明 |
|---|---|---|---|
| USB3OTG1_CFG | 0x34 | [15] | PIPE_ENABLE |
| [12] | PHY_DISABLE | ||
| [10] | SUSPEND_ENABLE | ||
| [8] | U3_PORT_DISABLE |
启用 U3 端口: 清除 bit[8] (U3_PORT_DISABLE = 0)
当前问题分析
问题描述
DWC3 PHY 配置寄存器无法写入:
GUSB3PIPECTL= 0x00000000 (不可写)GUSB2PHYCFG= 0x00000000 (不可写)
已实现的依赖
| 组件 | 时钟 | 复位 | 电源域 | GRF | 状态 |
|---|---|---|---|---|---|
| DWC3 控制器 | ✅ 420, 421, 422 | ✅ 679 | ✅ 31, 32 | - | ✅ 完成 |
| USBDP PHY | ✅ 617, 639, 694 | ✅ 40, 41, 42, 43, 1154 | - | ✅ dp_grf, usb_grf | ✅ 完成 |
| USB2 PHY | ✅ 693 | ✅ 1161 | - | ✅ usb2phy_grf | ✅ 完成 |
可能的根因
尽管所有依赖都已实现,PHY 寄存器仍不可写,可能的原因:
-
USB2 PHY UTMI 480MHz 时钟未真正启动
- USB2PHY GRF 配置可能不完整
- 可能需要额外的 PLL 配置
-
USBDP PHY PIPE 接口未正确初始化
- PIPE PHY GRF 可能需要额外配置
- UTMI 时钟输入可能需要显式连接
-
DWC3 控制器时钟域问题
- 某 些时钟可能需要特定相位或频率
- 可能存在时钟门控问题
-
硬件差异或 TRM 未说明的要求
- RK3588 可能有特定的初始化序列
- 可能需要额外的魔法寄存器配置
诊断步骤
- 检查 USB2 PHY 寄存器实际状态
- 验证 USBDP PHY 寄存器配置
- 对比 Linux 内核 RK3588 DWC3 驱动初始化代码
- 检查是否有遗漏的 GRF 配置
参考信息
相关文档
- RK3588 TRM (Technical Reference Manual) Chapter 14
- Linux: drivers/phy/rockchip/phy-rockchip-usbdp.c
- Linux: drivers/usb/dwc3/core.c
- U-Boot: drivers/phy/phy-rockchip-usbdp.c
- U-Boot: drivers/usb/host/xhci-dwc3.c
设备树参考
/* USB3OTG1 控制器 */
usb@fc400000 {
compatible = "snps,dwc3";
reg = <0x00 0xfc400000 0x00 0x400000>;
interrupts = <0x00 0xdd 0x04>;
power-domains = <0x61 0x1f>; /* power domain 31 */
resets = <0x02 0x2a7>; /* reset 679 */
dr_mode = "host";
phys = <0x1aa 0x1ab>; /* USB2 PHY, USB3 PHY */
phy-names = "usb2-phy\0usb3-phy";
};
/* USBDP PHY */
phy@fed90000 {
compatible = "rockchip,rk3588-usbdp-phy";
reg = <0x00 0xfed90000 0x00 0x10000>;
clocks = <0x02 0x2b6 0x02 0x280 0x02 0x26a 0x1ce>;
resets = <0x02 0x2f 0x02 0x30 0x02 0x31 0x02 0x32 0x02 0x484>;
rockchip,u2phy-grf = <0x1cc>;
rockchip,usb-grf = <0x75>;
rockchip,usbdpphy-grf = <0x1cd>;
};
/* USB2 PHY */
usb2-phy@4000 {
compatible = "rockchip,rk3588-usb2phy";
reg = <0x4000 0x10>;
clocks = <0x02 0x2b5>;
clock-output-names = "usb480m_phy1";
resets = <0x02 0xc0048 0x02 0x489>;
rockchip,usbctrl-grf = <0x75>;
};
DWC3 寄存器详细说明 (基于 TRM Chapter 13)
寄存器地址映射
DWC3 控制器寄存器位于 USB3OTG 基地址 0xfc400000 的偏移处:
| 寄存器名称 | 偏移 (Operational Base) | 说明 |
|---|---|---|
| GCTL | 0xC110 | 全局控制寄存器 |
| GSTS | 0xC118 | 全局状态寄存器 |
| GSNPSID | 0xC120 | Synopsys ID 寄存器 |
| GUSB2PHYCFG(n) | 0xC200 + 0x04*n | USB2 PHY 配置寄存器 |
| GUSB3PIPECTL(n) | 0xC2C0 + 0x04*n | USB3 PHY PIPE 控制寄存器 |
GCTL - 全局控制寄存器 (0xC110)
复位值: 0x30c11004
| 位 | 名称 | 访问 | 复位值 | 说明 |
|---|---|---|---|---|
| [31:19] | pwrdnscale | RW | 0x026a | Power Down Scale (不适用) |
| [18] | masterfiltbypass | RW | 0x0 | 主过滤器旁路 |
| [17] | bypassetaddr | RW | 0x0 | 旁路 Set Address (仅仿真) |
| [16] | u2rstecn | RW | 0x1 | USB2.0 复位使能检查次数 |
| [15:14] | frmscldwn | RW | 0x0 | SOF/USOF 持续时间缩放 |
| [13:12] | prtcapdir | RW | 0x0 | 端口能力方向 (关键!) |
| [11] | coresoftreset | RW | 0x0 | 核心软复位 |
| [10:4] | reserved | - | - | 保留 |
| [3:0] | reserved | - | - | 保留 |
prtcapdir (bit[13:12]) - 端口能力方向:
2'b01: Host 配置2'b10: Device 配置- 软件应基于 IDDIG 输入设置 USB 控制器为 OTG 2.0 A 设备或 B 设备
coresoftreset (bit[11]) - 核心软复位:
1'b0: 无软复位1'b1: 对核心执行软复位- 清除中断和所有 CSR,除了以下寄存器:
- GCTL, GUCTL, GSTS, GSNPSID, GGPIO, GUID
- GUSB2PHYCFGn 寄存器
- GUSB3PIPECTLn 寄存器
- DCFG, DCTL, DEVTEN, DSTS
GUSB2PHYCFG(n) - USB2 PHY 配置寄存器 (0xC200)
复位值: 0x20000000
| 位 | 名称 | 访问 | 复位值 | 说明 |
|---|---|---|---|---|
| [31] | physoftrst | RW | 0x0 | UTMI PHY 软复位 |
| [30] | u2_freeclk_exists | RW | 0x1 | USB 2.0 自由运行 PHY 时钟存在 |
| [29:25] | reserved | RO | 0x00 | 保留 |
| [24:22] | lstrd | RW | 0x0 | LS 转向时间 (2-5.5 bit times) |
| [21:19] | lsipd | RW | 0x2 | LS 包间时间 (默认 3 bit times) |
| [18:14] | reserved | RO | 0x00 | 保留 |
| [13:10] | usbtrdim | RW | 0x9 | USB 2.0 转向时间 |
| [9] | xcvrdly | RW | 0x0 | 收发器延迟使能 |
| [8] | reserved | RO | 0x0 | 保留 |
| [7] | reserved | RO | 0x0 | 保留 |
| [6] | suspendusb20 | RW | 0x0 | 挂起 USB2.0 PHY (关键!) |
| [5] | reserved | RO | 0x0 | 保留 |
| [4] | ulpi_utmi_sel | RO | 0x0 | ULPI/UTMI+ 选择 (0=UTMI+) |
| [3] | phyif | RW | 0x0 | UTMI+ 接口位宽 (0=8bit, 1=16bit) |
| [2:0] | tout_cal | RW | 0x0 | HS/FS 超时校准 |
physoftrst (bit[31]) - UTMI PHY 软复位:
- 导致 usb2phy_reset 信号被断言以复位 UTMI PHY
- 不适用于 ULPI
- 核心在以下复位时自动写入此寄存器:
- vcc_reset_n
- USBCMD.HCRST
- DCTL.SoftReset
- GCTL.SoftReset
u2_freeclk_exists (bit[30]) - USB2.0 自由运行时钟:
- 指定 USB 2.0 PHY 是否提供自由运行的 PHY 时钟
- 如果为 1,PHY 时钟必须连接到 utmi_clk[0] 输入
- 注意: 当核心配置为仅设备模式时,不要将此位设置为 1
suspendusb20 (bit[6]) - 挂起 USB2.0 PHY:
- ⚠️ 关键: 如果设置为 1,应用程序必须在 power-on reset 后清除此位
- ⚠️ 关键: 核心初始化完成后,应用程序需要将此位设置为 1
- 在 host mode,复位时此位被设置为 1,软件可以覆盖
- 在 device mode,在 2.0 速度下操作时,发出任何设备端点命令之前必须禁用此位,命令完成后启用
ulpi_utmi_sel (bit[4]) - ULPI 或 UTMI+ 选择:
1'b0: UTMI+ Interface1'b1: ULPI Interface
phyif (bit[3]) - UTMI+ 接口位宽:
1'b0: 8 bits1'b1: 16 bits
GUSB3PIPECTL(n) - USB3 PHY PIPE 控制寄存器 (0xC2C0)
复位值: 0x00000000
| 位 | 名称 | 访问 | 复位值 | 说明 |
|---|---|---|---|---|
| [31] | PHYSoftRst | RW | 0x0 | USB3 PHY 软复位 |
| [30] | HstPrtCmpl | RW | 0x0 | 主机端口合规模式 |
| [29] | U2SSInactP3ok | RW | 0x0 | U2/SS.Inactive 时 PHY 电源状态 |
| [28] | DisRxDetP3 | RW | 0x0 | P3 中禁用接收器检测 |
| [27] | Ux_exit_in_Px | RW | 0x0 | U1/U2/U3 退出时 PHY 电源状态 |
| [26] | ping_enhancement_en | RW | 0x0 | Ping 增强使能 |
| [25] | u1u2exitfail_to_recov | RW | 0x0 | U1U2 退出失败转恢复 |
| [24] | request_p1p2p3 | RW | 0x0 | 始终请求 P1/P2/P3 |
| [23] | StartRxDetU3RxDet | RW | 0x0 | U3/Rx.Detect 中启动接收器检测 |
| [22] | DisRxDetU3RxDet | RW | 0x0 | 禁用 U3/Rx.Detect 接收器检测 |
| [21:19] | DelayP1P2P3 | RW | 0x0 | 延迟 P1P2P3 |
| [18] | DELAYP1TRANS | RW | 0x0 | 延迟 P1 转换 |
| [17] | SUSPENDENABLE | RW | 0x0 | 挂起 USB3.0 PHY |
| [16:15] | DATWIDTH | RO | 0x0 | 数据总线宽度 (32/16/8 bits) |
| [14:0] | reserved | - | - | 保留 |
PHYSoftRst (bit[31]) - USB3 PHY 软复位:
- 设置为 1 后,软件需要清除此位
HstPrtCmpl (bit[30]) - 主机端口合规模式:
- 默认必须设置为
1'b0 - 合规实验室测试中使用
- 合规模式进入序列:
- 断开所有插入的设备
- 执行 USBCMD.HCRST 或 power-on-chip reset
- 设置 PORTSC.PP=0
- 设置 GUSB3PIPECTL.HstPrtCmpl=1
SUSPENDENABLE (bit[17]) - 挂起 USB3.0 PHY:
- ⚠️ 关键: 应用程序需要在核心初始化完成后将此位设置为 1
- 当设置此位且挂起条件有效时,USB 3.0 PHY 进入挂起模式
DATWIDTH (bit[16:15]) - 数据总线宽度:
2'b00: 32 bits2'b01: 16 bits2'b10: 8 bits- 复位后一个时钟,这些位接收 pipe3_DataBusWidth 上的值
TRM 中的关键初始化要求
1. GUSB2PHYCFG suspendusb20 位处理
TRM 明确说明 (bit[6]):
If it is set to 1, then the application must clear this bit after power-on reset. Application needs to set it to 1 after the core initialization completes.
正确的初始化序列:
1. Power-on reset 后:suspendusb20 = 1 (复位默认值)
2. 应用程序清除:suspendusb20 = 0 (使能 PHY)
3. 核心初始化期间:PHY 正常工作
4. 初始化完成后:suspendusb20 = 1 (进入挂起模式)
2. GUSB3PIPECTL SUSPENDENABLE 位处理
TRM 明确说明 (bit[17]):
Application needs to set it to '1' after the core initialization is completed.
正确的初始化序列:
1. 核心初始化期间:SUSPENDENABLE = 0 (PHY 不挂起)
2. 初始化完成后:SUSPENDENABLE = 1 (允许挂起)
3. xHCI HCRST 的作用
根据 TRM Fig. 14-4 和合规模式说明:
- Perform USBCMD.HCRST or power-on-chip reset.
HCRST 执行的功能:
- 复位主机控制器
- 使能 PHY 接口
- 清除端口状态
- 可能使能 GUSB2PHYCFG 和 GUSB3PIPECTL 的访问
为什么 PHY 寄存器不可写?
根据 TRM 分析,可能的原因:
-
suspendusb20 位未清除
- 如果此位为 1,PHY 处于挂起状态,寄存器可能不可写
- 解决方案: 在初始化开始时清除 bit[6]
-
xHCI HCRST 未执行
- HCRST 使能 PHY 接口访问
- 解决方案: 确保在访问 PHY 寄存器之前执行 HCRST
-
PHY 接口时钟未运行
- UTMI 480MHz 时钟必须正常工作
- 解决方案: 检查 USB2 PHY 是否真正启动并输出时钟
-
GCTL 核心软复位未解除
- 如果 coresoftreset (bit[11]) 为 1,寄存器可能不可访问
- 解决方案: 确保此位为 0
建议的初始化序列 (基于 TRM)
// 1. 使能时钟和电源
pm.power_domain_on(31)?;
cru.enable_dwc3_controller_clocks();
// 2. 解除 DWC3 复位
cru.deassert_dwc3_reset();
// 3. 初始化 USB2 PHY (启动 UTMI 480MHz)
usb2_phy.init_minimal();
// 4. 初始化 USBDP PHY
usbdp_phy.init()?;
// 5. 验证 SNPSID
dwc_regs.verify_snpsid();
// 6. 清除 GUSB2PHYCFG.suspendusb20 (⚠️ 关键!)
dwc_regs.clear_suspend_usb20();
// 7. 配置 GCTL (设置 HOST 模式)
dwc_regs.setup_gctl();
// 8. 执行 xHCI HCRST (⚠️ 关键! 使能 PHY 接口)
xhci.init().await?;
// 9. 配置 PHY 寄存器 (此时应该可写)
dwc_regs.setup_phy()?;
// 10. 恢复 GUSB2PHYCFG.suspendusb20 (可选)
dwc_regs.set_suspend_usb20();
更新日志
| 日期 | 更新内容 |
|---|---|
| 2025-12-30 | 初始版本,记录所有寄存器基地址、电源、时钟、复位依赖 |
| 2025-12-30 | 添加完整的 PHY 初始化顺序和时钟链分析 |
| 2025-12-30 | 添加当前问题描述和诊断步骤 |
| 2025-12-30 | 添加 DWC3 寄存器详细说明 (基于 TRM Chapter 13) |
| 2025-12-30 | 添加关键发现: suspendusb20 必须在初始化开始时清除 |
| 2025-12-30 | 添加建议的 TRM 初始化序列 |