Rockchip linux USB 驱动开发

Linux USB 驱动架构

Linux USB 协议栈是一个分层的架构,如下图 5-1 所示,左边是 USB Device 驱动,右边是 USB Host 驱动,最底层是 Rockchip 系列芯片不同 USB 控制器和 PHY 的驱动。

Linux USB 驱动架构

USB PHY 驱动开发

USB 2.0 PHY 驱动开发

Rockchip 系列芯片,主要使用两种 USB 2.0 PHY IP:Innosilicon IP 和 Synopsis IP。这两种 IP 的硬件设计不同,所以需要独立的 USB PHY 驱动。同时,使用同一种 USB 2.0 PHY IP 的系列芯片,复用同一个USB 2.0 PHY 驱动,而不是每种芯片都有一个专用的 USB 2.0 PHY 驱动。

  1. USB 2.0 PHY 驱动代码路径

Innosilicon USB 2.0 PHY 驱动代码

drivers/phy/phy-rockchip-inno-usb2.c

Synopsis USB 2.0 PHY 驱动代码 (用于 RK3188/RK3288)

drivers/phy/rockchip/phy-rockchip-usb.c

考虑到目前大部分的 Rockchip SoC (除了 RK3188/RK3288外) 都使用 Innosilicon IP,所以本章节重点介

绍 Innosilicon IP。

  1. Innosilicon USB 2.0 PHY IP 特性

完全符合 USB 2.0 规范

支持 480Mbps/12Mbps/1.5Mbps 数据传输

支持 USB 2.0 规范定义的所有测试模式

支持 1 个 PHY 1 个 port,或者 1 个 PHY 2 个 ports (1 个 OTG port 和 1 个 Host port)

OTG Port 支持 Device/Host 两种模式

支持 Battery Charge 1.2 规范

  1. USB 2.0 PHY 重要结构体

USB 2.0 PHY 驱动中,有一个重要的结构体 rockchip_usb2phy_cfg,主要作用是操作 USB PHY 相关的寄存器,在添加一个新芯片的 Innosilicon USB 2.0 PHY 的支持时,主要的工作就是增加芯片对应的rkxxxx_phy_cfgs 结构体。rockchip_usb2phy_cfg 结构体成员说明如下:

reg:USB PHY 位于 GRF 模块中的偏移地址,该地址与 DTS USB 2.0 PHY 对应的 reg 地址应一致,

作用是匹配 DTS PHY 和 驱动中的 PHY 的配置;

num_ports:定义 USB PHY 支持的 port 数量。比如,支持 OTG port 和 Host port,则 num_ports 为

2;phy_tuning:用于 USB PHY 信号的调整,比如:提高预加重,提高信号幅值等;

clkout_ctl:控制 USB PHY 480MHz 的输出时钟;

port_cfgs:USB PHY port 的寄存器配置;

chg_det:充电检测相关的寄存器配置;

  1. USB 2.0 PHY 状态机

USB 2.0 PHY 有三个 work,分别用于处理不同的状态机:

rockchip_chg_detect_work:用于 OTG port Device mode 的充电检测功能;

rockchip_usb2phy_otg_sm_work:用于 OTG port 的连接状态检测,以及控制 PHY 进入/退出

suspend;rockchip_usb2phy_sm_work:用于 Host port 的连接状态检测,以及控制 PHY 进入/退出 suspend;驱动代码中,在关键的地方都有加了 dev_dbg log,可以方便查看设备连接和断开过程中的状态机轮转。

  1. USB 2.0 PHY 驱动开发实例

以 RK3399 USB 2.0 PHY 驱动开发为例。

RK3399 支持两个独立的 USB 2.0 PHY。并且,每个 PHY 都包含两个 port:OTG port 和 Host port。其中,OTG port 用于 USB 3.0 OTG controller 的USB2 部分,与 Type-C USB 3.0 PHY 组成完整的 Type-C 功

