[PATCH v2 1/5] usb: tcpm: add core framework

Tim Harvey tharvey at gateworks.com
Wed Jul 17 04:00:06 CEST 2024


On Fri, Jul 12, 2024 at 5:23 PM Tim Harvey <tharvey at gateworks.com> wrote:
>
> On Tue, Jun 4, 2024 at 9:36 AM Sebastian Reichel
> <sebastian.reichel at collabora.com> wrote:
> >
> > This adds TCPM framework in preparation for fusb302 support, which can
> > handle USB power delivery messages. This is needed to solve issues with
> > devices, that are running from a USB-C port supporting USB-PD, but not
> > having a battery.
> >
> > Such a device currently boots to the kernel without interacting with
> > the power-supply at all. If there are no USB-PD message replies within
> > 5 seconds, the power-supply assumes the peripheral is not capable of
> > USB-PD. It usually takes more than 5 seconds for the system to reach
> > the kernel and probe the I2C based fusb302 chip driver. Thus the
> > system always runs into this state. The power-supply's solution to
> > fix this error state is a hard reset, which involves removing the
> > power from VBUS. Boards without a battery (or huge capacitors) will
> > reset at this point resulting in a boot loop.
> >
> > This imports the TCPM framework from the kernel. The porting has
> > originally been done by Rockchip using hardware timers and the Linux
> > kernel's TCPM code from some years ago.
> >
> > I had a look at upgrading to the latest TCPM kernel code, but that
> > beast became a lot more complex due to adding more USB-C features.
> > I believe these features are not needed in U-Boot and with multiple
> > kthreads and hrtimers being involved it is non-trivial to port them.
> > Instead I worked on stripping down features from the Rockchip port
> > to an even more basic level. Also the TCPM code has been reworked
> > to avoid complete use of any timers (Rockchip used SoC specific
> > hardware timers + IRQ to implement delayed work mechanism). Instead
> > the delayed state changes are handled directly from the poll loop.
> >
> > Note, that (in contrast to the original Rockchip port) the state
> > machine has the same hard reset quirk, that the kernel has - i.e.
> > it avoids disabling the CC pin resistors for devices that are not
> > self-powered. Without that quirk, the Radxa Rock 5B will not just
> > end up doing a machine reset when a hard reset is triggered, but will
> > not even recover, because the CPU will loose power and the FUSB302
> > will keep this state because of leak voltage arriving through the RX
> > serial pin (assuming a serial adapter is connected).
> >
> > This also includes a 'tcpm' command, which can be used to get
> > information about the current state and the negotiated voltage
> > and current.
> >
> > Co-developed-by: Wang Jie <dave.wang at rock-chips.com>
> > Signed-off-by: Wang Jie <dave.wang at rock-chips.com>
> > Signed-off-by: Sebastian Reichel <sebastian.reichel at collabora.com>
> > ---
> >  Makefile                         |    1 +
> >  cmd/Kconfig                      |    7 +
> >  cmd/Makefile                     |    1 +
> >  cmd/tcpm.c                       |  142 ++
> >  drivers/usb/Kconfig              |    2 +
> >  drivers/usb/tcpm/Kconfig         |    8 +
> >  drivers/usb/tcpm/Makefile        |    3 +
> >  drivers/usb/tcpm/tcpm-internal.h |  174 +++
> >  drivers/usb/tcpm/tcpm-uclass.c   |  102 ++
> >  drivers/usb/tcpm/tcpm.c          | 2251 ++++++++++++++++++++++++++++++
> >  include/dm/uclass-id.h           |    1 +
> >  include/usb/pd.h                 |  516 +++++++
> >  include/usb/tcpm.h               |   99 ++
> >  13 files changed, 3307 insertions(+)
> >  create mode 100644 cmd/tcpm.c
> >  create mode 100644 drivers/usb/tcpm/Kconfig
> >  create mode 100644 drivers/usb/tcpm/Makefile
> >  create mode 100644 drivers/usb/tcpm/tcpm-internal.h
> >  create mode 100644 drivers/usb/tcpm/tcpm-uclass.c
> >  create mode 100644 drivers/usb/tcpm/tcpm.c
> >  create mode 100644 include/usb/pd.h
> >  create mode 100644 include/usb/tcpm.h
> >
>
> Hi Sebastian,
>
> I have a board that has a STMicroelectronics STUSB4500 USB PD sink
> controller [1] on it that I would be interested in writing a driver
> for using this TCPM class. This device is a USB PD sink controller
> which has a nice 'auto-run' feature that has 3 updatable NVM backed
> PDO's that it negotiates on its own with the the PD source so that you
> get basic functionality without needing a driver.
>
> I am struggling a bit to get the stusb4500 working in a driver that
> fits into your framework and I think its the fact that the STUSB4500
> has no buffering capability so the processing of messages during the
> PD negotiation is extremely timing critical and I'm often missing the
> SRC_CAP message. To help me understand the correct operation of the
> tcpm state machine can you by chance enable DEBUG in fusb302.c and
> tcpm.c and share the output with me?
>
> I'm trying to understand the required state machine transitions. It
> looks to me like for a SINK the state machine should go like this:
> INVALID_STATE -> SNK_UNATTACHED
> SNK_UNATTACHED -> SNK_ATTACH_WAIT
> ^^^ during tcpm_init
> SNK_ATTACH_WAIT -> SNK_DEBOUNCED
> SNK_DEBOUNCED -> SNK_ATTACHED
> SNK_ATTACHED -> SNK_STARTUP
> SNK_STARTUP -> SNK_DISCOVERY
> SNK_DISCOVERY -> SNK_WAIT_CAPABILITIES
>
> At this point drvops->set_pd_rx(on) is called to allow your driver to
> accept PD messages but I don't understand the following logic:
>         case SNK_WAIT_CAPABILITIES:
>                 ret = drvops->set_pd_rx(dev, true);
>                 if (ret < 0) {
>                         tcpm_set_state(dev, SNK_READY, 0);
>                         break;
>                 }
>                 /*
>                  * If VBUS has never been low, and we time out waiting
>                  * for source cap, try a soft reset first, in case we
>                  * were already in a stable contract before this boot.
>                  * Do this only once.
>                  */
>                 if (port->vbus_never_low) {
>                         port->vbus_never_low = false;
>                         tcpm_set_state(dev, SOFT_RESET_SEND,
>                                        PD_T_SINK_WAIT_CAP);
>                 } else {
>                         tcpm_set_state(dev, hard_reset_state(port),
>                                        PD_T_SINK_WAIT_CAP);
>                 }
>
> Why on error would you go straight to SNK_READY? The comment indicates
> a return value of >=0 is a timeout. Why on success would you either go
> straight to a hard/soft reset? What does fusb302.c return from
> set_pd_rx and do after that call?

Hi Sebastian,

I've managed to make it further through the TCPM state machine with my
stusb4500 driver. I figured out that the intended operation of
SNK_WAIT_CAPABILITIES is to send a soft reset which gets the PD SRC to
send SRC_CAP which transitions to SNK_NEGOTIATE_CAPABILITIES then the
PD SRC sends an ACCEPT which transitions to SNK_TRANSITION_SINK then a
PS_READY which transitions to SNK_READY.

I am seeing that when a PD_DATA_REQUEST to negotiate a contract my
board loses power which does not happen if the STUSB4500 is allowed to
run in its auto-run mode. Do you know if there is some sort of power
glitch that is expected when a PD_DATA_REQUEST is sent from the SNK to
the SRC that must be managed with hold-up caps or something?

Best Regards,

Tim


More information about the U-Boot mailing list