Rockchip RK3399 - USB调试

----------------------------------------------------------------------------------------------------------------------------

开发板 :NanoPC-T4开发板eMMC16GBLPDDR34GB
显示屏 :15.6英寸HDMI接口显示屏u-boot2023.04linux6.3
----------------------------------------------------------------------------------------------------------------------------

一、设备树

设备树配置参考文档:

  • Documentation/devicetree/bindings/usb/generic-ehci.yaml; (USB控制器的通用属性配置说明)
  • Documentation/devicetree/bindings/usb/generic-ohci.yaml; (USB控制器的通用属性配置说明)
  • Documentation/devicetree/bindings/usb/generic-xhci.yaml; (USB控制器的通用属性配置说明)
  • Documentation/devicetree/bindings/usb/fcs,fusb302.yaml;
  • Documentation/devicetree/bindings/usb/rockchip,rk3399-dwc3.yaml;(适用于RK3399)
  • Documentation/devicetree/bindings/usb/usb-uhci.txt;
  • Documentation/devicetree/bindings/usb/usb-xhci.yaml;
  • Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt;
  • Documentation/devicetree/bindings/phy/rockchip,inno-usb2phy.yaml;
  • Documentation/devicetree/bindings/phy/rockchip-usb-phy.yaml;

1.1 USB2.0 Host Type-A

NanoPC-T4开发板支持两个USB2.0 Host Type-A接口,对应的USB控制器为USB2.0 HOST(EHCI&OHCI)、对应的USB PHYUSB2.0 HOST PHY

因此对应的设备树配置,包括USB2.0 HOST(EHCI&OHCI)控制器设备树配置和USB2.0 HOST PHY设备树配置。

1.1.1 控制器配置

(1) USB2.0 HOST0控制器设备节点usb_host0_ehciusb_host0_ohci定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

usb_host0_ehci: usb@fe380000 {
		compatible = "generic-ehci";
		reg = <0x0 0xfe380000 0x0 0x20000>;
		interrupts = ;
		clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
				 <&u2phy0>;
		phys = <&u2phy0_host>;
		phy-names = "usb";
		status = "disabled";
};

usb_host0_ohci: usb@fe3a0000 {
		compatible = "generic-ohci";
		reg = <0x0 0xfe3a0000 0x0 0x20000>;
		interrupts = ;
		clocks = <&cru HCLK_HOST0>, <&cru HCLK_HOST0_ARB>,
				 <&u2phy0>;
		phys = <&u2phy0_host>;
		phy-names = "usb";
		status = "disabled";
};

USB控制器设备节点中,通过phys属性关联对应的USB PHY

phys = <&u2phy0_host>;

这表明这两个USB控制器都用了u2phy0_host这个USB PHY.

这两个USB控制器就是我们之前介绍的是EHCIOHCIOHCI支持USB1.0USB1.1EHCI支持USB2.0

(2) USB2.0 HOST1控制器设备节点usb_host1_ehciusb_host1_ohci定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

usb_host1_ehci: usb@fe3c0000 {
		compatible = "generic-ehci";
		reg = <0x0 0xfe3c0000 0x0 0x20000>;
		interrupts = ;
		clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>,
				 <&u2phy1>;
		phys = <&u2phy1_host>;
		phy-names = "usb";
		status = "disabled";
};

usb_host1_ohci: usb@fe3e0000 {
		compatible = "generic-ohci";
		reg = <0x0 0xfe3e0000 0x0 0x20000>;
		interrupts = ;
		clocks = <&cru HCLK_HOST1>, <&cru HCLK_HOST1_ARB>,
				 <&u2phy1>;
		phys = <&u2phy1_host>;
		phy-names = "usb";
		status = "disabled";
};
1.1.2 PHY配置

(1) USB2.0 HOST PHY0设备节点u2phy0_host定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

u2phy0: usb2phy@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";
		status = "disabled";

		u2phy0_host: host-port {
				#phy-cells = <0>;
				interrupts = ;
				interrupt-names = "linestate";
				status = "disabled";
		};

		u2phy0_otg: otg-port {
				#phy-cells = <0>;
				interrupts = ,
							 ,
							 ;
				interrupt-names = "otg-bvalid", "otg-id",
								  "linestate";
				status = "disabled";
		};
};

(2) USB2.0 HOST PHY1设备节点u2phy1_host定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

u2phy1: usb2phy@e460 {
		compatible = "rockchip,rk3399-usb2phy";
		reg = <0xe460 0x10>;
		clocks = <&cru SCLK_USB2PHY1_REF>;
		clock-names = "phyclk";
		#clock-cells = <0>;
		clock-output-names = "clk_usbphy1_480m";
		status = "disabled";

		u2phy1_host: host-port {
				#phy-cells = <0>;
				interrupts = ;
				interrupt-names = "linestate";
				status = "disabled";
		};

		u2phy1_otg: otg-port {
				#phy-cells = <0>;
				interrupts = ,
							 ,
							 ;
				interrupt-names = "otg-bvalid", "otg-id",
								  "linestate";
				status = "disabled";
		};
};
1.1.3 电源配置

(1) USB2.0 PHY芯片三路电源依次为VCCA0V9_S3VCCA1V8_S3VCC3V3_S3

VCCA0V9_S3VCCA1V8_S3这两路由PMIC_SLEEP_H(连接RK3399GPIO1_A5/AP_PWROFF,这个应该是处理的睡眠引脚,处理器工作时电源有效)引脚控制的;

VCC3V3_S3RK808电源管理芯片第7号引脚VSWOUT提供,因此需要配置其电源输出为3.3V

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vcc3v3_s3设备节点;

&i2c0 {
    ...... 

    rk808: pmic@1b {
		......

        regulators {
           
		    ......
			
            vcc3v3_s3: SWITCH_REG1 {
                regulator-always-on;
                regulator-boot-on;
                regulator-name = "vcc3v3_s3";

                regulator-state-mem {
                    regulator-off-in-suspend;
                };
            };
			
			......

        };
    };
};

完整的rk808设备节点配置参考:rk808驱动配置。

(2) USB2.0 Host Type-A接口电源VCC5V0_HOST0RT9724GQW提供的,其输入端为VCC5V0_SYS

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vcc5v0_host

vcc5v0_sys: vcc5v0-sys {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v0_sys";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <5000000>;
		regulator-max-microvolt = <5000000>;
};

vcc5v0_host: vcc5v0-host-regulator {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v0_host";
		regulator-always-on;
		regulator-boot-on;	
		vin-supply = <&vcc5v0_sys>;
};
1.1.4 使能

下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件。

(1) 为了同时支持USB1.0USB1.1USB2.0,就需要同时用到EHCIOHCI,因此需要把这两个USB控制器都打开:

&usb_host0_ehci {
        status = "okay";
};

&usb_host0_ohci {
        status = "okay";
};

&usb_host1_ehci {
        status = "okay";
};

&usb_host1_ohci {
        status = "okay";
};

(2) 使能USB2.0 HOST PHY0,同时配置USB2.0 HOST PHY0 phy-supply属性,用于控制USB电源VBUS

&u2phy0 {
        status = "okay";
};

&u2phy0_host {
        phy-supply = <&vcc5v0_host>;
        status = "okay";
};

(3) 使能USB2.0 HOST PHY1,同时配置USB2.0 HOST PHY1 phy-supply属性,用于控制USB电源VBUS

&u2phy1 {
        status = "okay";
};

&u2phy1_host {
        phy-supply = <&vcc5v0_host>;
        status = "okay";
};

1.2 USB3.0 Host Type-A

NanoPC-T4开发板支持1个USB3.0 Host Type-A接口,对应的USB控制器为USB3.0/2.0 OTG1(DWC3/xHCI)、对应的USB PHYUSB3.0 Type-C PHY1USB2.0 OTG PHY1

因此对应的设备树配置,包括USB3.0/2.0 OTG1(DWC3/xHCI)控制器设备树配置和USB3.0 Type-C PHY1USB2.0 OTG PHY1设备树配置。

1.2.1 控制器配置

(1) USB3.0/2.0 OTG1(DWC3/xHCI)控制器设备节点usbdrd3_1,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

usbdrd3_1: usb@fe900000 {
		compatible = "rockchip,rk3399-dwc3";
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
		clocks = <&cru SCLK_USB3OTG1_REF>, <&cru SCLK_USB3OTG1_SUSPEND>,
				 <&cru ACLK_USB3OTG1>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
				 <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
		clock-names = "ref_clk", "suspend_clk",
					  "bus_clk", "aclk_usb3_rksoc_axi_perf",
					  "aclk_usb3", "grf_clk";
		resets = <&cru SRST_A_USB3_OTG1>;
		reset-names = "usb3-otg";
		status = "disabled";
		usbdrd_dwc3_1: usb@fe900000 {
				compatible = "snps,dwc3";
				reg = <0x0 0xfe900000 0x0 0x100000>;
				interrupts = ;
				clocks = <&cru SCLK_USB3OTG1_REF>, <&cru ACLK_USB3OTG1>,
						 <&cru SCLK_USB3OTG1_SUSPEND>;
				clock-names = "ref", "bus_early", "suspend";
				dr_mode = "otg";
				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,dis-tx-ipgap-linecheck-quirk;
				power-domains = <&power RK3399_PD_USB3>;
				status = "disabled";
		};
};
1.2.2 PHY配置

(1) USB3.0 Type-C PHY1设备节点tcphy1_usb3,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

tcphy1: phy@ff800000 {
		compatible = "rockchip,rk3399-typec-phy";
		reg = <0x0 0xff800000 0x0 0x40000>;
		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,grf = <&grf>;
		status = "disabled";

		tcphy1_dp: dp-port {
				#phy-cells = <0>;
		};

		tcphy1_usb3: usb3-port {
				#phy-cells = <0>;
		};
};

(2) USB2.0 OTG PHY1设备节点u2phy1_otg,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

u2phy1: usb2phy@e460 {
		compatible = "rockchip,rk3399-usb2phy";
		reg = <0xe460 0x10>;
		clocks = <&cru SCLK_USB2PHY1_REF>;
		clock-names = "phyclk";
		#clock-cells = <0>;
		clock-output-names = "clk_usbphy1_480m";
		status = "disabled";

		u2phy1_host: host-port {
				#phy-cells = <0>;
				interrupts = ;
				interrupt-names = "linestate";
				status = "disabled";
		};

		u2phy1_otg: otg-port {
				#phy-cells = <0>;
				interrupts = ,
							 ,
							 ;
				interrupt-names = "otg-bvalid", "otg-id",
								  "linestate";
				status = "disabled";
		};
};
1.2.3 电源配置

(1) USB2.0 PHY1芯片三路电源依次为VCCA0V9_S3VCCA1V8_S3VCC3V3_S3, 这个配置上面已经介绍了,不再重复介绍。

(2) USB3.0 Type-C PHY1芯片三路电源和USB2.0 PHY1芯片三路电源一样。

(3) USB3.0 Host Type-A接口电源VCC5V0_HOST2RT9724GQW提供的,其输入端为VCC5V0_SYS

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vcc5v2_host

vcc5v0_sys: vcc5v0-sys {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v0_sys";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <5000000>;
		regulator-max-microvolt = <5000000>;
};

vcc5v2_host: vcc5v2-host-regulator {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v2_host";
		regulator-always-on;
		regulator-boot-on;	
		vin-supply = <&vcc5v0_sys>;
};
1.2.4 使能

下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件。

(1) 使能usbdrd3_1

/* Configurate and Enable USB3.0/2.0 OTG Controller */
&usbdrd3_1 {
	status = "okay";
};

&usbdrd_dwc3_1 {
	/* 配置dr_mode为host,表示只支持Host only mode */
	dr_mode = "host";
	status = "okay";
};

(2) 使能tcphy1_usb3

/* Enable USB3.0 PHY */
&tcphy1 {
	status = "okay";
};

&tcphy1_usb3{
	status = "okay";
};

(3) 使能u2phy1_otg,同时配置USB2.0 OTG PHY1 phy-supply属性,用于控制USB电源VBUS

/* Enable USB2.0 PHY */
&u2phy1 {
   status = "okay";
};

&u2phy1_otg {
	phy-supply = <&vcc5v2_host>;
	status = "okay";
};
1.2.5 总结

USB3.0 Host Type-A接口设备树配置的注意点如下:

  • 对应的fusb节点不要配置,因为USB3.0 Host Type-A接口不需要fusb302芯片;
  • 对应的USB控制器子节点(usbdrd_dwc3)和PHY的节点(tcphyu2phy)都要删除extcon属性;
  • 对应的USB控制器子节点(usbdrd_dwc3)的dr_mode属性要配置为host

1.3 USB3.0 Type-C

NanoPC-T4开发板支持1个USB3.0 Type-C接口,对应的USB控制器为USB3.0/2.0 OTG0(DWC3/xHCI)、对应的USB PHYUSB3.0 Type-C PHY0USB2.0 OTG PHY0

