[PATCH v2 1/5] usb: tcpm: add core framework
Tim Harvey
tharvey at gateworks.com
Sat Jul 13 02:23:10 CEST 2024
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?
Also I would like to add the ability to show the PDO descriptions and
the current negotiated PD contract in cmd/tcpm.c do_print_info so I
will work on that. I would also like to add the capability to modify
for the STUSB4500 the 3 stored PDO's and request a new contract (for
example to up the wattage requested by and delivered to a board before
enabling a higher power peripheral) and to store the modified PDO's in
NVM. Do you think it would make sense for me to add a command handler
operation to the tcpm class so non-common device-specific commands
could be added or do you think I should just add my own
U_BOOT_CMD(stusb4500, ...) for this in my driver?
Best Regards,
Tim
[1] https://www.st.com/resource/en/datasheet/stusb4500.pdf
https://www.st.com/resource/en/user_manual/um2650-the-stusb4500-software-programing-guide-stmicroelectronics.pdf
More information about the U-Boot
mailing list