能。Host port 用于USB 2.0 Host 控制器。具体的 rk3399_phy_cfgs 结构体代码如下:

其中,port_cfgs 中的寄存器,主要用 PHY suspend mode 的控制、VBUS 电平状态的检测、OTG ID 电平

状态的检测、DP/DM 线上电平状态的检测等。每个成员的具体功能说明,请参考驱动中结构体成员的注

释。

static const struct rockchip_usb2phy_cfg rk3399_phy_cfgs[] = {

{

.reg = 0xe450,

.num_ports = 2,

.phy_tuning = rk3399_usb2phy_tuning,

.clkout_ctl = { 0xe450, 4, 4, 1, 0 },

.port_cfgs = {

[USB2PHY_PORT_OTG] = {

.phy_sus = { 0xe454, 8, 0, 0x052, 0x1d1 },

.bvalid_det_en = { 0xe3c0, 3, 3, 0, 1 },

.bvalid_det_st = { 0xe3e0, 3, 3, 0, 1 },

.bvalid_det_clr = { 0xe3d0, 3, 3, 0, 1 },

.bypass_dm_en = { 0xe450, 2, 2, 0, 1 },

.bypass_sel = { 0xe450, 3, 3, 0, 1 },

.idfall_det_en = { 0xe3c0, 5, 5, 0, 1 },

.idfall_det_st = { 0xe3e0, 5, 5, 0, 1 },

.idfall_det_clr = { 0xe3d0, 5, 5, 0, 1 },

.idrise_det_en = { 0xe3c0, 4, 4, 0, 1 },

.idrise_det_st = { 0xe3e0, 4, 4, 0, 1 },

.idrise_det_clr = { 0xe3d0, 4, 4, 0, 1 },

.ls_det_en = { 0xe3c0, 2, 2, 0, 1 },

.ls_det_st = { 0xe3e0, 2, 2, 0, 1 },

.ls_det_clr = { 0xe3d0, 2, 2, 0, 1 },

.utmi_avalid = { 0xe2ac, 7, 7, 0, 1 },

.utmi_bvalid = { 0xe2ac, 12, 12, 0, 1 },

.utmi_iddig = { 0xe2ac, 8, 8, 0, 1 },

.utmi_ls = { 0xe2ac, 14, 13, 0, 1 },

.vbus_det_en = { 0x449c, 15, 15, 1, 0 },

},

[USB2PHY_PORT_HOST] = {

.phy_sus = { 0xe458, 1, 0, 0x2, 0x1 },

.ls_det_en = { 0xe3c0, 6, 6, 0, 1 },

.ls_det_st = { 0xe3e0, 6, 6, 0, 1 },

.ls_det_clr = { 0xe3d0, 6, 6, 0, 1 },

.utmi_ls = { 0xe2ac, 22, 21, 0, 1 },

.utmi_hstdet = { 0xe2ac, 23, 23, 0, 1 }

}

},

.chg_det = {

.opmode = { 0xe454, 3, 0, 5, 1 },

.cp_det = { 0xe2ac, 2, 2, 0, 1 },

.dcp_det = { 0xe2ac, 1, 1, 0, 1 },

.dp_det = { 0xe2ac, 0, 0, 0, 1 },

.idm_sink_en = { 0xe450, 8, 8, 0, 1 },

.idp_sink_en = { 0xe450, 7, 7, 0, 1 },

.idp_src_en = { 0xe450, 9, 9, 0, 1 },

.rdm_pdwn_en = { 0xe450, 10, 10, 0, 1 },

.vdm_src_en = { 0xe450, 12, 12, 0, 1 },

  1. USB 2.0 PHY 调试接口

.vdp_src_en = { 0xe450, 11, 11, 0, 1 },

},

},

{

.reg = 0xe460,

.num_ports = 2,

.phy_tuning = rk3399_usb2phy_tuning,

.clkout_ctl = { 0xe460, 4, 4, 1, 0 },

.port_cfgs = {

[USB2PHY_PORT_OTG] = {

.phy_sus = { 0xe464, 8, 0, 0x052, 0x1d1 },

.bvalid_det_en = { 0xe3c0, 8, 8, 0, 1 },

.bvalid_det_st = { 0xe3e0, 8, 8, 0, 1 },

.bvalid_det_clr = { 0xe3d0, 8, 8, 0, 1 },

.idfall_det_en = { 0xe3c0, 10, 10, 0, 1 },

.idfall_det_st = { 0xe3e0, 10, 10, 0, 1 },

.idfall_det_clr = { 0xe3d0, 10, 10, 0, 1 },

.idrise_det_en = { 0xe3c0, 9, 9, 0, 1 },

.idrise_det_st = { 0xe3e0, 9, 9, 0, 1 },

.idrise_det_clr = { 0xe3d0, 9, 9, 0, 1 },

.ls_det_en = { 0xe3c0, 7, 7, 0, 1 },

.ls_det_st = { 0xe3e0, 7, 7, 0, 1 },

.ls_det_clr = { 0xe3d0, 7, 7, 0, 1 },

.utmi_avalid = { 0xe2ac, 10, 10, 0, 1 },

.utmi_bvalid = { 0xe2ac, 16, 16, 0, 1 },

.utmi_iddig = { 0xe2ac, 11, 11, 0, 1 },

.utmi_ls = { 0xe2ac, 18, 17, 0, 1 },

.vbus_det_en = { 0x451c, 15, 15, 1, 0 },

},

[USB2PHY_PORT_HOST] = {

.phy_sus = { 0xe468, 1, 0, 0x2, 0x1 },

.ls_det_en = { 0xe3c0, 11, 11, 0, 1 },

.ls_det_st = { 0xe3e0, 11, 11, 0, 1 },

.ls_det_clr = { 0xe3d0, 11, 11, 0, 1 },

.utmi_ls = { 0xe2ac, 26, 25, 0, 1 },

.utmi_hstdet = { 0xe2ac, 27, 27, 0, 1 }

}

},

.chg_det = {

.opmode = { 0xe464, 3, 0, 5, 1 },

.cp_det = { 0xe2ac, 5, 5, 0, 1 },

.dcp_det = { 0xe2ac, 4, 4, 0, 1 },

.dp_det = { 0xe2ac, 3, 3, 0, 1 },

.idm_sink_en = { 0xe460, 8, 8, 0, 1 },

.idp_sink_en = { 0xe460, 7, 7, 0, 1 },

.idp_src_en = { 0xe460, 9, 9, 0, 1 },

.rdm_pdwn_en = { 0xe460, 10, 10, 0, 1 },

.vdm_src_en = { 0xe460, 12, 12, 0, 1 },

.vdp_src_en = { 0xe460, 11, 11, 0, 1 },

},

},

{ /* sentinel */ }

};

