RK平台基本能够通过dts配置就能实现USB功能。为了方便理解,我这里分三部分来介绍,包括:usb-phy,usb控制器,usb供电。
usb-phy负责最底层的信号转换,主要是硬件的差分信号转换成数字信号传给usb控制器,然后再送到主控,其框架大概如下:
以rk3399的host口为例,我们先找到原理图上对应的usb口:
由原理图我们可以知道,rk3399有两个usb-phy,分别是PHY0和PHY1,一个usb-phy有两个port口,分别是typec口和host口,我们要配置的是PHY0下面的host口,确定好这个之后我们就可以去dts找对应的配置节点。
在rk3399.dtsi中我们可以看到:
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_host: host-port {
#phy-cells = <0>;
interrupts = <GIC_SPI 27 IRQ_TYPE_LEVEL_HIGH 0>;
interrupt-names = "linestate";
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";
};
};
从以上代码看到,原理图上的PHY0刚好对应u2phy0,下面有两个port,分别是u2phy0_host和u2phy0_otg,我们关注的是u2phy0_host,因此,只要确认dts中有把u2phy0和u2phy0_host打开就可以了,如:
&u2phy0 {
status = "okay";
u2phy0_host: host-port {
status = "okay";
};
};
确定好usb-phy之后,我们可以直接去rk3399.dtsi就可以找到对应的usb控制器了,在rk3399.dtsi中,我们可以看到:
usb_host0_ehci: usb@fe380000 {
compatible = "generic-ehci";
reg = <0x0 0xfe380000 0x0 0x20000>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
┆<&cru SCLK_USBPHY0_480M_SRC>;
clock-names = "hclk_host0", "hclk_host0_arb", "usbphy0_480m";
phys = <&u2phy0_host>;
phy-names = "usb";
power-domains = <&power RK3399_PD_PERIHP>;
status = "disabled";
};
usb_host0_ohci: usb@fe3a0000 {
compatible = "generic-ohci";
reg = <0x0 0xfe3a0000 0x0 0x20000>;
interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH 0>;
clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
┆<&cru SCLK_USBPHY0_480M_SRC>;
clock-names = "hclk_host0", "hclk_host0_arb", "usbphy0_480m";
phys = <&u2phy0_host>;
phy-names = "usb";
power-domains = <&power RK3399_PD_PERIHP>;
status = "disabled";
};
以上两个节点里面都有这样一句:phys = <&u2phy0_host>;
,这表明这两个usb控制器都用了u2phy0_host这个usb-phy,这里我们需要了解一下,这两个usb控制器分别是ehci和ohci,ohci支持usb1.0和usb1.1,ehci支持usb2.0,为了同时支持usb1.0、usb1.1和usb2.0,就需要同时用到ehci和ohci,因此需要把这两个usb控制器都打开,如:
&usb_host0_ehci {
status = "okay";
};
&usb_host0_ohci {
status = "okay";
};
RK平台的usb供电主要是usb-phy和vbus,其他的供电在芯片内部,我们一般不需要操作。
从前面usb-phy的原理图我们可以看到有三路供电,分别是USB_AVDD_0V9,USB_AVDD_1V8,USB_AVDD_3V3,这三路供电将会影响usb的信号,一般由pmu提供的,只要硬件设计的时候跟官方的参考原理图一样,一般不需要修改,如果有自己修改,需要确认清楚,这三路供电的配置是这样的:
vcc0v9_soc: LDO_REG3 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <900000>;
regulator-max-microvolt = <900000>;
regulator-name = "vcc0v9_soc";
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <900000>;
};
};
vcc_1v8: LDO_REG2 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-name = "vcc_1v8";
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
vcc3v3_sys: DCDC_REG4 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-initial-mode = <0x2>;
regulator-name = "vcc3v3_sys";
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
注意:当usb出现识别异常的时候需要确认一下这三路供电,其纹波不能超过电压值的10%。
vbus供电就是给usb设备用的电源,从原理图可以看到:
由此我们可以知道,这个host口的vbus是由pmu供过来的,我们可以找到dts对应的节点:
vcc5v0_usb: SWITCH_REG1 {
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
regulator-name = "vcc5v0_usb";
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <5000000>;
};
};
RK平台这个供电是在usb-phy驱动里面控制的,因此我们把它配置到usb-phy节点中:
&u2phy0 {
status = "okay";
u2phy0_host: host-port {
phy-supply = <&vcc5v0_usb>;
status = "okay";
};
};
至此,一个usb host口的dts就配置完了,如果其他配置没问题(如defconfig)就能正常工作了。