USB 概念
USB(Universal Serial Bus) 通用串行总线,目标是实现即插即用
USB 和其他接口的区别如下图
USB Host Controller Interface
USB Connector Type
RK USB 控制器
Rockchip SOC 通常内置多个 USB 控制器,不同控制器互相独立。
RK3399 2 个 USB 2.0 HOST(EHCI/OHCI), 1 个 USB HSIC(EHCI),2 个 USB 3.0/2.0 OTG(DWC3/xHCI)
HSIC—USB High Speed Inter-Chip 是一个两线源同步的串行接口,使用240MHz双倍数据速率产生480MHz的高速速率,和传统的USB电缆连接拓扑结构的主机完全兼容, 常用在3G 和 4G模块中。
USB 2.0 HOST
USB 2.0 Host 硬件电路有两种:USB 2.0 Host 和 USB 2.0 HSIC。虽然 USB 2.0 Host 和 HSIC 都使用 EHCI 控制器,但使用的 USB 2.0 PHY 不同,所以对应的硬件电路也不同。
硬件电路
FE1.1S是用于USB2.0 HUB的主控IC, 提供4个USB Port
USB 2.0 OTG
USB 3.0 OTG
USB 2.0 PHY
USB 2.0 PHY 支持 1 个 port 和 2 个 port 两种设计,如下图 1-4 是支持 2 个 port 的框图。
- Host Port:通过 UTMI+ 连接到 USB 2.0 Host 控制器;
- OTG Port:通过 UTMI+ 连接 USB 3.0 或者 USB 2.0 OTG 控制器的 USB 2.0 逻辑模块;
USB 3.0 Type-C PHY
内核配置
kernel/arch/arm64/configs/rockchip_defconfig
# USB PHY CONFIG
CONFIG_PHY_ROCKCHIP_USB=y
CONFIG_PHY_ROCKCHIP_INNO_USB2=y
CONFIG_PHY_ROCKCHIP_INNO_USB3=y
CONFIG_PHY_ROCKCHIP_TYPEC=y
# USB Host CONFIG
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_OHCI_HCD=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
# USB OTG CONFIG
CONFIG_USB_DWC3=y
CONFIG_USB_DWC2=y
# USB Gadget
CONFIG_USB_GADGET=y
CONFIG_USB_GADGET_DEBUG_FILES=y
CONFIG_USB_GADGET_VBUS_DRAW=500
CONFIG_USB_CONFIGFS=y
CONFIG_USB_CONFIGFS_ACM=y
CONFIG_USB_CONFIGFS_RNDIS=y
CONFIG_USB_CONFIGFS_MASS_STORAGE=y
CONFIG_USB_CONFIGFS_F_FS=y
CONFIG_USB_CONFIGFS_F_MTP=y
CONFIG_USB_CONFIGFS_F_PTP=y
CONFIG_USB_CONFIGFS_F_ACC=y
CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y
CONFIG_USB_CONFIGFS_UEVENT=y
CONFIG_USB_CONFIGFS_F_MIDI=y
# Others
USB DTS 配置说明
USB PHY 分为 USB 2.0 PHY 和 USB 3.0 PHY 两种。这两种 PHY 是互相独立的,并且特性差异比较大,所以需要分别配置 DTS。
Note:RK3399 芯片的 USB PHY DTS 配置比较灵活且复杂,请参考文档:《Rockchip_RK3399_Developer_Guide_USB_DTS_CN》
USB 2.0 PHY DTS
arch/arm64/boot/dts/rockchip/rk3399.dtsi
grf: syscon@ff770000 {
compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
reg = <0x0 0xff770000 0x0 0x10000>;
#address-cells = <1>;
#size-cells = <1>;
u2phy0: usb2-phy@e450 {
compatible = "rockchip,rk3399-usb2phy";
reg = <0xe450 0x10>;
clocks = <&cru SCLK_USB2PHY0_REF>;
clock-names = "phyclk";
#clock-cells = <0>;
clock-output-names = "clk_usbphy0_480m";
power-domains = <&power RK3399_PD_PERIHP>;
status = "disabled";
u2phy0_otg: otg-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH 0>,
<GIC_SPI 106 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "otg-bvalid", "otg-id",
"linestate";
status = "disabled";
};
u2phy0_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
status = "disabled";
};
};
}
对于 Host port 和 OTG port Host 模式,需要为 USB 外设提供 5V 供电电源,所以我们要在 DTS 中配置 USB VBUS 5V
RK3399 USB 2.0 Host VBUS 的控制方式是: GPIO 拉高,则使能 VBUS 5V 输出,GPIO 拉低,则关闭 VBUS 5V 输出。DTS 中使用 regulator 的方式,来配置 GPIO。 其中,属性 “regulator-always-on” 表示,系统启动后,就拉高 GPIO 以使能 VBUS 5V 输出,直到系统关机。
arch/arm64/boot/dts/rockchip/rk3399-evb.dtsi
vcc5v0_host: vcc5v0-host-regulator {
compatible = "regulator-fixed";
enable-active-high;
gpio = <&gpio4 25 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&host_vbus_drv>;
regulator-name = "vcc5v0_host";
regulator-always-on;
};
usb2 {
host_vbus_drv: host-vbus-drv {
rockchip,pins =
<4 25 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
&u2phy0 {
status = "okay";
//extcon = <&fusb0>;
vbus-5v-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; /* Vbus GPIO 配置 */
u2phy0_otg: otg-port {
status = "okay";
};
u2phy0_host: host-port {
phy-supply = <&vcc5v0_host>;
status = "okay";
};
};
&u2phy1 {
status = "okay";
//extcon = <&fusb1>;
u2phy1_otg: otg-port {
status = "okay";
};
u2phy1_host: host-port {
phy-supply = <&vcc5v0_host>;
status = "okay";
};
};
USB 3.0 PHY DTS
arch/arm64/boot/dts/rockchip/rk3399.dtsi
// type-c 0
usbdrd3_0: usb@fe800000 {
compatible = "rockchip,rk3399-dwc3";
clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
<&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_GRF>;
clock-names = "ref_clk", "suspend_clk",
"bus_clk", "grf_clk";
power-domains = <&power RK3399_PD_USB3>;
resets = <&cru SRST_A_USB3_OTG0>;
reset-names = "usb3-otg";
#address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled";
usbdrd_dwc3_0: dwc3@fe800000 {
compatible = "snps,dwc3";
reg = <0x0 0xfe800000 0x0 0x100000>;
interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH 0>;
dr_mode = "otg";
phys = <&u2phy0_otg>, <&tcphy0_usb3>;
phy-names = "usb2-phy", "usb3-phy";
phy_type = "utmi_wide";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis_u2_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,tx-ipgap-linecheck-dis-quirk;
snps,xhci-slow-suspend-quirk;
snps,xhci-trb-ent-quirk;
snps,usb3-warm-reset-on-resume-quirk;
status = "disabled";
};
};
// type-c 1
usbdrd3_1: usb@fe900000 {
compatible = "rockchip,rk3399-dwc3";
clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
<&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_GRF>;
clock-names = "ref_clk", "suspend_clk",
"bus_clk", "grf_clk";
power-domains = <&power RK3399_PD_USB3>;
resets = <&cru SRST_A_USB3_OTG1>;
reset-names = "usb3-otg";
#address-cells = <2>;
#size-cells = <2>;
ranges;
status = "disabled";
usbdrd_dwc3_1: dwc3@fe900000 {
compatible = "snps,dwc3";
reg = <0x0 0xfe900000 0x0 0x100000>;
interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH 0>;
dr_mode = "host";
phys = <&u2phy1_otg>, <&tcphy1_usb3>;
phy-names = "usb2-phy", "usb3-phy";
phy_type = "utmi_wide";
snps,dis_enblslpm_quirk;
snps,dis-u2-freeclk-exists-quirk;
snps,dis_u2_susphy_quirk;
snps,dis-del-phy-power-chg-quirk;
snps,tx-ipgap-linecheck-dis-quirk;
snps,xhci-slow-suspend-quirk;
snps,xhci-trb-ent-quirk;
snps,usb3-warm-reset-on-resume-quirk;
status = "disabled";
};
};
// type-c 0
tcphy0: phy@ff7c0000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff7c0000 0x0 0x40000>;
rockchip,grf = <&grf>;
#phy-cells = <1>;
clocks = <&cru SCLK_UPHY0_TCPDCORE>,
<&cru SCLK_UPHY0_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY0_TCPDCORE>;
assigned-clock-rates = <50000000>;
power-domains = <&power RK3399_PD_TCPD0>;
resets = <&cru SRST_UPHY0>,
<&cru SRST_UPHY0_PIPE_L00>,
<&cru SRST_P_UPHY0_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe580 0 16>;
rockchip,usb3tousb2-en = <0xe580 3 19>;
rockchip,usb3-host-disable = <0x2434 0 16>;
rockchip,usb3-host-port = <0x2434 12 28>;
rockchip,external-psm = <0xe588 14 30>;
rockchip,pipe-status = <0xe5c0 0 0>;
rockchip,uphy-dp-sel = <0x6268 19 19>;
status = "disabled";
tcphy0_dp: dp-port {
#phy-cells = <0>;
};
tcphy0_usb3: usb3-port {
#phy-cells = <0>;
};
};
//type-c 1
tcphy1: phy@ff800000 {
compatible = "rockchip,rk3399-typec-phy";
reg = <0x0 0xff800000 0x0 0x40000>;
rockchip,grf = <&grf>;
#phy-cells = <1>;
clocks = <&cru SCLK_UPHY1_TCPDCORE>,
<&cru SCLK_UPHY1_TCPDPHY_REF>;
clock-names = "tcpdcore", "tcpdphy-ref";
assigned-clocks = <&cru SCLK_UPHY1_TCPDCORE>;
assigned-clock-rates = <50000000>;
power-domains = <&power RK3399_PD_TCPD1>;
resets = <&cru SRST_UPHY1>,
<&cru SRST_UPHY1_PIPE_L00>,
<&cru SRST_P_UPHY1_TCPHY>;
reset-names = "uphy", "uphy-pipe", "uphy-tcphy";
rockchip,typec-conn-dir = <0xe58c 0 16>;
rockchip,usb3tousb2-en = <0xe58c 3 19>;
rockchip,usb3-host-disable = <0x2444 0 16>;
rockchip,usb3-host-port = <0x2444 12 28>;
rockchip,external-psm = <0xe594 14 30>;
rockchip,pipe-status = <0xe5c0 16 16>;
rockchip,uphy-dp-sel = <0x6268 3 19>;
status = "disabled";
tcphy1_dp: dp-port {
#phy-cells = <0>;
};
tcphy1_usb3: usb3-port {
#phy-cells = <0>;
};
};
arch/arm64/boot/dts/rockchip/rk3399-evb.dtsi
&u2phy0 {
status = "okay";
//extcon = <&fusb0>;
vbus-5v-gpios = <&gpio1 3 GPIO_ACTIVE_HIGH>; /* Vbus GPIO 配置 */
u2phy0_otg: otg-port {
status = "okay";
};
u2phy0_host: host-port {
phy-supply = <&vcc5v0_host>;
status = "okay";
};
};
&usbdrd3_0 {
extcon = <&u2phy0>;
status = "okay";
};
&usbdrd_dwc3_0 {
dr_mode = "otg" ;
status = "okay" ;
};
&usbdrd3_1 {
status = "okay";
};
&usbdrd_dwc3_1 {
dr_mode = "host";
status = "okay";
};