因此对应的设备树配置,包括USB3.0/2.0 OTG0(DWC3/xHCI)控制器设备树配置和USB3.0 Type-C PHY0USB2.0 OTG PHY0设备树配置。

1.3.1 控制器配置

(1) USB3.0/2.0 OTG0(DWC3/xHCI)控制器设备节点usbdrd3_0,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

usbdrd3_0: usb@fe800000 {
		compatible = "rockchip,rk3399-dwc3";
		#address-cells = <2>;
		#size-cells = <2>;
		ranges;
		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
				 <&cru ACLK_USB3OTG0>, <&cru ACLK_USB3_RKSOC_AXI_PERF>,
				 <&cru ACLK_USB3>, <&cru ACLK_USB3_GRF>;
		clock-names = "ref_clk", "suspend_clk",
					  "bus_clk", "aclk_usb3_rksoc_axi_perf",
					  "aclk_usb3", "grf_clk";
		resets = <&cru SRST_A_USB3_OTG0>;
		reset-names = "usb3-otg";
		status = "disabled";
		usbdrd_dwc3_0: usb@fe800000 {
				compatible = "snps,dwc3";
				reg = <0x0 0xfe800000 0x0 0x100000>;
				interrupts = ;
				clocks = <&cru SCLK_USB3OTG0_REF>, <&cru ACLK_USB3OTG0>,
						 <&cru SCLK_USB3OTG0_SUSPEND>;
				clock-names = "ref", "bus_early", "suspend";
				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,dis-tx-ipgap-linecheck-quirk;
				power-domains = <&power RK3399_PD_USB3>;
				status = "disabled";
		};
};
1.3.2 PHY配置

(1) USB3.0 Type-C PHY0设备节点tcphy0_usb3,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

tcphy0: phy@ff7c0000 {
		compatible = "rockchip,rk3399-typec-phy";
		reg = <0x0 0xff7c0000 0x0 0x40000>;
		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,grf = <&grf>;
		status = "disabled";

		tcphy0_dp: dp-port {
				#phy-cells = <0>;
		};

		tcphy0_usb3: usb3-port {
				#phy-cells = <0>;
		};
};

(2) USB2.0 OTG PHY0设备节点u2phy0_otg,定义在arch/arm64/boot/dts/rockchip/rk3399.dtsi

u2phy0: usb2phy@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";
		status = "disabled";

		u2phy0_host: host-port {
				#phy-cells = <0>;
				interrupts = ;
				interrupt-names = "linestate";
				status = "disabled";
		};

		u2phy0_otg: otg-port {
				#phy-cells = <0>;
				interrupts = ,
							 ,
							 ;
				interrupt-names = "otg-bvalid", "otg-id",
								  "linestate";
				status = "disabled";
		};
};
1.3.3 电源配置

(1) USB2.0 PHY0芯片三路电源依次为VCCA0V9_S3VCCA1V8_S3VCC3V3_S3, 这个配置上面已经介绍了,不再重复介绍。

(2) USB3.0 Type-C PHY0芯片三路电源和USB2.0 PHY0芯片三路电源一样。

(3) USB3.0 Type-C接口电源VBUS_TYPECRT9724GQW提供的,其输入端为VCC5V0_SYS。由GPIO4_D2引脚使能,高电平有效;

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置vbus_typec

vcc5v0_sys: vcc5v0-sys {
		compatible = "regulator-fixed";
		regulator-name = "vcc5v0_sys";
		regulator-always-on;
		regulator-boot-on;
		regulator-min-microvolt = <5000000>;
		regulator-max-microvolt = <5000000>;
};

vbus_typec: vbus-typec {
		compatible = "regulator-fixed";
		enable-active-high;
		gpio = <&gpio4 RK_PD2 GPIO_ACTIVE_HIGH>;
		pinctrl-names = "default";
		pinctrl-0 = <&vbus_typec_en>;
		regulator-name = "vbus_typec";
		vin-supply = <&vcc5v0_sys>;
};

由于vbus_typec节点配置了default状态对应的引脚配置节点为vbus_typec_en,因此需要在pinctrl节点下增加引脚配置节点vbus_typec_en,这个节点在fusb配置中介绍。

1.3.4 fusb302配置

arch/arm64/boot/dts/rockchip/rk3399-evb.dts配置:

&i2c4 {
        clock-frequency = <400000>;
        i2c-scl-rising-time-ns = <160>;
        i2c-scl-falling-time-ns = <30>;
        status = "okay";

        fusb0: typec-portc@22 {
                compatible = "fcs,fusb302";
                reg = <0x22>;
                interrupt-parent = <&gpio1>;
                interrupts = ;
                pinctrl-names = "default";
                pinctrl-0 = <&fusb0_int>;
                vbus-supply = <&vbus_typec>;
	            status = "okay";
        };
};

&pinctrl {
        fusb30x {
                fusb0_int: fusb0-int {
                       rockchip,pins = <1 RK_PA2 RK_FUNC_GPIO &pcfg_pull_up>;
                };
				
				vbus_typec_en: vbus-typec-en {
					   rockchip,pins = <4 RK_PD2 RK_FUNC_GPIO &pcfg_pull_up>;
				};
        };
		......
}

其中GPIO1_A2连接了fusb302的中断引脚,低电平触发。

fusb0设备节点匹配的驱动程序是drivers/usb/typec/tcpm/fusb302.c

如果你使用的是linux 4.19,更改设备节点fusb0如下:

&i2c4 {
		.....
        fusb0: fusb30x@22 {
                compatible = "fairchild,fusb302";
                reg = <0x22>;
                pinctrl-names = "default";
                pinctrl-0 = <&fusb0_int>;
                int-n-gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;    /*  中断引脚GPIO1_A2配置 */
                vbus-5v-gpios = <&gpio4 26 GPIO_ACTIVE_HIGH>;   /* VBUS使能引脚GPIO4_D2配置 */
                status = "okay";
        };
};

fusb0设备节点匹配的驱动程序是drivers/mfd/fusb302.c

1.3.5 使能

下面介绍的都是配置在arch/arm64/boot/dts/rockchip/rk3399-evb.dts文件。

(1) 使能usbdrd3_0

通过dr_mode属性设置USB控制器的模式,一共有三种模式:otg(同时支持主机/设备)、host(主机)、peripheral(设备);这里配置为otg

/* Configurate and Enable USB3.0/2.0 OTG Controller notifier */
&usbdrd3_0 {
	status = "okay";
};

&usbdrd_dwc3_0 {
	/* 配置dr_mode为otg */
	dr_mode = "otg";
	status = "okay";
};

需要注意的是由于我们使用的是linux 6.3内核,内核没有支持驱动drivers/mfd/fusb302.c,导致不会为fusb302驱动注册extcon设备,因此不要在usbdrd3_0设备节点配置extcon属性,不然将会由于找不到extcon,导致usbdrd3_0无法正常工作;并且出现类似如下错误:

[   24.692156] platform ff7c0000.phy: deferred probe pending
[   24.692188] platform fe800000.usb: deferred probe pending

如果你使用的是linux 4.19的内核,由于内核支持驱动drivers/mfd/fusb302.c,因此在usbdrd3_0节点配置extcon属性;

&usbdrd3_0 {
	status = "okay";
    /* 配置extcon属性,用于接收fusb302驱动的UFP/DFP */
  	extcon = <&fusb0>;
};

(2) 使能tcphy0_usb3

/* Enable USB3.0 PHY */
&tcphy0 {
	status = "okay";
};

&tcphy0_usb3{
	status = "okay";
};

同上,如果是linux 4.19的内核,需要在tcphy0节点配置extcon属性。

(3) 使能u2phy0_otg,同时配置USB2.0 OTG PHY0 phy-supply属性,用于控制USB电源VBUS

/* Enable USB2.0 PHY */
&u2phy0 {
     status = "okay";
};

&u2phy0_otg {
	phy-supply = <&vbus_typec>;
	status = "okay";
};

同上,如果是linux 4.19的内核,需要在u2phy0节点配置extcon属性。

1.3.6 总结

USB3.0 Type-C设备树配置的注意点如下:

  • 对应的fusb节点需要配置,因为USB3.0 Type-C需要fusb302芯片;
  • 对应的USB控制器子节点(usbdrd_dwc3)和PHY的节点(tcphyu2phy)都要配置extcon属性;
  • 对应的USB控制器子节点(usbdrd_dwc3)的dr_mode属性要配置为otg

二、 配置内核

2.1 配置USB PHY

linux内核根目录下执行make menuconfig配置以下选项:

Device Drivers  --->
    PHY Subsystem  ---> 
       <*> Rockchip INNO USB2PHY Driver
	   <*> Rockchip TYPEC PHY Driver

USB2.0 PHY使用的是Innosilicon IP,所以应选择Rockchip INNO USB2PHY Driver,驱动位于drivers/phy/rockchip/phy-rockchip-inno-usb2.cUSB3.0 Type-C PHY使用的是Type-C,所以应选择Rockchip TYPEC PHY Driver,驱动位于drivers/phy/rockchip/phy-rockchip-typec.c

2.2 配置USB控制器

linux内核根目录下执行make menuconfig配置以下选项:

Device Drivers  --->
    [*] USB support --->
	   <*> xHCI HCD (USB 3.0) support
       -*- Generic xHCI driver for a platform device
	   <*> EHCI HCD (USB 2.0) support
       -*- Root Hub Transaction Translators
       [*] Improved Transaction Translator scheduling
       <*> Generic EHCI driver for a platform device
       <*> OHCI HCD (USB 1.1) support
       <*> Generic OHCI driver for a platform device
	<*> USB support  -->
	   [*] USB announce new devices(输出识别的每个usb设备的基本信息,比如idVendor、idProduct、制造商、产品、和序列号等)

OHCI HCD (USB 1.1)选择OHCI Driver配置;

EHCI HCD (USB 2.0) 选择EHCI Driver配置;

xHCI HCD (USB 3.0)选择xHCI Driver配置。

2.3 配置USB OTG

默认情况下dw3是双角色(即同时支持HostDevice模式,可以动态切换):

Device Drivers --->
	[*] USB support --->
		<*> DesignWare USB2 DRD Core Support
			DWC2 Mode Selection (Dual Role mode)
		<*> DesignWare USB3 DRD Core Support
			DWC3 Mode Selection (Dual Role mode)

RK3399 USB3.0 OTG使用Synopsys方案,即xHCI扩展的DWC3控制器,因此需要配置DesignWare USB3 DRD Core Support

2.4 配置USB Gadget

由于我们将USB3.0 Type-C接口配置为了USB OTG,作为USB device(丛机)使用,因此我们可以将开发板模拟成一个存储设备、或者声卡、鼠标等设备,然后可以通过开发板上的USB3.0 Type-C接口将PC和开发板连接在一起。

linux内核根目录下执行make menuconfig配置以下选项:

Device Drivers  --->
    [*] USB support  ---> 
       <*> USB Gadget Support ---> 
	        USB Gadget functions configurable through configfs
              [*]  Generic serial bulk in/out                                                       
			  [*]  Abstract Control Model (CDC ACM)  		  
              [*]  Object Exchange Model (CDC OBEX)                                                 
			  [*]  Network Control Model (CDC NCM)                                                 
			  [*]  Ethernet Control Model (CDC ECM)                                                 
			  [*]  Ethernet Control Model (CDC ECM) subset                                         
			  [*]  RNDIS                                                                           
			  [*]  Ethernet Emulation Model (EEM)                                                   
			  [*]  Mass storage     (大容量存储功能)                     
			  [ ]  Loopback and sourcesink function (for testing)                                   
			  [*]  Function filesystem (FunctionFS)                                                 
			  [*]  Audio Class 1.0 (音频功能 1.0)
			  [*]  Audio Class 1.0 (legacy implementation)                                         
			  [*]  Audio Class 2.0 (音频功能 2.0) 
			  [ ]  MIDI function                                                                   
			  [*]  HID function    (HID功能)    
              [*]  USB Webcam functio (USB摄像头功能)    
			  [ ]  Printer function  
		 USB Gadget precomposed configurations  --->
			   Audio Gadget           (音频设备)   
			  < > Ethernet Gadget (with CDC Ethernet support)     (网络设备)
			  < > Network Control Model (NCM) support     
			  <*> Gadget Filesystem                          
			  <*> Function Filesystem                                     
			   Mass Storage Gadget  (存储设备)
			  < > Serial Gadget (with CDC ACM and CDC OBEX support)   (串口设备)
			  < > MIDI Gadget                    
			  < > Printer Gadget    (打印机)
			  < > CDC Composite Device (Ethernet and ACM)  
			  < > CDC Composite Device (ACM and mass storage)
			  < > Multifunction Composite Gadget 
			   HID Gadget           (hid设备)
			  < > EHCI Debug Device Gadget
			  < > USB Webcam Gadget    (`USB`摄像头)
			  < > USB Raw Gadget

