Showing results for 
Search instead for 
Did you mean: 

STM32MP1/STUSB1600 - DRP to DRP negotiation guidelines (no PD controller)


Hi there, 

I am working on an STM32MP157F-DK2 board and an STUSB1600 with hsotg gadget support and no PD controller. I am running a buildroot image with all the necessary drivers enabled including dwc2, SystemFS etc.  

The gadget is working as expected in most configurations. It can be hotplugged and get recognised with a high-speed unique address without any issues on several computers running windows or linux with a usb-c to usb-c cable . Recently I attempted to connect the board to a series of apple computers to test compatibility. I faced several unexpected behaviours during these tests. 

  • Apple Macbooks (Intel) will have a 50-50 chance of recognising the DK board as a peripheral. The rest of the times the DK is recognised as a charger and the MBP will start charging 
  • Apple Macbooks (M1) will still have a 50-50 chance of recognising the DK board as a peripheral but the rest of the gadget will not get recognised at all. 

  • Apple Mac Mini (M2) will not get recognised at all. The dwc2 otg driver will do several attempts always on address 1 until time-out. 

None of the above issues are present by using a usb-c to usb-A cable, usb Hub or usb-c to usb-A adapter. 

Following the Apple Accessory Design Guidelines it seems that any usb typec device is expected to work as long as it follows the Universal Serial Bus Type-C Cable and Connector Specification

I believe that a good hypothesis on the cause of the issue according to USB Type-C specification is hinted on

"In the special case of a DRP being attached to another DRP, an initialization protocol across the CC pins is used to establish the initial host-to-device relationship. Given no role-swapping intervention, the determination of which is DFP or UFP is random from the user’s perspective." 
Universal Serial Bus Type-C Cable and Connector Specification. Pg:34
More information on actual mechanisms on Pg: 200

It seems that the behaviour of the symptom is consistent with a random DRP to DRP negotiation between Apple machines and the DK board. In this particular application my goal is to create a mechanism that when the STUSB1600 detects a DRP or any DFP it always keeps the CC pins on UFP so the DK will always gets recognised as a peripheral in the case of a DRP to DRP connection. 