"otg_mode" 节点用于软件强制切换 OTG Device/Host 模式,并且不受 OTG ID 电平状态的影响。

举例:

强制切换为 Host 模式

echo host > /sys/devices/platform/[u2phy dev name]/otg_mode

强制切换为 Device 模式

echo peripheral > /sys/devices/platform/[u2phy dev name]/otg_mode

强制切换为 OTG 模式

echo otg > /sys/devices/platform/[u2phy dev name]/otg_mode

同时,该节点仍然兼容 Linux-3.10 及更早以前的旧命令,即:

强制切换为 Host 模式

echo 1 > /sys/devices/platform/[u2phy dev name]/otg_mode

强制切换为 Device 模式

echo 2 > /sys/devices/platform/[u2phy dev name]/otg_mode

强制切换为 OTG 模式

echo 0 > /sys/devices/platform/[u2phy dev name]/otg_mode

Note:

  1. USB 2.0 PHY 完整路径中 [u2phy dev name] 需要修改为芯片对应的具体 PHY 节点名称。

  2. RV1126/RV1109 USB OTG 建议按照如下方法切换模式,可以提高各种应用场景(如:保持 USB 连

接到 PC,然后使用命令交替切换Host/Device模式)的切换稳定性。

RV1126/RV1109 USB OTG 强制切换为 Host 模式:

echo disconnect > /sys/class/udc/ffd00000.dwc3/soft_connect (断开 usb device 的连

接)

echo host > /sys/devices/platform/ff4c0000.usb2-phy/otg_mode

RV1126/RV1109 USB OTG 强制切换为 Device 模式:

echo peripheral > /sys/devices/platform/ff4c0000.usb2-phy/otg_mode

echo connect > /sys/class/udc/ffd00000.dwc3/soft_connect (使能 usb device 的连接)

RV1126/RV1109 USB OTG 强制切换为 OTG 模式:

echo otg > /sys/devices/platform/ff4c0000.usb2-phy/otg_mode

echo connect > /sys/class/udc/ffd00000.dwc3/soft_connect (使能 usb device 的连接)

USB 3.0 PHY 驱动开发

Rockchip 系列芯片,主要使用三种 USB 3.0 PHY IP:Type-C PHY IP,Innosilicon USB 3.0 PHY IP 和

Innosilicon USB 3.0 CombPhy IP。这三种 IP 的硬件设计不同,所以需要独立的 USB PHY 驱动。

/sys/devices/platform/[u2phy dev name] # ls

driver extcon of_node phy subsystem

driver_override modalias otg_mode power uevent

需要注意的是,这三种 USB 3.0 PHY IP 都只支持 SuperSpeed,所以要与 USB 2.0 PHY (支持

HighSpeed/FullSpeed/LowSpeed) 一起配合使用,才能完整支持 USB 3.0 协议。

下面分别对这三种不同的 USB 3.0 PHY IP 驱动进行简要的描述。

  1. Type-C PHY 驱动开发

Type-C USB 3.0 PHY 驱动代码路径

drivers/phy/rockchip/phy-rockchip-typec.c

Type-C USB 3.0 PHY 驱动实例

以 RK3399 Type-C PHY 为例。

RK3399 Type-C PHY 是一个CombPhy,包含一个 USB 3.0 SuperSpeed PHY 和一个 DisplayPort Transmit

PHY。Type-C PHY 的特性,请参考USB 3.0 Type-C PHY

在 Type-C PHY 驱动的 probe 函数中,会分别创建 "dp-port" 的 rockchip_dp_phy_ops 和 "usb3-port" 的

rockchip_usb3_phy_ops,也即 USB 3.0 PHY 和 DP PHY 的操作函数 (如:power_on 和 power_off) 是独立

的,互不影响。Type-C PHY 驱动可以支持如下 4 种工作模式:

USB 3.0 only:只工作在 USB 3.0 模式,比如连接 Type-C to Type-A USB 3.0 的转接线;

DP only:只工作在 DP 模式,比如连接 DP 线缆;

USB 3.0 + DP 2 lanes:同时支持 USB 3.0 和 DP 2 lanes 工作,比如连接 Type-C dongle;

USB 2.0 + DP 4 lanes:同时支持 USB 2.0 和 DP 4 lanes 工作,比如连接 Type-C VR 头盔;

为了支持上述 4 种工作模式,Type-C PHY 需要结合 CC 芯片 (推荐使用 FUSB302 芯片) 来检测插入的

Type-C 线缆的类型。CC 芯片使用 extcon 通知机制发消息给 Type-C PHY。

重要函数:

rockchip_usb3_phy_power_on():获取 PHY 的工作模式,并初始化 PHY;

rockchip_usb3_phy_power_off():反初始化 PHY,设置 PHY 处于 reset 状态,并关闭时钟;