USB Gadget驱动主要包括两大块:

  • USB Gadget functions各种USB子类设备功能驱动,位于drivers/usb/gadget/function目录下,里面给出了对应的sample。其作用是配置USB子类协议的接口描述以及其它子类协议,比如uvc协议,hid等;

  • USB Gadget Legacy:整个Gadget设备驱动的入口,位于drivers/usb/gadget/legacy目录下:里面给出了常用的USB类设备的驱动sample。其作用就是配置USB设备描述符信息,提供一个usb_composite_driver, 然后注册到composite层。

有关USB Gadget驱动更加具体内容参考《一文搞懂 USB 设备端驱动框架》。

下面我们介绍几个Gadget设备驱动:

  • Mass Storage Gadget用于模拟大容量存储设备;需要注意:linux下的SD卡、eMMC文件系统一般是ext4,在windows下不识别;所以如果做实验,可以使用FAT格式的存储器,比如U盘;或者是NFTS格式的移动硬盘;因此我们还需要配置内核支持exFAT/NFTS文件系统;
File systems 
    <*> FUSE (Filesystem in Userspace) support
	DOS/FAT/EXFAT/NT Filesystems  ---> 
	 	 < > MSDOS fs support   
	 	 <*> VFAT (Windows-95) fs support   
	 	 (437) Default codepage for FAT 
	 	 (iso8859-1) Default iocharset for FAT 
	 	 [*] Enable FAT UTF-8 option by default
	 	 <*> exFAT filesystem support 
	 	 (utf8) Default iocharset for exFAT (NEW)
	 	 <*> NTFS file system support
		     [ ] NTFS debugging support
		     [*] NTFS write support
	 	 <*> NTFS Read-Write file system support 
		     [*] 64 bits per NTFS clusters 
  	 	     [*] activate support of external compressions lzx/xpress
             [*] NTFS POSIX Access Control Lists
  • Audio Gadget用于模拟声卡;USB声卡就是USB接口的外置声卡,一般电脑都自带了声卡,但是内部自带的声卡效果相对来说比较差,不能满足很多HIFI玩家的需求,USB声卡通过USB接口来传递音频数据。具体的ADCDAC过程由声卡完成,摆脱了电脑主板体积的限制,外置USB声卡就可以做的很好。NanoPC-T4开发板搭载了音频解码芯片,因此可以将NanoPC-T4开发板作为一个外置USB声卡。该驱动程序它会自动使用默认音频解码器来播放来自主机机器的音频。

  • HID Gadget用于模拟人机接口设备,包括键盘、鼠标、操纵杆、扫描仪、数字化板、触摸屏等。

此外我们还配置了Gadget FilesystemFunction Filesystem

  • Gadget FilesystemGadget文件系统是通过/config/usb_gadget/目录暴露给用户空间的一个虚拟文件系统。在该文件系统下,可以创建和配置USB gadget设备。例如,可以创建用于描述设备信息和字符串描述符的文件、定义功能的文件,并通过对这些文件进行操作来配置USB gadget
  • Function FilesystemFunction文件系统是一个以 /sys/class/udc/为根目录的伪文件系统。它通过与USB控制器驱动程序进行交互,用于配置和管理USB gadget功能。在该文件系统中,每个USB gadget功能都表示为一个子目录,可以在其中配置各种功能参数。例如,对于Mass Storage功能,可以在/sys/class/udc/gadget_name/function_name/目录下找到相关配置文件。

2.5 配置USB外设

根据开发板硬件情况,配置支持各种USB设备。

2.51 配置大容量存储设备

移动硬盘属于SCSI设备,所以在配置USB模块之前需要配置SCSI选项;

Device Drivers --->
    SCSI device support --->
        <*> SCSI device support
        [*] legacy /proc/scsi/ support
        *** SCSI support type (disk, tape, CD-ROM) ***
        <*> SCSI disk support
        < > SCSI tape support
        < > SCSI CDROM support
        <*> SCSI generic support
        [*] /dev/bsg support (SG v4)
        <*> SCSI media changer support
        [*] Verbose SCSI error reporting (kernel size +=75K)
        [*] SCSI logging facility
        [*] Asynchronous SCSI scanning
        SCSI Transports --->
        [*] SCSI low-level drivers --->
        [ ] SCSI Device Handlers ----

配置完SCSI Device Support后,可以在USB Support中找到如下选项,选上即可

Device Driver --->
	[*] USB support --->
		<*> USB Mass Storage support
2.5.2 配置USB转串口

(1) 支持USB 3G Modem

USB 3G Modem使用的是USB转串口,使用时需要选上如下选项:

Device Driver --->
	[*] USB support --->
		<*> USB Serial Converter support --->
			<*> USB driver for GSM and CDMA modems

此外,USB 3G Modem还需要使能PPP拨号的相关配置项:

Device Driver --->
	[*] Network device support --->
		<*> PPP (point-to-point protocol) support
            <*> PPP BSD-Compress compression
            <*> PPP Deflate compression
            [*] PPP filtering
            <*> PPP MPPE compression (encryption)
            [*] PPP multilink support
            <*> PPP over Ethernet
            <*> PPP over L2TP
            <*> PPP on L2TP Access Concentrator
            <*> PPP on PPTP Network Server
            <*> PPP support for async serial ports
            <*> PPP support for sync tty ports

(2) 支持PL2303

如果要使用PL2303输出数据到串口,需要选择如下选项,同时需要禁用 USB driver for GSM and CDMA modems,否则,PL2303可能会被误识别为USB 3G modem

Device Driver --->
	[*] USB support --->
		<*> USB Serial Converter support --->
			<*> USB Prolific 2303 Single Port Serial Driver

(3) 支持USB GPS
如果要支持USB GPS,如u-blox 6-GPS Receiver设备,需要选择如下选项:

Device Drivers --->
	[*] USB support --->
		[*] USB Modem (CDC ACM) support
2.5.3 配置HID

USB键盘、鼠标、触摸屏的配置选项如下:

Device Drivers --->
	[*] HID bus support
		-*-   HID bus core support
			 <*>  Generic HID driver
	    USB HID support  --->
		     <*> USB HID transport layer
			 [ ] PID device support
	 		 [*] /dev/hiddev raw HID device support

USB HID transport layer(USB人机接口设备传输层) 此选项对应配置项就是CONFIG_USB_HID,也就是USB接口的HID设备。如果要使用USB接口的keyboards(键盘)、mice(鼠标)、joysticks(摇杆)、graphic tablets(绘图板)等其他的HID设备,那么就需要选中USB HID Transport layer

USB HID Transport LayerUSB协议栈中的一个组件,用于支持 HID类型的设备与计算机之间的通信。USB HID传输层负责解析来自HID设备的数据,并将其转换为适当的格式,以便应用程序可以理解和使用。

关于USB鼠标我们之前有单独的文章介绍:linux驱动移植-usb鼠标接口驱动。

关于USB键盘我们之前有单独的文章介绍:linux驱动移植-usb键盘接口驱动。

实际上在linux中还有一个通用输入层子系统,用于处理和管理各种输入设备,例如键盘、鼠标、触摸屏和游戏手柄等。通用输入层提供了一个统一的接口,使应用程序可以以一致的方式与不同类型的输入设备进行交互,配置如下:

Device Drivers  --->
   Input device support  
      -*- Generic input layer (needed for keyboard, mouse, ...)

那他们之间有什么区别呢?

区别在于,Generic Input LayerLinux内核的一个通用输入设备管理层,它与各种输入设备进行交互,并将输入数据传递给应用程序。USB HID Transport Layer USB协议栈中的一个特定组件,专门用于处理HID设备的通信和数据传输。通用输入层可以与各种输入设备一起使用(不仅限于USB HID设备),而USB HID传输层则专注于USB HID设备的通信协议。

针对于USB输入设备,我们配置USB HID transport layer即可。

2.5.4 配置USB摄像头
Device Drivers -->
	--- Multimedia support 
	    [ ]  Filter media drivers  (取消选择)
        Media core support  --->
		    <*> Video4Linux core (NEW) 
		    [*] Media Controller API (NEW) 
	    Media drivers  --->
			[*] Media USB Adapters(启用usb总线的媒体驱动程序,drivers/media/usb)
				<*> USB Video Class(UVC)(我们的摄像头支持UVC,选择这个驱动即可)
				[*] UVC input events device  supports(NEW)
				<> GSPCA based webcams --> (GSPCA 是一个法国程序员在业余时间制作的一个万能USB 摄像头驱动程序,在此可以选择对应类型USB摄像头的支持)
				<> SONIX Bayer USB Camer Driver (NEW)
				<> OV772x/OV965x/... 系列摄像头支持
				<> ....  
        	[*] Media platform devices (NEW)  --->
				[*]V4L platform devices

关于USB摄像头我们之前有单独的文章介绍:linux驱动移植-usb摄像头uvc驱动。

2.5.5 配置USB音频
Device Driver --->
	<*> Sound card support --->
		<*> Advanced Linux Sound Architecture --->
			[*] USB sound devices --->
				[*] USB Audio/MIDI driver
2.5.6 配置USB HUB

如果要支持USB HUB,请将Disable external hubs配置选项去掉;

Device Drivers --->
	[*] USB support --->
		[ ] Disable external hubs

其它有可能用到的USB设备还有很多,如GPSPrinter等,有可能需要Vendor定制的驱动,也有可能
是标准的 设备类驱动,如需支持这类设备,可直接在网络上搜索linux对该设备支持要做的工作。

2.6 配置extcon

2.6.1 linux 6.3配置

配置Fairchild FUSB302 Type-C chip driver驱动,将drivers/usb/typec/tcpm/fusb302.c编译到内核;

Device Driver --->
    -*- External Connector Class (extcon) support  --->
	<*> USB support --->
		<*> USB Type-C Support --->
			[*] USB Type-C Port Controller Manager --->
			[*] Fairchild FUSB302 Type-C chip driver

需要注意的是drivers/usb/typec/tcpm/fusb302.c驱动并不会注册extcon设备;因此无法识别是接入了USB主机或USB设备。

drivers/usb/typec/tcpm/fusb302.cprobe函数:

点击查看代码
static int fusb302_probe(struct i2c_client *client)
{
        struct fusb302_chip *chip;
        struct i2c_adapter *adapter = client->adapter;
        struct device *dev = &client->dev;
        const char *name;
        int ret = 0;

        if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
                dev_err(&client->dev,
                        "I2C/SMBus block functionality not supported!\n");
                return -ENODEV;
        }
        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;

        chip->i2c_client = client;
        chip->dev = &client->dev;
        mutex_init(&chip->lock);

        /*
         * Devicetree platforms should get extcon via phandle (not yet
         * supported). On ACPI platforms, we get the name from a device prop.
         * This device prop is for kernel internal use only and is expected
         * to be set by the platform code which also registers the i2c client
         * for the fusb302.
         */
        if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
                chip->extcon = extcon_get_extcon_dev(name);
                if (IS_ERR(chip->extcon))
                        return PTR_ERR(chip->extcon);
        }

        chip->vbus = devm_regulator_get(chip->dev, "vbus");
        if (IS_ERR(chip->vbus))
                return PTR_ERR(chip->vbus);

        chip->wq = create_singlethread_workqueue(dev_name(chip->dev));
        if (!chip->wq)
                return -ENOMEM;

        spin_lock_init(&chip->irq_lock);
        INIT_WORK(&chip->irq_work, fusb302_irq_work);
        INIT_DELAYED_WORK(&chip->bc_lvl_handler, fusb302_bc_lvl_handler_work);
        init_tcpc_dev(&chip->tcpc_dev);
        fusb302_debugfs_init(chip);

        if (client->irq) {
                chip->gpio_int_n_irq = client->irq;
        } else {
                ret = init_gpio(chip);
                if (ret < 0)
                        goto destroy_workqueue;
        }

        chip->tcpc_dev.fwnode = fusb302_fwnode_get(dev);
        if (IS_ERR(chip->tcpc_dev.fwnode)) {
                ret = PTR_ERR(chip->tcpc_dev.fwnode);
                goto destroy_workqueue;
        }

        chip->tcpm_port = tcpm_register_port(&client->dev, &chip->tcpc_dev);
        if (IS_ERR(chip->tcpm_port)) {
                fwnode_handle_put(chip->tcpc_dev.fwnode);
                ret = dev_err_probe(dev, PTR_ERR(chip->tcpm_port),
                                    "cannot register tcpm port\n");
                goto destroy_workqueue;
        }

        ret = request_irq(chip->gpio_int_n_irq, fusb302_irq_intn,
                          IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                          "fsc_interrupt_int_n", chip);
        if (ret < 0) {
                dev_err(dev, "cannot request IRQ for GPIO Int_N, ret=%d", ret);
                goto tcpm_unregister_port;
        }
        enable_irq_wake(chip->gpio_int_n_irq);
        i2c_set_clientdata(client, chip);

        return ret;