Following the stusb160x driver and the Device Tree Configuration guide I was not able to see an exposed entry or a direct modification that can account for such case. To my understanding all the dts entries on the typec connector will point to initial configurations but none of the available entries can achieve such behaviour.  I attach my current dts entries for both hsusbotg and stusb1600 below:


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"; //Advertise usb2 power capabilities (up to 500mV on PD negotiation)
           port {
               con_usbotg_hs_ep: endpoint {
                   remote-endpoint = <&usbotg_hs_ep>;



Board level


&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 = "peripheral";
   g-rx-fifo-size = <256>;
   g-np-tx-fifo-size = <32>;
   g-tx-fifo-size = <128 128 128 128 64 32 16 16>;
   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 */


I was wondering if I am missing a dts or software configuration that can handle DRP to DRP connections for the STUSB1600.

Any advice or ideas on this topic are highly appreciated. 

ST Employee

Hello @KChar.1,

I am afraid you are facing now an issue that is more than tricky right now. We passed months and months to debug a such USB-C issue like the one you have now.

So, let me summarize you our researches in few words :

  • New Apple devices (such as iPhone 12 or more / Apple MAC with M1 chip or newer) now integrates an eUSB2 to USB2 repeater that modify a bit the signal is formed on USB lanes.
  • To explain it briefly, the first bit formed by the repeater, that is supposed to be the first bit of the SYNC pattern seen by STM32MP15 PHY-C, has a random duration. It is not "out of spec" but in the gray zone.
  • Whatever, our PHY-C does not always recognize this first bit as a real bit if the frequency is too quick, and the result is that the packet is dropped, and note that we are talking about picoseconds delta for a packet passing or not passing.

So, now let's talk about what interest you, is there any solution ?
Well, difficult to say. We have a workaround that has much better result than the default behavior, it is composed of :

  • 1 SW modification
  • 1 HW modification

Both modifications are here to slow down a very little bit the speed of the first bit seen by our PHY-C, and then consider the USB packet as a valid packet.

SW modif :

Change the PHY-C tuning, by changing the following registers with given values :

- Register 0x5A00610C --> value: 0x01A76BEC
- Register 0x5A00620C --> value: 0x01A76BEC

HW modif :

Adding a coil of 27nH between the connector and the SoC on D+ and D- USB lines. In the case of STM32MP157F-DK2 board, this is between the SoC and the U29 component (ESD protection).

You can first make a try with the SW modif only, to see if it improves your results. This is far from being an easy topic, and it deals with the very basic HW USB signal, and the way a PHY can understand this last one.
Kind regards,

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.


Thanks a lot for the very detailed and quick reply. I will move forward tryin both your suggestions and keep you posted for any updates. 

By checking the USBPHYC documentation I was not able to locate the provided registers. I was wondering if there are any available examples or documentation. 


ST Employee

Hello  KChar.1,
"None of the above issues are present by using a usb-c to usb-A cable, usb Hub or usb-c to usb-A adapter. ": when using those cable, power and data role are forced by the cable.
When using TypeC to TypeC cable, as STUSB1600 is DRP and devices mentioned are also DRP (i. e CC pin toggle to be part of time Source/DRP and part of time SInk/UFP), there is 50% of chance to connect as Sink/UFP and 50% as Source/DFP.
As the is TypeC only (and not PD) there is no protocol messaging to swap power or data role.
To force the role, 'manual force' needs to be done by forcing system disconnection and setting stusb1600 to either source/dfp or sink/ufp.
Best regards


@KChar.1 ,
In the Reference Manual, you have a chapter named "USBPHYC register" with a base address of 0x5A006000

The exact registers we modify are so USBPHYC_TUNE1 and USBPHYC_TUNE2.

2 solutions: for your tests, you can use a tool such as devmem2 to modify registers just after the boot and begin your USB negotiation. The other way is to modify the device tree nodes usbphyc_port0 and usbphyc_port1 as described in stm32mp15xx-dkx.dtsi. You have to check the YAML documentation in parallel of the Reference Manual, to make match each property to the ones activated by 0x01A76BEC value. 

I advice to first test with devmem2, just to see if it solves the case when you see your timeout. @NBALL answered about 50/50 cases (thanks).

Board $> devmem2 0x5A00610C w 0x01A76BEC
Board $> devmem2 0x5A00620C w 0x01A76BEC

Kind regards,

In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.


Thank you so much for providing more details. Changing the registers already improved the issue on Apple Silicon machines. Based on several tests today I can see that the device is detected stably more than 90% of the times.

Thanks so much for the explanation. Indeed this is consistent with my original hypothesis and the Universal Serial Bus Type-C Cable and Connector Specification.

I experience this issue with all intel Macbooks. 

I am wondering whether it is possible to read from the stusb1600 registers when a connection has been established with a DRP port on the other end. If this is possible, can a forced disconnection and a switch to sink/ufp be established through user-space or the stusb160x driver?

@KChar.1 ,
I am 95% sure that Linux expose a sysfs entry or something like this to force a role switch. I already saw iPhone communicating by USB-C with STM32MP15 (a kind of car-play application), and the STM32MP15 clearly asked for a role switch at user space level.

Please let me know if you find it online or if you miss the information, I'll take a better look at it if you do not find it.


In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

By reading @x0E STUSB1600, you can get current power role after connection. But you cannot know if the other device is single role or DRP. This would need PD functionality.
So when connection is so that stusb1600 is source while you wish to be sink, you can force the role and see if a connection is setup again. If counter part was sink only, there will be no connection (sink to sink is not a valid connection). Timeout of 475ms after restarting the new role can be used to decide to be back to initial role for example. (475 = 200+275 which corresponds to, as per spec, tccdebounce max + tVbusOn max).

Best regards




Awesome! Thanks for this. I could not find something with a quick look but I will take a deeper look around to see whether a role exchange can be forced via sysfs.  @NBALL , this is a great suggestion! Highly appreciated! I will try to implement this logic as soon as I figure out an efficient way to force role changes from usr-space.