tcphy_cfg_usb3_to_usb2_only():关闭 USB 3.0 逻辑模块,强制工作在 USB 2.0 only 模式;

tcphy_cfg_usb3_pll():配置 USB 3.0 相关的 PLL;

  1. Innosilicon USB 3.0 PHY 驱动开发

Innosilicon USB 3.0 PHY 驱动代码路径

drivers/phy/rockchip/phy-rockchip-inno-usb3.c

Innosilicon USB 3.0 PHY 驱动实例

以 RK3328 USB 3.0 PHY 为例。

RK33228 USB 3.0 PHY 由 USB 3.0 PHY 和 USB 2.0 PHY 两部分组成。

Innosilicon USB 3.0 PHY 硬件特性:

支持 5.0Gb/s 传输速率

支持 8位、16位或32位并行接口传输和接收USB超高速数据

允许集成高速组件 (USB 2.0 PHY) 作为独立的功能模块

从USB超高速总线上的串行流恢复数据和时钟

支持符合 USB 3.0 协议电气规范的 compliance test pattern

支持8b/10b 编解码及错误指示

无法检测外设断开的状态

Innosilicon USB 3.0 PHY 驱动有两个特别之处:

同时实现了 USB 2.0 PHY 和 USB 3.0 PHY 的操作函数(虽然从硬件原理上,这两个 PHY 是独立

的),这与其他 USB 3.0 PHY 不同。驱动中,使用 "U3PHY_TYPE_UTMI" 和

"U3PHY_TYPE_PIPE" 分别作为 USB 2.0 PHY 和 USB 3.0 PHY的索引,具体请参考驱动代码中的如

下函数:

rockchip_u3phy_port_init():对 USB 3.0 的 USB 2.0 port 和 USB 3.0 port 作初始化;

rockchip_u3phy_power_on():打开时钟,并且配置 USB 2.0 PHY 为 Normal mode,配置 USB 3.0

PHY 进入 P0 state;

rockchip_u3phy_power_off():配置 USB 2.0 PHY 为 Suspend mode,配置 USB 3.0 PHY 为 进入 P3

state,并且关闭时钟,以节省 PHY 的整体功耗。

为了解决 USB 3.0 PHY 无法检测外设断开的状态,增加了特殊的函数,这与其他 USB 3.0 PHY 不

同。具体请参考驱动中的如下函数:

rockchip_u3phy_on_disconnect():当 USB HUB core 驱动通过检测 linkstate 状态的变化,判断外设已

经断开时,会通过 PHY 注册的 notifier,调用该 disconnect 函数,从而完成soft disconnect的一系列

操作;

rockchip_u3phy_on_shutdown():该函数提供给 DWC3 控制器驱动调用,作用是,在 soft disconnect

流程中,对 USB3 PHY 进行复位操作;

rockchip_u3phy_on_init():该函数提供给 DWC3 控制器驱动调用,作用是,在 soft disconnect 流程

的最后,释放 USB 3.0 PHY 的复位信号;

Innosilicon USB 3.0 PHY 支持通过软件命令,强制 PHY 只工作于 USB 2.0 only的模式:

配置 USB 3.0 PHY 为 USB 2.0 only 模式的命令

echo u2 > /sys/kernel/debug/[phy name]/u3phy_mode

配置 USB 3.0 PHY 同时支持 USB 3.0/2.0 模式的命令 (驱动初始化后,默认支持)

echo u3 > /sys/kernel/debug/[phy name]/u3phy_mode

Note: [phy name] 需要修改为芯片对应的具体 PHY 节点名。

  1. Innosilicon USB 3.0 CombPhy 驱动开发

Innosilicon USB 3.0 CombPhy 驱动代码路径

drivers/phy/rockchip/phy-rockchip-inno-combphy.c

Innosilicon USB 3.0 CombPhy 驱动实例

以 RK1808 USB 3.0 CombPhy 为例。