tcpm_unregister_port:
        tcpm_unregister_port(chip->tcpm_port);
        fwnode_handle_put(chip->tcpc_dev.fwnode);
destroy_workqueue:
        fusb302_debugfs_exit(chip);
        destroy_workqueue(chip->wq);

        return ret;
}
2.6.2 linux 4.19配置

如果你使用的是linux 4.19内核,则配置Fairchild fusb302 Support驱动,将drivers/mfd/fusb302.c编译到内核;

Device Driver --->
	<*> Fairchild fusb302 Support

linux 6.3为啥不配置这个呢?因此linux 6.3内核驱动没有带有这个驱动,除非我们自己移植过来。

需要注意的是drivers/mfd/fusb302.c驱动并会注册extcon设备;因此能够识别是接入了USB主机或USB设备。

drivers/mfd/fusb302.cprobe函数:

点击查看代码
static int fusb30x_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
{
        struct fusb30x_chip *chip;
        struct PD_CAP_INFO *pd_cap_info;
        int ret;
        char *string[2];

        chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
                return -ENOMEM;

        if (fusb30x_port_used == 0xff)
                return -1;

        chip->port_num = fusb30x_port_used++;
        fusb30x_port_info[chip->port_num] = chip;

        chip->dev = &client->dev;
        chip->regmap = devm_regmap_init_i2c(client, &fusb302_regmap_config);
        if (IS_ERR(chip->regmap)) {
                dev_err(&client->dev, "Failed to allocate regmap!\n");
                return PTR_ERR(chip->regmap);
        }

        ret = fusb_initialize_gpio(chip);
        if (ret)
                return ret;

        fusb_initialize_timer(chip);

        chip->fusb30x_wq = create_workqueue("fusb302_wq");
        INIT_WORK(&chip->work, fusb302_work_func);

        chip->role = ROLE_MODE_NONE;
        chip->try_role = ROLE_MODE_NONE;
        if (!of_property_read_string(chip->dev->of_node, "fusb302,role",
                                     (const char **)&string[0])) {
                if (!strcmp(string[0], "ROLE_MODE_DRP"))
                        chip->role = ROLE_MODE_DRP;
                else if (!strcmp(string[0], "ROLE_MODE_DFP"))
                        chip->role = ROLE_MODE_DFP;
                else if (!strcmp(string[0], "ROLE_MODE_UFP"))
                        chip->role = ROLE_MODE_UFP;
        }
        if (chip->role == ROLE_MODE_NONE) {
                dev_warn(chip->dev,
                         "Can't get property of role, set role to default DRP\n");
                chip->role = ROLE_MODE_DRP;
                string[0] = "ROLE_MODE_DRP";
        }

        if (!of_property_read_string(chip->dev->of_node, "fusb302,try_role",
                                     (const char **)&string[1])) {
                if (!strcmp(string[1], "ROLE_MODE_DFP"))
                        chip->try_role = ROLE_MODE_DFP;
                else if (!strcmp(string[1], "ROLE_MODE_UFP"))
                        chip->try_role = ROLE_MODE_UFP;
        }

        if (chip->try_role == ROLE_MODE_NONE)
                string[1] = "ROLE_MODE_NONE";

        chip->vconn_supported = true;
        tcpm_init(chip);
        tcpm_set_rx_enable(chip, 0);
        chip->conn_state = unattached;
        tcpm_set_cc(chip, chip->role);

        chip->n_caps_used = 1;
        chip->source_power_supply[0] = 0x64;
        chip->source_max_current[0] = 0x96;

        pd_cap_info = &chip->pd_cap_info;
        pd_cap_info->dual_role_power = 1;
        pd_cap_info->data_role_swap = 1;

        pd_cap_info->externally_powered = 1;
        pd_cap_info->usb_suspend_support = 0;
        pd_cap_info->usb_communications_cap = 0;
        pd_cap_info->supply_type = 0;
        pd_cap_info->peak_current = 0;

        chip->extcon = devm_extcon_dev_allocate(&client->dev, fusb302_cable);
        if (IS_ERR(chip->extcon)) {
                dev_err(&client->dev, "allocat extcon failed\n");
                return PTR_ERR(chip->extcon);
        }

        ret = devm_extcon_dev_register(&client->dev, chip->extcon);
        if (ret) {
                dev_err(&client->dev, "failed to register extcon: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_USB,
                                             EXTCON_PROP_USB_TYPEC_POLARITY);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set USB property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_USB_HOST,
                                             EXTCON_PROP_USB_TYPEC_POLARITY);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set USB_HOST property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_DISP_DP,
                                             EXTCON_PROP_USB_TYPEC_POLARITY);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set DISP_DP property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_USB,
                                             EXTCON_PROP_USB_SS);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set USB USB_SS property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_USB_HOST,
                                             EXTCON_PROP_USB_SS);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set USB_HOST USB_SS property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_DISP_DP,
                                             EXTCON_PROP_USB_SS);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set DISP_DP USB_SS property capability: %d\n",
                        ret);
                return ret;
        }

        ret = extcon_set_property_capability(chip->extcon, EXTCON_CHG_USB_FAST,
                                             EXTCON_PROP_USB_TYPEC_POLARITY);
        if (ret) {
                dev_err(&client->dev,
                        "failed to set USB_PD property capability: %d\n", ret);
                return ret;
        }

        i2c_set_clientdata(client, chip);

        spin_lock_init(&chip->irq_lock);
        chip->enable_irq = 1;

        chip->gpio_int_irq = gpiod_to_irq(chip->gpio_int);
        if (chip->gpio_int_irq < 0) {
                dev_err(&client->dev,
                        "Unable to request IRQ for INT_N GPIO! %d\n",
                        ret);
                ret = chip->gpio_int_irq;
                goto IRQ_ERR;
        }

        ret = devm_request_threaded_irq(&client->dev,
                                        chip->gpio_int_irq,
                                        NULL,
                                        cc_interrupt_handler,
                                        IRQF_ONESHOT | IRQF_TRIGGER_LOW,
                                        client->name,
                                        chip);
        if (ret) {
                dev_err(&client->dev, "irq request failed\n");
                goto IRQ_ERR;
        }

        dev_info(chip->dev,
                 "port %d probe success with role %s, try_role %s\n",
                 chip->port_num, string[0], string[1]);

        chip->input = devm_input_allocate_device(&client->dev);
        if (!chip->input) {
                dev_err(chip->dev, "Can't allocate input dev\n");
                ret = -ENOMEM;
                goto IRQ_ERR;
        }

        chip->input->name = "Typec_Headphone";
        chip->input->phys = "fusb302/typec";

        input_set_capability(chip->input, EV_SW, SW_HEADPHONE_INSERT);

        ret = input_register_device(chip->input);
        if (ret) {
                dev_err(chip->dev, "Can't register input device: %d\n", ret);
                goto IRQ_ERR;
        }
        return 0;
IRQ_ERR:
        destroy_workqueue(chip->fusb30x_wq);
        return ret;
}

2.7 保存配置

配置完内核之后记得保存配置:

Rockchip RK3399 - USB调试_第1张图片

存档:

root@zhengyang:/work/sambashare/rk3399/linux-6.3# mv rk3399_defconfig ./arch/arm64/configs/

重新配置内核(如果不想重新编译内核,可以存档一份到.config):

root@zhengyang:/work/sambashare/rk3399/linux-6.3# make rk3399_defconfig

2.8 烧录内核

2.8.1 编译内核

linux内核根目录下执行如下命令进行编译内核:

root@zhengyang:/work/sambashare/rk3399/linux-6.3# make -j8

u-boot-2023.04路径下的mkimage工具拷贝过来,然后在命令行使用mkimage工具编译即可:

root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp ../u-boot-2023.04/tools/mkimage ./
root@zhengyang:/work/sambashare/rk3399/linux-6.3# ./mkimage -f kernel.its kernel.itb
2.8.2 通过tftp烧录内核

给开发板上电,同时连接上网线,进入uboot命令行。我们将内核拷贝到tftp文件目录:

root@zhengyang:/work/sambashare/rk3399/linux-6.3# cp kernel.itb /work/tftpboot/

接着给开发板上电。通过uboot命令行将kernel.itb下到内存地址0x10000000处:

=> tftp 0x10000000 kernel.itb

通过mmc write命令将内核镜像烧录到eMMC0x8000个扇区处:

=> mmc erase 0x8000 0xA000
=> mmc write 0x10000000 0x8000 0xA000
2.8.3 启动内核

我们重新启动开发板,我们会看到与USB相关的日志:

[    1.829924] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    1.830411] ehci-platform fe380000.usb: EHCI Host Controller
[    1.830442] ohci-platform fe3a0000.usb: Generic Platform OHCI controller
[    1.830485] ohci-platform fe3a0000.usb: new USB bus registered, assigned bus number 1
[    1.830590] ehci-platform fe3c0000.usb: EHCI Host Controller
[    1.830609] ohci-platform fe3e0000.usb: Generic Platform OHCI controller
[    1.830621] ehci-platform fe3c0000.usb: new USB bus registered, assigned bus number 2
[    1.830638] ohci-platform fe3e0000.usb: new USB bus registered, assigned bus number 3
[    1.830658] ohci-platform fe3a0000.usb: irq 53, io mem 0xfe3a0000
[    1.830761] ehci-platform fe3c0000.usb: irq 52, io mem 0xfe3c0000
[    1.830789] ohci-platform fe3e0000.usb: irq 54, io mem 0xfe3e0000
[    1.836166] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 4
[    1.842483] ehci-platform fe380000.usb: new USB bus registered, assigned bus number 5
[    1.850092] xhci-hcd xhci-hcd.0.auto: hcc params 0x0220fe64 hci version 0x110 quirks 0x0000000002010010
[    1.853065] ehci-platform fe3c0000.usb: USB 2.0 started, EHCI 1.00
[    1.853516] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[    1.853532] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    1.853544] usb usb2: Product: EHCI Host Controller
[    1.853553] usb usb2: Manufacturer: Linux 6.3.0 ehci_hcd
[    1.853562] usb usb2: SerialNumber: fe3c0000.usb
[    1.854382] hub 2-0:1.0: USB hub found
[    1.854450] hub 2-0:1.0: 1 port detected
[    1.858836] ehci-platform fe380000.usb: irq 51, io mem 0xfe380000
[    1.865071] xhci-hcd xhci-hcd.0.auto: irq 49, io mem 0xfe800000
[    1.885063] ehci-platform fe380000.usb: USB 2.0 started, EHCI 1.00
[    1.890257] xhci-hcd xhci-hcd.0.auto: xHCI Host Controller
[    1.897120] usb usb5: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[    2.023756] usb usb5: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.031870] usb usb5: Product: EHCI Host Controller
[    2.037347] usb usb5: Manufacturer: Linux 6.3.0 ehci_hcd
[    2.043306] usb usb5: SerialNumber: fe380000.usb
[    2.049117] hub 5-0:1.0: USB hub found
[    2.053375] hub 5-0:1.0: 1 port detected
[    2.058339] usb usb1: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.03
[    2.067630] usb usb1: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.075719] usb usb1: Product: Generic Platform OHCI controller
[    2.082361] usb usb1: Manufacturer: Linux 6.3.0 ohci_hcd
[    2.088316] usb usb1: SerialNumber: fe3a0000.usb
[    2.094011] hub 1-0:1.0: USB hub found
[    2.098273] hub 1-0:1.0: 1 port detected
[    2.103093] xhci-hcd xhci-hcd.0.auto: new USB bus registered, assigned bus number 6
[    2.103266] usb usb3: New USB device found, idVendor=1d6b, idProduct=0001, bcdDevice= 6.03
[    2.111691] xhci-hcd xhci-hcd.0.auto: Host supports USB 3.0 SuperSpeed
[    2.120951] usb usb3: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.136415] usb usb3: Product: Generic Platform OHCI controller
[    2.143068] usb usb3: Manufacturer: Linux 6.3.0 ohci_hcd
[    2.149052] usb usb3: SerialNumber: fe3e0000.usb
[    2.154791] hub 3-0:1.0: USB hub found
[    2.159046] hub 3-0:1.0: 1 port detected
[    2.164005] usb usb4: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[    2.173296] usb usb4: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.181386] usb usb4: Product: xHCI Host Controller
[    2.186857] usb usb4: Manufacturer: Linux 6.3.0 xhci-hcd
[    2.192813] usb usb4: SerialNumber: xhci-hcd.0.auto
[    2.198818] hub 4-0:1.0: USB hub found
[    2.203079] hub 4-0:1.0: 1 port detected
[    2.207872] usb usb6: We don't know the algorithms for LPM for this host, disabling LPM.
[    2.217093] usb usb6: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.03
[    2.226375] usb usb6: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.234485] usb usb6: Product: xHCI Host Controller
[    2.239956] usb usb6: Manufacturer: Linux 6.3.0 xhci-hcd
[    2.245911] usb usb6: SerialNumber: xhci-hcd.0.auto
[    2.251953] hub 6-0:1.0: USB hub found
[    2.256206] hub 6-0:1.0: 1 port detected
[    2.261191] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[    2.267479] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 7
[    2.276205] xhci-hcd xhci-hcd.1.auto: hcc params 0x0220fe64 hci version 0x110 quirks 0x0000000002010010
[    2.286876] xhci-hcd xhci-hcd.1.auto: irq 50, io mem 0xfe900000
[    2.293711] xhci-hcd xhci-hcd.1.auto: xHCI Host Controller
[    2.299883] xhci-hcd xhci-hcd.1.auto: new USB bus registered, assigned bus number 8
[    2.308563] xhci-hcd xhci-hcd.1.auto: Host supports USB 3.0 SuperSpeed
[    2.316043] usb usb7: New USB device found, idVendor=1d6b, idProduct=0002, bcdDevice= 6.03
[    2.325407] usb usb7: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.333513] usb usb7: Product: xHCI Host Controller
[    2.338977] usb usb7: Manufacturer: Linux 6.3.0 xhci-hcd
[    2.345017] usb usb7: SerialNumber: xhci-hcd.1.auto
[    2.351075] hub 7-0:1.0: USB hub found
[    2.355332] hub 7-0:1.0: 1 port detected
[    2.360123] usb usb8: We don't know the algorithms for LPM for this host, disabling LPM.
[    2.369320] usb usb8: New USB device found, idVendor=1d6b, idProduct=0003, bcdDevice= 6.03
[    2.378593] usb usb8: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[    2.386698] usb usb8: Product: xHCI Host Controller
[    2.392169] usb usb8: Manufacturer: Linux 6.3.0 xhci-hcd
[    2.398123] usb usb8: SerialNumber: xhci-hcd.1.auto
[    2.404138] hub 8-0:1.0: USB hub found
[    2.408398] hub 8-0:1.0: 1 port detected
[    2.414435] usbcore: registered new interface driver usb-storage
[    2.421325] usbcore: registered new interface driver pl2303
[    2.427613] usbserial: USB Serial support registered for pl2303
[    3.598344] usbcore: registered new interface driver uvcvideo
[    3.718570] usbcore: registered new interface driver usbhid
[    3.730651] usbhid: USB HID core driver
[    3.744550] usbcore: registered new interface driver snd-usb-audio

