Skip to main content
Graduate
February 7, 2024
Solved

STM32MP1 - OTG does not switch to host for data mode

  • February 7, 2024
  • 1 reply
  • 1589 views

Hey there,

I am trying to troubleshoot the following issue for quite some time now. I am working on an stm32mp157f based board attempting to enable a combination of stusb16xx and USB OTG . The behavior I am expecting to see is that when a usb device is connected to usbphyc_port1 (usb-c) it will get recognized in the same way as if it was on ehci but when a host device is connected to the same port I can trigger a gadget script in udev.rules. My current configuration works as expected for all gadget modes:

 

typec: stusb1600@28 {
		compatible = "st,stusb1600";
		reg = <0x28>;
		interrupts = <11 IRQ_TYPE_LEVEL_LOW>;
		interrupt-parent = <&gpioi>;
		
 vsys-supply = <&vdd_usb>;

		pinctrl-names = "default";
		pinctrl-0 = <&stusb1600_pins_a>;
		status = "okay";
		vdd-supply = <&vin>;

		typec_con: connector {
			compatible = "usb-c-connector";
			label = "USB-C";
			power-role = "dual";
			data-role = "dual";
			typec-power-opmode = "default";
				
			port {
				con_usbotg_hs_ep: endpoint {
					remote-endpoint = <&usbotg_hs_ep>;
				};
			};
		};
	};

&usbotg_hs {
	compatible = "st,stm32mp15-hsotg", "snps,dwc2";
	phys = <&usbphyc_port1 0>; /* 0: UTMI switch selects the OTG controller */
	phy-names = "usb2-phy";
	dr_mode = "otg";
	g-rx-fifo-size = <256>;
 g-np-tx-fifo-size = <32>;
 g-tx-fifo-size = <128 128 128 128 64 32 16 16>;
	usb-role-switch;
	role-switch-default-mode = "peripheral"; /* see USB generic bindings [4] */
	status = "okay"; /* enable OTG */
	
	port {
		usbotg_hs_ep: endpoint {
			remote-endpoint = <&con_usbotg_hs_ep>; 	 /* point the Type-C controller endpoint node */
		};
	};
};

 

To my understanding phys = <&usbphyc_port1 0>; will set the UTMI to OTG and dr_mode="otg" will set the mode in the same way.  In this configuration I can get the board recognized as a USB peripheral from other devices successfully. If I connect a peripheral device to the usb-c when the gadget is running the usb-c port will not provide any power as expected. If I stop the gadget and connect a peripheral the usb-c port will send the right power. Although this behavior looks correct according to the dts, no peripherals will get recognized in stlinux when the gadget is not running and a peripheral usb device is connected to the usb-c port. 

If I use the same phys to ehci and ohci then I will get the usb running only on host mode and all peripherals will get successfully detected in lsusb.

 

&usbh_ehci {
 phys = <&usbphyc_port0>, <&usbphyc_port1 1>;
 phy-names = "usb", "usb2-phy";
 status = "okay";
};

&usbh_ohci {
 status = "okay";
 phy-names = "usb", "usb2-phy";
 phys = <&usbphyc_port0>, <&usbphyc_port1 1>;
};

 

If I understand this correctly for recognizing USB 1.1 I need the OHCI host controller and for USB2.0 I need the EHCI controller. If this is the case in order for the OTG to work as expected I need to share <&usbphyc_port1> between usbotg_hs, usbh_ehci and usbh_ohci so when OTG performs a role switch the host part is managed by the USBH controllers. When attempting to share the same usbphyc between otg_hs and USBH I do not get OTG mode since the phy is already occupied before otg gets intialized:

 

[ 4.069548] stusb160x 2-0028: Failed to get port caps: -6
[ 4.108387] stm32-usbphyc 5a006000.usbphyc: phy port1 already used
[ 4.113359] dwc2 49000000.usb-otg: error -EBUSY: error getting phy

 

If I share the node with 0 UTMI flag as below:

 

&usbotg_hs {
	compatible = "st,stm32mp15-hsotg", "snps,dwc2";
	phys = <&usbphyc_port1 0>; /* 0: UTMI switch selects the OTG controller */
	phy-names = "usb2-phy";
	dr_mode = "otg";
	g-rx-fifo-size = <256>;
 g-np-tx-fifo-size = <32>;
 g-tx-fifo-size = <128 128 128 128 64 32 16 16>;
	usb-role-switch;
	role-switch-default-mode = "peripheral"; /* see USB generic bindings [4] */
	status = "okay"; /* enable OTG */
	
	port {
		usbotg_hs_ep: endpoint {
			remote-endpoint = <&con_usbotg_hs_ep>; 	 /* point the Type-C controller endpoint node */
		};
	};
};

&usbh_ehci {
 phys = <&usbphyc_port0>, <&usbphyc_port1 0>;
 phy-names = "usb", "usb2-phy";
 status = "okay";
};

&usbh_ohci {
 status = "okay";
 phy-names = "usb", "usb2-phy";
 phys = <&usbphyc_port0>, <&usbphyc_port1 0>;
};

 

I get all 3 entries recongized in lsusb but no peripherals recongised when connected.

Any ideas or pointers on how to debug this further are really appreciated.



    This topic has been closed for replies.
    Best answer by KChar.1

    After some time I found out that the SDA and SCL I2C lines of the stusb1600x were inverted. By correcting this in HW I was able to change data roles from the stusb160x driver or from user space with

    /sys/devices/platform/soc/49000000.usb-otg/usb_role/49000000.usb-otg-role-switch/role


    This has been part of a more complex solution described in this post.

    1 reply

    KChar.1AuthorAnswer
    Graduate
    February 23, 2024

    After some time I found out that the SDA and SCL I2C lines of the stusb1600x were inverted. By correcting this in HW I was able to change data roles from the stusb160x driver or from user space with

    /sys/devices/platform/soc/49000000.usb-otg/usb_role/49000000.usb-otg-role-switch/role


    This has been part of a more complex solution described in this post.