RK1808 USB 3.0 CombPhy 包含了 USB 3.0 SuperSpeed PHY 和 PCIe PHY,并且 USB 3.0 PHY 和 PCIe

PHY无法同时工作。PHY 驱动中,会注册 PHY 的接口函数 rockchip_combphy_xlate(),提供给 USB 3.0控制器驱动和 PCIe 驱动调用,以配置 USB 3.0 CombPHY 工作在控制器要求的类型。

如果要使用 USB 3.0,则配置 USB 3.0 控制器 DTS 的 phys 属性为

如果要使用 PCIe,则配置 PCIe 控制器 DTS 的 phys 属性为

phys = <&u2phy_otg>, <&combphy PHY_TYPE_USB3>;

phy-names = "usb2-phy", "usb3-phy";RK1808 USB 3.0 CombPhy 的 USB 3.0 SuperSpeed PHY 模块,只支持 SuperSpeed,它需要配合 USB 2.0PHY OTG port (支持 HighSpeed/FullSpeed/LowSpeed) 一起使用,才能完整支持 USB 3.0/2.0/1.1/1.0 协议。Innosilicon USB 3.0 CombPhy PHY 硬件特性:

支持 5.0Gb/s 传输速率支持 8位、16位或32位并行接口传输和接收USB超高速数据

允许集成高速组件 (USB 2.0 PHY) 作为独立的功能模块

从USB超高速总线上的串行流恢复数据和时钟

支持符合 USB 3.0 协议电气规范的 compliance test pattern

支持8b/10b 编解码及错误指示Innosilicon USB 3.0 CombPhy PHY 驱动代码中,USB 3.0 PHY 和 PCIe PHY 复用 phy_ops 函数:rockchip_combphy_init():打开 PHY 参考时钟,设置 PHY 类型,初始化 PHY 寄存器;rockchip_combphy_exit():关闭 PHY 参考时钟;

rockchip_combphy_power_on():power on USB 3.0 PHY 的逻辑模块,并配置 PHY 进入 P0 state;

rockchip_combphy_power_off():power off USB 3.0 PHY 的逻辑模块,并配置 PHY 进入 P3 state;

Innosilicon USB 3.0 CombPhy PHY 支持通过软件命令,强制 PHY 只工作于 USB 2.0 only的模式:

Note:

[u3phy dev name] 和 [u2phy dev name] 需要修改为芯片对应的具体 PHY 节点名称;

USB 的 default mode,由 DWC3 控制器 DTS 中的属性 "dr_mode" 决定;

在切换 USB 3.0 和 USB 2.0 only 工作模式时,需要设置 otg_mode 节点的原因是为了重新初始化

xHCI 控制器,否则切换 PHY 的工作模式,会导致控制器工作异常;

相关推荐
iiiiiankor1 小时前
C/C++内存管理 | new的机制 | 重载自己的operator new
java·c语言·c++
小辛学西嘎嘎1 小时前
C/C++精品项目之图床共享云存储(3):网络缓冲区类和main
c语言·开发语言·c++
Biomamba生信基地1 小时前
Linux也有百度云喔~
linux·运维·服务器·百度云
无敌最俊朗@1 小时前
stm32学习之路——八种GPIO口工作模式
c语言·stm32·单片机·学习
new_abc1 小时前
Ubuntu 22.04 ftp搭建
linux·运维·ubuntu
flying robot2 小时前
RPM的使用
linux
2301_799084672 小时前
超全排序C语言实现
c语言·数据结构·算法·排序算法
腾科张老师4 小时前
为什么要使用Ansible实现Linux管理自动化?
linux·网络·学习·自动化·ansible
7yewh5 小时前
嵌入式硬件杂谈(一)-推挽 开漏 高阻态 上拉电阻
驱动开发·stm32·嵌入式硬件·mcu·物联网·硬件架构·pcb工艺