从上面日志上可以看到总共注册了8个USB总线,编号依次从1~8。每个USB总线上对应一个USB控制器,一共有8个USB控制器;

  • ohci-platform fe3a0000.usbUSB总线编号为1,对应设备节点usb_host0_ohci,对应开发板上接口为USBH2

  • ehci-platform fe3c0000.usbUSB总线编号为2,对应设备节点usb_host1_ehci,对应开发板上接口为USBH3

  • ohci-platform fe3e0000.usbUSB总线编号为3,对应设备节点usb_host1_ohci,对应开发板上接口为USBH3

  • xhci-hcd xhci-hcd.0.auto(fe800000.usb)USB总线编号为4,对应设备节点usbdrd3_0,对应开发板上接口为Type-C/DP

  • ehci-platform fe380000.usbUSB总线编号为5,对应设备节点usb_host0_ehci,对应开发板上接口为USBH2

  • xhci-hcd xhci-hcd.0.auto(fe800000.usb)USB总线编号为6,对应设备节点usbdrd3_0,对应开发板上接口为Type-C/DP

  • xhci-hcd xhci-hcd.1.auto(fe900000.usb)USB总线编号为7,对应设备节点usbdrd3_1,对应开发板上接口为CON5

  • xhci-hcd xhci-hcd.1.auto(fe900000.usb)USB总线编号为8,对应设备节点usbdrd3_1,对应开发板上接口为CON5

三、测试USB设备

我们接下来在开发板USB2.0 Host Type-AUSB3.0 Host Type-A接口插入不同的USB设备进行测试。

3.1 测试USB鼠标

我们将USB鼠标接到开发板其中一个USB2.0 Host Type-A接口(对应开发板上的USBH3), 我们可以在内核日志中,找到USB鼠标信息的日志:

[ 1457.916575] usb 3-1: new full-speed USB device number 2 using ohci-platform
[ 1458.149684] usb 3-1: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.11
[ 1458.149723] usb 3-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1458.149740] usb 3-1: Product: USB Receiver
[ 1458.149754] usb 3-1: Manufacturer: Logitech
[ 1458.161331] input: Logitech USB Receiver as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.0/0003:046D:C52B.0001/input/input1
[ 1458.221766] hid-generic 0003:046D:C52B.0001: input: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-fe3e0000.usb-1/input0
[ 1458.230238] input: Logitech USB Receiver Mouse as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input2
[ 1458.230914] input: Logitech USB Receiver Consumer Control as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input3
[ 1458.289373] input: Logitech USB Receiver System Control as /devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/0003:046D:C52B.0002/input/input4
[ 1458.290293] hid-generic 0003:046D:C52B.0002: input,hiddev96: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-fe3e0000.usb-1/input1
[ 1458.297793] hid-generic 0003:046D:C52B.0003: hiddev97: USB HID v1.11 Device [Logitech USB Receiver] on usb-fe3e0000.usb-1/input2

此时可以在ubuntu桌面系统测试鼠标,可以发现是可以正常使用的。

USB鼠标工作在全速模式下,OHCI控制器,USB1.1通信协议,使用的USB总线编号为3,设备编号为2。

系统检测到了Logitech(罗技)的鼠标,如果成功驱动的话就会在/dev/input目录下生成一个名为eventX(X=0,1,2,3…)的文件,这个就是我们前面讲的输入子系统,鼠标和键盘都是作为输入子系统设备的。

3.2 测试USB键盘

(1) 我们将USB键盘接到开发板另一个USB2.0 Host Type-A接口(对应开发板上的USBH2),在内核日志中,找到USB键盘信息的日志:

[ 1619.954338] usb 1-1: new low-speed USB device number 2 using ohci-platform
[ 1620.183564] usb 1-1: New USB device found, idVendor=1a2c, idProduct=4d7e, bcdDevice= 1.10
[ 1620.183603] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1620.183620] usb 1-1: Product: USB Keyboard
[ 1620.183634] usb 1-1: Manufacturer: SEMICO
[ 1620.193197] input: SEMICO USB Keyboard as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.0/0003:1A2C:4D7E.0004/input/input6
[ 1620.251611] hid-generic 0003:1A2C:4D7E.0004: input: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-fe3a0000.usb-1/input0
[ 1620.263525] input: SEMICO USB Keyboard Consumer Control as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input7
[ 1620.323415] input: SEMICO USB Keyboard System Control as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input8
[ 1620.324115] input: SEMICO USB Keyboard as /devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/0003:1A2C:4D7E.0005/input/input10
[ 1620.324871] hid-generic 0003:1A2C:4D7E.0005: input,hiddev98: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-fe3a0000.usb-1/input1

此时可以在ubuntu桌面系统测试键盘,可以发现是可以正常使用的。

USB键盘工作在低速模式下,OHCI控制器,USB1.0通信协议,使用的USB总线编号为1,设备编号为2。

(2) 拔掉USB键盘,尝试将USB键盘接到USB3.0 Host Type-A接口(对应开发板上的CON5),在内核日志中,找到USB键盘信息的日志:

[ 1665.652164] usb 1-1: USB disconnect, device number 2
[ 1678.668389] usb 7-1: new low-speed USB device number 2 using xhci-hcd
[ 1678.822673] usb 7-1: New USB device found, idVendor=1a2c, idProduct=4d7e, bcdDevice= 1.10
[ 1678.822713] usb 7-1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[ 1678.822729] usb 7-1: Product: USB Keyboard
[ 1678.822743] usb 7-1: Manufacturer: SEMICO
[ 1678.850429] input: SEMICO USB Keyboard as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.0/0003:1A2C:4D7E.0006/input/input11
[ 1678.909715] hid-generic 0003:1A2C:4D7E.0006: input: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-xhci-hcd.1.auto-1/input0
[ 1678.921243] input: SEMICO USB Keyboard Consumer Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input12
[ 1678.981216] input: SEMICO USB Keyboard System Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input13
[ 1678.981907] input: SEMICO USB Keyboard as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.1/0003:1A2C:4D7E.0007/input/input15
[ 1678.982716] hid-generic 0003:1A2C:4D7E.0007: input,hiddev98: USB HID v1.10 Keyboard [SEMICO USB Keyboard] on usb-xhci-hcd.1.auto-1/input1

此时可以在ubuntu桌面系统测试键盘,可以发现是可以正常使用的。

USB键盘工作在低速模式下,xHCI控制器,USB1.0通信协议,使用的USB总线编号为7,设备编号为2。

3.3 测试USB摄像头

我们将USB摄像头接到开发板的USB3.0 Host Type-A接口(对应开发板上的CON5),在内核日志中,找到USB摄像头信息的日志:

[ 2305.074204] usb 7-1: USB disconnect, device number 2
[ 2323.296616] usb 7-1: new high-speed USB device number 3 using xhci-hcd
[ 2323.483982] usb 7-1: New USB device found, idVendor=0c45, idProduct=6340, bcdDevice= 0.00
[ 2323.484022] usb 7-1: New USB device strings: Mfr=2, Product=1, SerialNumber=0
[ 2323.484038] usb 7-1: Product: USB 2.0 Camera
[ 2323.484052] usb 7-1: Manufacturer: Sonix Technology Co., Ltd.
[ 2323.495745] usb 7-1: Found UVC 1.00 device USB 2.0 Camera (0c45:6340)
[ 2323.519918] input: USB 2.0 Camera: USB Camera as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1:1.0/input/input16

USB键盘工作在高速模式下,xHCI控制器,USB2.0通信协议,使用的USB总线编号为7,设备编号为2。

从上面的信息可以看到这里,已经识别到了我们的USB摄像头,VID=0c45PID=6340

安装应用程序茄子:

root@rk3399:/# sudo apt-get install cheese

ubuntu输入cheese命令捕捉视频:

root@rk3399:/# cheese

如图所示:

3.4 测试移动硬盘

准备好一个移动硬盘,注意移动硬盘要为NFTS格式的!NTFSexFAT由于版权问题所以在Linux下支持的不完善,操作的话可能会有问题,比如只能读,不能写或者无法识别等。

准备好以后将移动硬盘插入到开发板USB3.0 Host Type-A接口(对应开发板上的CON5),在内核日志中,找到移动硬盘信息的日志:

[ 3341.772611] usb 7-1: USB disconnect, device number 3
[ 3393.909693] usb 8-1: new SuperSpeed USB device number 2 using xhci-hcd
[ 3393.932045] usb 8-1: New USB device found, idVendor=0480, idProduct=b200, bcdDevice= 1.00
[ 3393.932085] usb 8-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1
[ 3393.932102] usb 8-1: Product: External USB 3.0
[ 3393.932115] usb 8-1: Manufacturer: TOSHIBA
[ 3393.932129] usb 8-1: SerialNumber: 2018010302552D
[ 3393.936501] usb-storage 8-1:1.0: USB Mass Storage device detected
[ 3393.937468] scsi host0: usb-storage 8-1:1.0
[ 3394.970703] scsi 0:0:0:0: Direct-Access     TOSHIBA  External USB 3.0 0    PQ: 0 ANSI: 6
[ 3394.972008] sd 0:0:0:0: Attached scsi generic sg0 type 0
[ 3394.973469] sd 0:0:0:0: [sda] Spinning up disk...
[ 3395.993613] ...ready
[ 3398.068783] sd 0:0:0:0: [sda] 1953525168 512-byte logical blocks: (1.00 TB/932 GiB)
[ 3398.069873] sd 0:0:0:0: [sda] Write Protect is off
[ 3398.069891] sd 0:0:0:0: [sda] Mode Sense: 43 00 00 00
[ 3398.071119] sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA
[ 3398.114863]  sda: sda1 sda2 sda3 sda4 < sda5 >
[ 3398.116779] sd 0:0:0:0: [sda] Attached SCSI disk

移动硬盘工作在超高速模式下,xHCI控制器,USB3.0通信协议,使用的USB总线编号为8,设备编号为2。

可以看出,系统检测到移动硬盘插入,大小为1TB,对应的设备文件为/dev/sda/dev/sda1~5,大家可以查看一下/dev目录下有没有sdasda1~5这6个文件;

root@rk3399:/# ll /dev/sda*
brw-rw---- 1 root disk 8, 0 Sep 16 15:28 /dev/sda
brw-rw---- 1 root disk 8, 1 Sep 16 15:28 /dev/sda1
brw-rw---- 1 root disk 8, 2 Sep 16 15:28 /dev/sda2
brw-rw---- 1 root disk 8, 3 Sep 16 15:28 /dev/sda3
brw-rw---- 1 root disk 8, 4 Sep 16 15:28 /dev/sda4
brw-rw---- 1 root disk 8, 5 Sep 16 15:28 /dev/sda5

其中:

  • /dev/sda:是整个移动硬盘;
  • /dev/sda1~5: 是移动硬盘的第1个到第5个分区,这是是由于我在PC上已经将移动硬盘分了5个分区;

(1) 要想访问移动硬盘我们需要先对移动硬盘进行挂载,理论上挂载到任意一个目录下都可以.

测试发现ubuntu系统会自动将移动硬盘下的各个分区挂载到/media/root下;

root@rk3399:/media/root# df -T
Filesystem     Type     1K-blocks     Used Available Use% Mounted on
/dev/root      ext4      14801956  4998424   9143588  36% /
devtmpfs       devtmpfs   1950140        0   1950140   0% /dev
tmpfs          tmpfs      1972572        0   1972572   0% /dev/shm
tmpfs          tmpfs       394516     1760    392756   1% /run
tmpfs          tmpfs         5120        4      5116   1% /run/lock
tmpfs          tmpfs      1972572        0   1972572   0% /sys/fs/cgroup
tmpfs          tmpfs       394512       16    394496   1% /run/user/0
/dev/sda3      fuseblk  209715196 14878708 194836488   8% /media/root/小白PE工具盘1
/dev/sda5      fuseblk  347613180 14758876 332854304   5% /media/root/小白PE工具盘
/dev/sda2      fuseblk  209715196 42328260 167386936  21% /media/root/程序
/dev/sda1      fuseblk  209715196 13973916 195741280   7% /media/root/学业

(2) 这里我创建一个/mnt/usb_disk目录,然后将移动硬盘第一个分区挂载到/mnt/usb_disk目录下,命令如下:

root@rk3399:/# mkdir -p /mnt/usb_disk 
root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8

其中:

  • -t ntfs:指定挂载所使用的文件系统类型,这里设置为ntfs,也就是NTFS文件系统;
  • -o iocharset=utf8:设置硬盘编码格式为utf8,否则的话移动硬盘里面的中文会显示乱码;

如果挂载的时候出现如下错误:

root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8
Mount is denied because the NTFS volume is already exclusively opened.
The volume may be already mounted, or another software may use it which
could be identified for example by the help of the 'fuser' command.

通过错误语句的输出可以知道NTFS卷被拒绝是因为已经执行打开,可能已经被挂载或者有应用程序正在使用它,可以使用fuser命令显示正在使用指定的filefile system或者socket的进程信息。

fuser -m -u /dev/sda1 使用-m -u显示正在使用/dev/sda1的进程PID以及用户名称,如我输入上述命令后显示的情况:

root@rk3399:/# fuser -m -u /dev/sda1
/dev/sda1:            5168(root)
root@rk3399:/# kill 5168

表明是PID为5168的进程正在使用它,可以使用kill命令杀死该进程,此时在使用mount命令就不会出错了。

挂载成功以后进入到/mnt/usb_disk目录下,输入ls命令查看移动硬盘文件;

root@rk3399:/# cd /mnt/usb_disk/
root@rk3399:/mnt/usb_disk# ll
total 60
drwxrwxrwx 1 root root  8192 Jun 22  2021 '$RECYCLE.BIN'/
drwxrwxrwx 1 root root 12288 Jun 22  2021  ./
drwxr-xr-x 3 root root  4096 Sep 16 15:37  ../
drwxrwxrwx 1 root root  4096 Jun 22  2021  1.led/
drwxrwxrwx 1 root root  4096 Jun 22  2021  3.myboot/
drwxrwxrwx 1 root root  4096 Jun 22  2021  4.mmu/
drwxrwxrwx 1 root root  4096 Jun 22  2021  5.nadflash/
drwxrwxrwx 1 root root  8192 Jun 22  2021  6.interupt/
drwxrwxrwx 1 root root  4096 Jun 22  2021  7.uart/
drwxrwxrwx 1 root root  4096 Jun 22  2021  8.do_bootm_linux/
drwxrwxrwx 1 root root  4096 Dec 22  2021 'System Volume Information'/

至此移动硬盘就能正常读写操作了,直接对/mnt/usb_disk目录进行操作就行了。如果要拔出移动硬盘要执行一个sync命令进行同步,然后在使用unmount进行移动硬盘卸载,命令如下所示:

root@rk3399:/mnt/usb_disk# sync 		
root@rk3399:/mnt/usb_disk# cd / 		
root@rk3399:/# umount /mnt/usb_disk

3.5 测试Type-C触摸屏

现在我手里有一个NanoPC-T4开发板,同时还有一个15.6英寸HDMI接口显示屏,并且该显示屏支持Type-C十点触摸。

(1) 配置USB3.0/2.0 OTG0的工作模式为Host(主机),这种做法只会临时有效:

root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
host

如果想永久有效,可以通过修改设备树dr-mode = host将工作配置为Host(主机);具体可以参考:《Rockchip RK3399 - USB触摸屏接口驱动》。

(2) 这里我们通过Type-C线(两端都是Type-C接口)将开发板USB3.0 Type-C接口(对应开发板上的Type-C/DP)与触摸屏的Type-C接口连接起来。内核输出日志信息:

[ 2358.710215] usb 4-1: new full-speed USB device number 2 using xhci-hcd
[ 2358.862485] usb 4-1: New USB device found, idVendor=222a, idProduct=0001, bcdDevice= 1.00
[ 2358.862525] usb 4-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[ 2358.862542] usb 4-1: Product: SingWon-CTP-V1.18A
[ 2358.862555] usb 4-1: Manufacturer: UsbHID
[ 2358.862569] usb 4-1: SerialNumber: 6F6A099B1133
[ 2358.899245] input: UsbHID SingWon-CTP-V1.18A as /devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-1/4-1:1.0/0003:222A:0001.0003/input/input6
[ 2358.899571] hid-generic 0003:222A:0001.0003: input: USB HID v1.11 Device [UsbHID SingWon-CTP-V1.18A] on usb-xhci-hcd.0.auto-1/input0
[ 2358.903930] input: UsbHID SingWon-CTP-V1.18A as /devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-1/4-1:1.1/0003:222A:0001.0004/input/input7
[ 2358.966870] hid-generic 0003:222A:0001.0004: input: USB HID v1.12 Keyboard [UsbHID SingWon-CTP-V1.18A] on usb-xhci-hcd.0.auto-1/input1

此时可以在ubuntu桌面系统测试触摸屏,可以发现触摸屏可以正常实用。

USB触摸屏工作在全速模式下,xHCI控制器,USB1.1通信协议,使用的USB总线编号为4,设备编号为2。

3.6 测试USB 4口HUB集线器

这里我们将USB 4口HUB集线器里连接到开发板USB3.0 Host Type-A接口(对应开发板上的CON5)。内核输出日志信息:

[  232.825153] usb 7-1: new high-speed USB device number 4 using xhci-hcd
[  232.975149] usb 7-1: New USB device found, idVendor=14cd, idProduct=8601, bcdDevice= 0.00
[  232.975188] usb 7-1: New USB device strings: Mfr=1, Product=3, SerialNumber=0
[  232.975204] usb 7-1: Product: USB 2.0 Hub
[  232.975218] usb 7-1: Manufacturer: USB Device
[  233.011052] hub 7-1:1.0: USB hub found
[  233.011213] hub 7-1:1.0: 4 ports detected

USB键盘工作在高速模式下,xHCI控制器,USB2.0通信协议,使用的USB总线编号为7,设备编号为4。

从上面的信息可以看到这里,已经识别到了我们的USB 4口HUB集线器,VID=14cdPID=8601,并且有4个端口。

我们尝试在将USB鼠标插入HUB其中一个端口,内核输出日志信息:

[  450.823397] usb 7-1.1: new full-speed USB device number 5 using xhci-hcd
[  450.928638] usb 7-1.1: New USB device found, idVendor=046d, idProduct=c52b, bcdDevice=24.11
[  450.928677] usb 7-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[  450.928694] usb 7-1.1: Product: USB Receiver
[  450.928707] usb 7-1.1: Manufacturer: Logitech
[  451.031478] input: Logitech USB Receiver as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.0/0003:046D:C52B.0006/input/input11
[  451.092719] hid-generic 0003:046D:C52B.0006: input: USB HID v1.11 Keyboard [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input0
[  451.099030] input: Logitech USB Receiver Mouse as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input12
[  451.099733] input: Logitech USB Receiver Consumer Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input13
[  451.160075] input: Logitech USB Receiver System Control as /devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-1/7-1.1/7-1.1:1.1/0003:046D:C52B.0007/input/input14
[  451.160547] hid-generic 0003:046D:C52B.0007: input,hiddev97: USB HID v1.11 Mouse [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input1
[  451.165557] hid-generic 0003:046D:C52B.0008: hiddev98: USB HID v1.11 Device [Logitech USB Receiver] on usb-xhci-hcd.1.auto-1.1/input2

此时可以在ubuntu桌面系统测试鼠标,可以发现是可以正常使用的。

USB鼠标工作在全速模式下,xHCI控制器,USB1.1通信协议,使用的USB总线编号为7,设备编号为5。

四、 模拟USB设备

4.1 模拟存储设备

我们需要按照前面的内核配置将USB Gadget precomposed configurations ---> Mass Storage Gadget驱动编译成模块。使用的时候直接输入命令加载驱动即可。

(1) 配置好以后重新linux内核,会得到三个.ko驱动文件:

drivers/usb/gadget/libcomposite.ko
drivers/usb/gadget/function/usb_f_mass_storage.ko
drivers/usb/gadget/legacy/g_mass_storage.ko

(2) 重新烧录内核,启动开发板。将上述三个.ko模块拷贝到开发板/lib/modules/6.3.0(如果没有该目录,自行创建),命令如下:

root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/modules.builtin  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/modules.order  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/libcomposite.ko  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/usb_f_mass_storage.ko  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/legacy/g_mass_storage.ko  /lib/modules/6.3.0

(3) 在开发板插入一个移动硬盘到我们的USB3.0 Host Type-A接口,并使用Type-C连接线,并按照之前介绍的将/dev/sda1分区挂载到/mnt/usb_disk目录下;

root@rk3399:/# mount /dev/sda1 /mnt/usb_disk/ -t ntfs -o iocharset=utf8

最后将开发板USB3.0 Type-C接口与PC连接起来。

(4) 配置USB3.0/2.0 OTG0的工作模式为Device(设备),这种做法只会临时有效:

root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device

如果想永久有效,可以通过修改设备树dr-mode = peripheral将工作配置为Device(设备);

(5) 需要在加载模块之前建立该模块的依赖关系,也即必须用depmod来更新一下/lib/modules/linux-6.3/modules.dep文件;

root@rk3399:/lib/modules/6.3.0# cd /lib/modules/6.3.0
root@rk3399:/lib/modules/6.3.0# depmod -a
root@rk3399:/lib/modules/6.3.0# modprobe libcomposite
root@rk3399:/lib/modules/6.3.0# modprobe usb_f_mass_storage
root@rk3399:/lib/modules/6.3.0# modprobe g_mass_storage file=/dev/sda1 removable=1

modprobeinsmode的区别在于modprobe可以动态加载依赖的驱动,而insmode必须一个一个加载。加载g_mass_storage的时候使用file参数指定使用的大容量存储设备对应的/dev/sda1。同时内核会输出如下日志:

[  390.786425] Mass Storage Function, version: 2009/09/11
[  390.786459] LUN: removable file: (no medium)
[  390.786724] LUN: removable file: /dev/sda1
[  390.786743] Number of LUNs=1
[  390.786975] g_mass_storage gadget.0: Mass Storage Gadget, version: 2009/09/11
[  390.786995] g_mass_storage gadget.0: userspace failed to provide iSerialNumber
[  390.787005] g_mass_storage gadget.0: g_mass_storage ready

通过命令可以查看我们已经加载的驱动:

root@rk3399:/lib/modules/6.3.0# lsmod
Module                  Size  Used by
#### 下面是我们刚才加载的 ######
g_mass_storage         16384  0
usb_f_mass_storage     69632  2 g_mass_storage
libcomposite           81920  2 usb_f_mass_storage,g_mass_storage
#### 下面是wifi相关的,忽略即可 #####
brcmfmac_wcc           16384  0
brcmfmac              348160  1 brcmfmac_wcc
cfg80211              901120  1 brcmfmac
brcmutil               24576  1 brcmfmac

如果加载成功的话PC就会出现一个移动硬盘,如下图所示:

Rockchip RK3399 - USB调试_第2张图片

(6) 我们可以直接在电脑上对这个移动硬盘进行读写操作,实际上操作的就是我们的移动硬盘,操作完成以后要退出的话执行如下命令:

root@rk3399:/lib/modules/6.3.0# rmmod g_mass_storage

4.2 模拟声卡

我们需要按照前面的内核配置将USB Gadget precomposed configurations ---> Audio Gadget驱动编译成模块。使用的时候直接输入命令加载驱动即可。

(1) 配置好以后重新linux内核,会得到5个.ko驱动文件:

drivers/usb/gadget/libcomposite.ko
drivers/usb/gadget/function/usb_f_uac1.ko
drivers/usb/gadget/function/u_audio.ko
drivers/usb/gadget/legacy/g_audio.ko

(2) 重新烧录内核,启动开发板。将上述5个.ko模块拷贝到开发板/lib/modules/6.3.0(如果没有该目录,自行创建),命令如下:

root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/modules.builtin  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/modules.order  /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/libcomposite.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/usb_f_uac1.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/function/u_audio.ko /lib/modules/6.3.0
root@rk3399:/lib# scp -r [email protected]:/work/sambashare/rk3399/linux-6.3/drivers/usb/gadget/legacy/g_audio.ko /lib/modules/6.3.0

(3) 首先按照我们之前声卡驱动移植章节介绍的,保证声卡可以正常播放。

使用Type-C连接线,将开发板USB3.0 Type-C接口与PC连接起来。

(4) 配置USB3.0/2.0 OTG0的工作模式为Device(设备),这种做法只会临时有效:

root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device

如果想永久有效,可以通过修改设备树dr-mode = peripheral将工作配置为Device(设备);

(5) 需要在加载模块之前建立该模块的依赖关系,也即必须用depmod来更新一下/lib/modules/linux-6.3/modules.dep文件;

root@rk3399:~# cd /lib/modules/6.3.0
root@rk3399:/lib/modules/6.3.0# depmod -a
root@rk3399:/lib/modules/6.3.0# modprobe libcomposite
root@rk3399:/lib/modules/6.3.0# modprobe u_audio
root@rk3399:/lib/modules/6.3.0# modprobe usb_f_uac1
root@rk3399:/lib/modules/6.3.0# modprobe g_audio

modprobeinsmode的区别在于modprobe可以动态加载依赖的驱动,而insmode必须一个一个加载。内核会输出如下日志:

[ 1863.468513] g_audio gadget.0: Linux USB Audio Gadget, version: Feb 2, 2012
[ 1863.468535] g_audio gadget.0: g_audio ready

通过命令可以查看我们已经加载的驱动:

root@rk3399:/lib/modules/6.3.0# lsmod
Module                  Size  Used by
#### 下面是我们刚才加载的 ######
g_audio                16384  0
usb_f_uac1             36864  0
u_audio                32768  2 usb_f_uac1,usb_f_uac2
libcomposite           81920  5 usb_f_uac1,u_audio,g_audio,usb_f_mass_storage,usb_f_uac2
#### 下面是wifi相关的,忽略即可 #####
brcmfmac_wcc           16384  0
brcmfmac              348160  1 brcmfmac_wcc
cfg80211              901120  1 brcmfmac
brcmutil               24576  1 brcmfmac

加载完成以后稍等一会虚拟出一个USB声卡,打开电脑的设备管理器,选择声音、视频和游戏控制器,会出现有一个名为Source/Sink设备,如下图所示:

Rockchip RK3399 - USB调试_第3张图片

选择该设备,并通过PC播放音乐,不过这里我测试始终没有声音输出,具体原因还不太清除;

Rockchip RK3399 - USB调试_第4张图片

(6) 移除驱动:

root@rk3399:/lib/modules/6.3.0# rmmod g_audio

五、调试接口

5.1 USB Gadget Configfs

之前我们介绍了如何模拟一个存储设备、声卡设备;此外还可以通过USB Gadget Configfs来实现同样的功能。

5.1.1 挂载configfs

首先需要挂载configfs/config目录下:

root@rk3399:/# mkdir /config
root@rk3399:/# mount -t configfs none /config

挂载完成后,会在/config目录下生成usb_gadget目录。

创建g1文件夹,创建完g1之后,会在该目录下生成很多配置目录;

root@rk3399:/# cd /config/usb_gadget/
root@rk3399:/config/usb_gadget# mkdir -p g1
root@rk3399:/config/usb_gadget# ll g1/
-rw-r--r-- 1 root root 4096 Sep 17 22:16 UDC
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceClass
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceProtocol
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bDeviceSubClass
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bMaxPacketSize0
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bcdDevice
-rw-r--r-- 1 root root 4096 Sep 17 22:16 bcdUSB
drwxr-xr-x 2 root root    0 Sep 17 22:16 configs/
drwxr-xr-x 2 root root    0 Sep 17 22:16 functions/
-rw-r--r-- 1 root root 4096 Sep 17 22:16 idProduct
-rw-r--r-- 1 root root 4096 Sep 17 22:16 idVendor
-rw-r--r-- 1 root root 4096 Sep 17 22:16 max_speed
drwxr-xr-x 2 root root    0 Sep 17 22:16 os_desc/
drwxr-xr-x 2 root root    0 Sep 17 22:16 strings/
drwxr-xr-x 2 root root    0 Sep 17 22:16 webusb/

这里的g1表示gadget 1,一个UDC对应一个gadget ,如果SoC上有多个gadget,可以创建多个gx目录。

5.1.2 配置g1

(1) 配置PIDVID

echo 0x1a2c > /config/usb_gadget/g1/idVendor
echo 0x4d7e > /config/usb_gadget/g1/idProduct

(2) 创建并配置string字目录:

mkdir /config/usb_gadget/g1/strings/0x409
echo "0" > /config/usb_gadget/g1/strings/0x409/serialnumber
echo "SEMICO" > /config/usb_gadget/g1/strings/0x409/manufacturer
echo "USB Keyboard" > /config/usb_gadget/g1/strings/0x409/product

上面的配置信息大部分都是从USB键盘设备信息中拷贝过来的。

(3) 创建configuration和字符串:

mkdir /config/usb_gadget/g1/configs/c.1
mkdir /config/usb_gadget/g1/configs/c.1/strings/0x409
echo "mass_storage" > /config/usb_gadget/g1/configs/c.1/strings/0x409/configuration

这里的mass_storage的名字不能随便起,需要根据modprobefunction驱动usb_f_mass_storage.ko来决定,否则会出现错误。

(4) 创建functions

mkdir /config/usb_gadget/g1/functions/mass_storage.0

(5) 将functionsconfiguration关联起来:

ln -s /config/usb_gadget/g1/functions/mass_storage.0 /config/usb_gadget/g1/configs/c.1

上述配置之后,得到的结果为:

root@rk3399:/config# find .
.
./usb_gadget
./usb_gadget/g1
./usb_gadget/g1/webusb
./usb_gadget/g1/webusb/landingPage
./usb_gadget/g1/webusb/bVendorCode
./usb_gadget/g1/webusb/bcdVersion
./usb_gadget/g1/webusb/use
./usb_gadget/g1/os_desc
./usb_gadget/g1/os_desc/qw_sign
./usb_gadget/g1/os_desc/b_vendor_code
./usb_gadget/g1/os_desc/use
./usb_gadget/g1/strings
./usb_gadget/g1/strings/0x409
./usb_gadget/g1/strings/0x409/serialnumber
./usb_gadget/g1/strings/0x409/product
./usb_gadget/g1/strings/0x409/manufacturer
./usb_gadget/g1/configs
./usb_gadget/g1/configs/c.1
./usb_gadget/g1/configs/c.1/strings
./usb_gadget/g1/configs/c.1/strings/0x409
./usb_gadget/g1/configs/c.1/strings/0x409/configuration
./usb_gadget/g1/configs/c.1/bmAttributes
./usb_gadget/g1/configs/c.1/MaxPower
./usb_gadget/g1/functions
./usb_gadget/g1/functions/mass_storage.0
./usb_gadget/g1/functions/mass_storage.0/lun.0
./usb_gadget/g1/functions/mass_storage.0/lun.0/forced_eject
./usb_gadget/g1/functions/mass_storage.0/lun.0/inquiry_string
./usb_gadget/g1/functions/mass_storage.0/lun.0/nofua
./usb_gadget/g1/functions/mass_storage.0/lun.0/cdrom
./usb_gadget/g1/functions/mass_storage.0/lun.0/removable
./usb_gadget/g1/functions/mass_storage.0/lun.0/ro
./usb_gadget/g1/functions/mass_storage.0/lun.0/file
./usb_gadget/g1/functions/mass_storage.0/stall
./usb_gadget/g1/max_speed
./usb_gadget/g1/UDC
./usb_gadget/g1/bcdUSB
./usb_gadget/g1/bcdDevice
./usb_gadget/g1/idProduct
./usb_gadget/g1/idVendor
./usb_gadget/g1/bMaxPacketSize0
./usb_gadget/g1/bDeviceProtocol
./usb_gadget/g1/bDeviceSubClass
./usb_gadget/g1/bDeviceClass

(6) 配置USB3.0/2.0 OTG0的工作模式为Device(设备):

root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
otg
root@rk3399:/lib/modules/6.3.0# echo device > /sys/kernel/debug/usb/fe800000.usb/mode
root@rk3399:/lib/modules/6.3.0# cat /sys/kernel/debug/usb/fe800000.usb/mode
device

(7) 查看当前的UDC,可见开发板上有1个UDCfe800000.usb

root@rk3399:/config# ll /sys/class/udc/
total 0
drwxr-xr-x  2 root root 0 Mar 15  2023 ./
drwxr-xr-x 78 root root 0 Mar 15  2023 ../
lrwxrwxrwx  1 root root 0 Sep 17 23:37 fe800000.usb -> '../../devices/platform/usb@fe800000/fe800000.usb/udc/fe800000.usb'/

配置当前gadget对应的USB OTG控制器, 执行如下命令;

echo fe800000.usb > /config/usb_gadget/g1/UDC
5.1.3 验证

使用Type-C连接线,将开发板USB3.0 Type-C接口与PC连接起来。

Rockchip RK3399 - USB调试_第5张图片

上述的结果是只识别到一个mass storage的设备,但是没有看到相应的磁盘信息。想要看到磁盘信息,可以更进一步的设置mass_storagebacken file属性。

5.1.4 补充

除了USB Gadget Configfs之外,我又发现了一种模拟存储设备、声卡设备的方法,具体可以参考《zynqusb gadget模拟网口、U盘、串口》。

5.2 sysfs

5.2.1 USB设备

所有USB设备可以在/sys/bus/usb/devices下找到;

root@rk3399:/# ll /sys/bus/usb/devices
total 0
drwxr-xr-x 2 root root 0 Mar 15  2023 ./
drwxr-xr-x 4 root root 0 Mar 15  2023 ../
lrwxrwxrwx 1 root root 0 Mar 15  2023 1-0:1.0 -> ../../../devices/platform/fe3a0000.usb/usb1/1-0:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1:1.0 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:50 1-1:1.1 -> ../../../devices/platform/fe3a0000.usb/usb1/1-1/1-1:1.1/
lrwxrwxrwx 1 root root 0 Mar 15  2023 2-0:1.0 -> ../../../devices/platform/fe3c0000.usb/usb2/2-0:1.0/
lrwxrwxrwx 1 root root 0 Mar 15  2023 3-0:1.0 -> ../../../devices/platform/fe3e0000.usb/usb3/3-0:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.0 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.0/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.1 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.1/
lrwxrwxrwx 1 root root 0 Sep 16 21:31 3-1:1.2 -> ../../../devices/platform/fe3e0000.usb/usb3/3-1/3-1:1.2/
lrwxrwxrwx 1 root root 0 Mar 15  2023 4-0:1.0 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4/4-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 5-0:1.0 -> ../../../devices/platform/fe380000.usb/usb5/5-0:1.0/
lrwxrwxrwx 1 root root 0 Mar 15  2023 6-0:1.0 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb6/6-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 7-0:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7/7-0:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 8-0:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-0:1.0'/
lrwxrwxrwx 1 root root 0 Sep 16 22:03 8-1 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-1'/
lrwxrwxrwx 1 root root 0 Sep 16 22:03 8-1:1.0 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8/8-1/8-1:1.0'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb1 -> ../../../devices/platform/fe3a0000.usb/usb1/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb2 -> ../../../devices/platform/fe3c0000.usb/usb2/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb3 -> ../../../devices/platform/fe3e0000.usb/usb3/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb4 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb4'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb5 -> ../../../devices/platform/fe380000.usb/usb5/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb6 -> '../../../devices/platform/usb@fe800000/fe800000.usb/xhci-hcd.0.auto/usb6'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb7 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb7'/
lrwxrwxrwx 1 root root 0 Mar 15  2023 usb8 -> '../../../devices/platform/usb@fe900000/fe900000.usb/xhci-hcd.1.auto/usb8'/

如上图所示,可以看到大量的USB设备。取名规则如下:

bus-port.port:configuration.interface

其中:

  • bus:表示USB控制器所连接的总线编号;从1开始编号;
  • port:表示总线上的硬件端口号;从0开始编号;
  • port:如果总线上的硬件端口连接的设备是一个HUB,那么该port表示连接在HUB上的硬件端口号;从1开始编号;
  • configuration:表示设备的配置值;从1开始编号;
  • interface:表示设备的接口号;从0开始编号;

比如1-1:1.1具有以下含义:

  • 1-1:表示连接到第一个USB控制器的编号为1的硬件端口;
  • 1.1:表示设备的第一个配置(configuration)编号为1接口(interface)。

7-1.2:1.0具有以下含义:

  • 7-1.2:表示连接到第7个USB控制器的编号为1的硬件端口连接了一个HUBHUB编号为2的硬件端口上连接了一个设备;
  • 1.0:表示设备的第一个配置(configuration)编号为0接口(interface)。
5.2.2 USB设备信息

我们可以查看USB设备PIDVID

root@rk3399:/sys/bus/usb/devices# ls
1-0:1.0  1-1:1.0  2-0:1.0  3-1      3-1:1.1  4-0:1.0  6-0:1.0  8-0:1.0  8-1:1.0  usb2  usb4  usb6  usb8
1-1      1-1:1.1  3-0:1.0  3-1:1.0  3-1:1.2  5-0:1.0  7-0:1.0  8-1      usb1     usb3  usb5  usb7
root@rk3399:/sys/bus/usb/devices# ls 8-1/id*
8-1/idProduct  8-1/idVendor
root@rk3399:/sys/bus/usb/devices# cat 8-1/idVendor
0480
root@rk3399:/sys/bus/usb/devices# cat 8-1/idProduct
b200
root@rk3399:/sys/bus/usb/devices# cat 8-1/manufacturer
TOSHIBA
root@rk3399:/sys/bus/usb/devices# cat 8-1/product
External USB 3.0
root@rk3399:/sys/bus/usb/devices# cat 8-1/version
 3.00

VID=0480PID=b200对应的使我们移动硬盘。

1个USB设备可能会有多个接口,比如:

root@rk3399:/sys/bus/usb/devices# ls 1-1/1-1\:1.
1-1:1.0/ 1-1:1.1/

目录l-1存放的是USB设备信息,1-1:1.01-1:1.1目录下存放的相应接口的信息;

5. 3 debugfs

USB调试信息位于/sys/kernel/debug/usb

root@rk3399:~# ll /sys/kernel/debug/usb
-r--r--r--  1 root root 0 Jan  1  1970 devices
drwxr-xr-x  4 root root 0 Jan  1  1970 ehci/
drwxr-xr-x  2 root root 0 Jan  1  1970 fe800000.usb/
drwxr-xr-x  2 root root 0 Jan  1  1970 fe900000.usb/
drwxr-xr-x  2 root root 0 Jan  1  1970 fusb302-4-0022/
drwxr-xr-x  4 root root 0 Jan  1  1970 ohci/
drwxr-xr-x  2 root root 0 Jan  1  1970 tcpm-4-0022/
drwxr-xr-x  2 root root 0 Jan  1  1970 uvcvideo/
drwxr-xr-x  4 root root 0 Jan  1  1970 xhci/

其中:

  • devices:该文件列出了当前系统中已连接的USB设备的详细信息;
  • ehci:该目录包含EHCI主机控制器接口的调试信息;
  • fe800000.usb:该目录包含与fe800000.usb控制器相关的调试信息;
  • fe900000.usb:该目录包含与fe900000.usb控制器相关的调试信息。
  • fusb302-4-0022:该目录包含与fusb302-4-0022设备相关的调试信息,4位I2C总线编号,0022为I2C设备地址;
  • ohci:该目录包含OHCI主机控制器接口的调试信息;
  • tcpm-4-0022:该目录包含与tcpm-4-0022设备相关的调试信息,4位I2C总线编号,0022为I2C设备地址;
  • uvcvideo:该目录包含与uvcvideo(USB Video ClassUSB视频类)驱动程序相关的调试信息;
  • xhci:该目录包含XHCI主机控制器的调试信息;
5.3.1 查看工作模式

USB3.0/2.0 OTG0(DWC3/xHCI)控制器为例,对应设备节点usbdrd3_0: usb@fe800000

root@rk3399:~# ll /sys/kernel/debug/usb/fe800000.usb/
-rw-r--r--  1 root root 0 Jan  1  1970 link_state
-rw-r--r--  1 root root 0 Jan  1  1970 lsp_dump
-rw-r--r--  1 root root 0 Jan  1  1970 mode
-r--r--r--  1 root root 0 Jan  1  1970 regdump
-rw-r--r--  1 root root 0 Jan  1  1970 testmode

其中:

  • link_state:打印DWC3的链路状态;
  • regdump:打印DWC3控制器的寄存器状态信息;
  • mode:打印DWC3的工作模式;
  • testmode:设置DWC3HighSpeed的测试模式,用于眼图测试;

我们可以查看USB3.0/2.0 OTG0USB3.0/2.0 OTG1控制器的工作模式:

root@rk3399:~# cat /sys/kernel/debug/usb/fe800000.usb/mode      # OTG0 对应开发板Type-C/DP接口
otg
root@rk3399:~# cat /sys/kernel/debug/usb/fe900000.usb/mode      # OTG1  对应开发板CON5接口
host
5.3.2 查看xhci
root@rk3399:/# ll /sys/kernel/debug/usb/xhci/
drwxr-xr-x  6 root root 0 Jan  1  1970 xhci-hcd.0.auto/
drwxr-xr-x  6 root root 0 Jan  1  1970 xhci-hcd.1.auto/
root@rk3399:/# ll /sys/kernel/debug/usb/xhci/xhci-hcd.0.auto/
drwxr-xr-x 2 root root 0 Jan  1  1970 command-ring/
drwxr-xr-x 2 root root 0 Jan  1  1970 devices/
drwxr-xr-x 2 root root 0 Jan  1  1970 event-ring/
drwxr-xr-x 4 root root 0 Jan  1  1970 ports/
-r--r--r-- 1 root root 0 Jan  1  1970 reg-cap
-r--r--r-- 1 root root 0 Jan  1  1970 reg-ext-dbc:00
-r--r--r-- 1 root root 0 Jan  1  1970 reg-ext-legsup:00
-r--r--r-- 1 root root 0 Jan  1  1970 reg-ext-protocol:00
-r--r--r-- 1 root root 0 Jan  1  1970 reg-ext-protocol:01
-r--r--r-- 1 root root 0 Jan  1  1970 reg-op
-r--r--r-- 1 root root 0 Jan  1  1970 reg-runtime
5.3.3 查看ehci
root@rk3399:/# ll /sys/kernel/debug/usb/ehci/
drwxr-xr-x  2 root root 0 Jan  1  1970 fe380000.usb/
drwxr-xr-x  2 root root 0 Jan  1  1970 fe3c0000.usb/
root@rk3399:/# ll /sys/kernel/debug/usb/ehci/fe380000.usb/
-r--r--r-- 1 root root 0 Jan  1  1970 async
-r--r--r-- 1 root root 0 Jan  1  1970 bandwidth
-r--r--r-- 1 root root 0 Jan  1  1970 periodic
-r--r--r-- 1 root root 0 Jan  1  1970 registers
5.3.4 查看fusb302-4-0022
root@rk3399:/# ll /sys/kernel/debug/usb/fusb302-4-0022/
-r--r--r--  1 root root 0 Jan  1  1970 log
root@rk3399:/# cat /sys/kernel/debug/usb/fusb302-4-0022/log
[    3.588457] sw reset
[    3.589715] fusb302 device ID: 0x81
[    3.591218] pd := off
[    3.591222] vbus is already Off
[    3.591225] charge is already Off
[    3.591228] vconn is already Off
[    3.591588] pd header := Sink, Device
[    3.591658] cc1=Open, cc2=Open
[    3.593266] pd := off
[    3.593278] vbus is already Off
[    3.593283] charge is already Off
[    3.593288] vconn is already Off
[    3.593623] pd header := Sink, Device
[    3.593646] cc := Open
[    3.696903] start drp toggling
[    3.697640] IRQ: 0x80, a: 0x00, b: 0x00, status0: 0x83
[    3.697650] IRQ: VBUS_OK, vbus=On
[    3.698289] IRQ: 0x80, a: 0x00, b: 0x00, status0: 0x83
[    3.698298] IRQ: VBUS_OK, vbus=On
5.3.5 查看tcpm-4-0022
root@rk3399:/# ll /sys/kernel/debug/usb/tcpm-4-0022/
-r--r--r--  1 root root 0 Jan  1  1970 log
root@rk3399:/# cat /sys/kernel/debug/usb/tcpm-4-0022/log
[    3.589722] Setting usb_comm capable false
[    3.591231] Setting voltage/current limit 0 mV 0 mA
[    3.591241] polarity 0
[    3.591297] Requesting mux state 0, usb-role 0, orientation 0
[    3.591601] state change INVALID_STATE -> SNK_UNATTACHED [rev1 NONE_AMS]
[    3.591661] CC1: 0 -> 0, CC2: 0 -> 0 [state SNK_UNATTACHED, polarity 0, disconnected]
[    3.591669] 4-0022: registered
[    3.591681] Setting usb_comm capable false
[    3.593293] Setting voltage/current limit 0 mV 0 mA
[    3.593312] polarity 0
[    3.593318] Requesting mux state 0, usb-role 0, orientation 0
[    3.593641] cc:=0
[    3.595138] pending state change PORT_RESET -> PORT_RESET_WAIT_OFF @ 100 ms [rev1 NONE_AMS]
[    3.695257] state change PORT_RESET -> PORT_RESET_WAIT_OFF [delayed 100 ms]
[    3.695272] state change PORT_RESET_WAIT_OFF -> SNK_UNATTACHED [rev1 NONE_AMS]
[    3.695282] Start toggling
[    3.697687] VBUS

5.4 更改USB3.0/2.0 OTG工作模式

我们使用的开发板USB3.0 Type-C PHY1物理接口被设计为USB3.0 Host Type-A,这里我们做一个尝试,尝试将USB3.0/2.0 OTG1控制器工作模式也设置为otg(同时支持主机/设备)。

Rockchip官方手册介绍中描述到:USB Gadget driver内核架构只支持一个USB控制器配置为otg,这里我们测试一下看看能不能同时将USB3.0/2.0 OTG0USB3.0/2.0 OTG1控制器都配置为otg模式;

5.4.1 修改usbdrd_dwc3_1设备节点

修改arch/arm64/boot/dts/rockchip/rk3399-evb.dts设备节点usbdrd_dwc3_1设备节点:

&usbdrd_dwc3_1 {
	/* 配置dr_mode为otg */
	dr_mode = "otg";
	status = "okay";
};
5.4.2 测试

重新编译烧录内核并烧录,查看USB3.0/2.0 OTG0USB3.0/2.0 OTG1控制器的工作模式;

root@rk3399:~# cat /sys/kernel/debug/usb/fe800000.usb/mode      # OTG0 对应开发板Type-C/DP接口
otg
root@rk3399:~# cat /sys/kernel/debug/usb/fe900000.usb/mode      # OTG1  对应开发板CON5接口
otg

更改工作模式为Host(主机),这种做法只会临时有效:

root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe800000.usb/mode   
root@rk3399:/lib/modules/6.3.0# echo host > /sys/kernel/debug/usb/fe900000.usb/mode

然后将开发板CON5Type-C/DP这两个接口接上USB设备测试发现USB设备均无法正常工作,因此这里我又将usbdrd_dwc3_1dr_mode属性改回为otg

参考文章

[1] PD快充 - fusb302驱动调试笔记

[2] RK3399 Android7.1 USB模块中的控制器和PHY

[3] RK3399ANDROID7.1 USB TYPE-A的配置

[4] 超详细USB Type-C引脚信号及PCB布局布线介绍

[5] Rockchip_Developer_Guide_USB_CN.pdf

[6] Rockchip_RK3399_Developer_Guide_USB_DTS_CN.pdf

[7] RK平台如何配置USB功能

[8] 正点原子视频

[9] USB总线-Linux内核USB3.0设备控制器之dwc3 gadget驱动初始化过程分析(五)

[10] ipkvmRK3568 usb gadget

[11] linux usb gadget hid模拟鼠标键盘configfs

[12] LINUX嵌入式模拟键盘 2022-05-21

[13] usb hid gadget驱动

[14 ] RK3399驱动开发 | 18 - 使用usb3.0作为device模拟u

[15] linux driver probe deferral 机制

[16] usb gadget configfs 验证

[17] 6.61、USB如何模拟HID设备

你可能感兴趣的:(Rockchip RK3399 - USB调试)