This article gives information about Linux® UCSI driver, and the STM32 UCSI firmware.
1. UCSI purpose[edit | edit source]
UCSI[1][2] stands for USB Type-C® Connector System Software Interface. It is a specification that defines a standard software interface for managing USB Type-C connectors and USB Power Delivery (USB PD) controllers. It provides a standardized and efficient way to manage power delivery, data transfer, and alternate modes. It enhances the user experience by enabling versatile and powerful connections through a single port.
In a UCSI enabled system, the Type-C port can me managed autonomously. The UCSI driver purpose is to be notified by (or to control) the USB Type-C interface, so the power role and/or the data role of the system is managed accordingly by the platform OS.
The UCSI specification[1][2] doesn't define the interface used to communicate with the UCSI controller (e.g. I2C, SPI...). On STM32 Arm® Cortex® MPUs , two flavors are available:
- An external STM32G0 can be used, running the X-CUBE-UCSI Firmware Package.
- An internal STM32Cube USBPD_DRP_UCSI application running on the Cortex®-M33 processor on STM32MP23x lines
or STM32MP25x lines
.
- On the STM32MP257F-EV1
, STM32MP257F-DK
and STM32MP257F-DK
for STM32MP23x lines evaluation
, the Cortex®-A35 communicates with the Cortex®-M33 through the Linux RPMsg framework.
- On the STM32MP257F-EV1
![]() |
The OpenSTLinux BSP running on the Arm® Cortex®-A processor(s) acts as the OPM (OS Policy Manager). The STM32Cube UCSI application running on the Arm® Cortex®-M processor acts as the PPM (Platform Policy Manager) and the LPM (Local Policy Managers). It uses independently several internal peripherals including the UCPD internal peripheral.
2. UCSI Architecture overview[edit | edit source]
2.1. On STM32 Arm® Cortex® MPUs
with external STM32G0[edit | edit source]
The X-CUBE-UCSI Firmware Package uses:
- two I2C device addresses:
- The primary address 0x53 may be tuned. It is reserved to communicate with the UCSI standard protocol.
- The secondary address 0x51 is used either by:
- - the STM32G0 when in bootloader mode (refer to AN4221)
- - the UCSI application at runtime to control the firmware update. It allows to request the firmware version, and to switch to booloader mode when needed.
- a GPIO based interrupt line to notify the application processor.
The Linux® UCSI driver:
- gets notified through GPIO
- can issue USCI commands onto the I2C link
It's responsible to switch the USB dual role stack, depending on the attached partner.
Please refer to USB_overview for further details on these interactions.
2.2. On STM32MP23x lines
and STM32MP25x lines
with the Cortex®-M33 for A35-TD flavor
[edit | edit source]
On STM32MP23x lines and STM32MP25x lines
, all can be integrated in a single SoC:
- OpenSTLinux distribution running on the Cortex®-A35
- STM32Cube UCSI application running on the Cortex®-M33
- - the application should be loaded on the Arm® Cortex®-M processor by using the Linux remoteproc framework
- - UCSI notifications and messages go through the Linux RPMsg framework
On STM32MP25x lines (STM32MP257F-DK Discovery kit
), USB3DR SuperSpeed lines are available:
- Routing the lines to the Type-C® connector is done through an external Super Speed switch to accommodate the cable orientation.
- Cable orientation is detected by the firmware, GPIOs can be used to drive the external switch.
3. How to use[edit | edit source]
USB Power delivery protocol on the CC line is managed independently by the UCSI firmware (either with external STM32G0 micro controller or internally with the Cortex®-M33 firmware).
Basically, the PPM detects if it's connected, if it's in front of a host or a device (by detecting a "Rp" pull-up or a "Rd" pull-down on the CC line). It also detects the presence of a Vbus and initiate USB power delivery messages on the CC line.
Once the connector attachment event has been detected by the PPM, it will notify the OPM throught UCSI events. The platform OS doesn't have access to the power delivery messages, but obtains a higher level of information through UCSI notifications, all described into the UCSI specification[1][2], such as:
- the connection status
- the connector partner type (Upstream Facing Port, Downstream Facing Port, powered cable...)
- the power mode of operation (USB default, 1.5A, 3A, PD, e.g. power delivery...)
- the power direction (provider or consumer)
- the data role (device or host)
- ...
![]() |
USB Type-C® devices can act as:
Upon the initial plug, the devices connected together will obtain respectively one of the A and B role on each side. Then the power and data roles may be swapped, when both ends support it, with USB power delivery protocol. |
This is exposed for the local port in:
cd /sys/class/typec/port0
ls
data_role supplier:platform:49000000.usb
device supported_accessory_modes
port0-partner uevent
power usb_power_delivery
power_operation_mode usb_power_delivery_revision
power_role usb_typec_revision
preferred_role vconn_source
subsystem waiting_for_supplier
cat data_role
host [device]
This is exposed for the partner port in:
cd /sys/class/typec/port0-partner
ls
accessory_mode subsystem usb_power_delivery_revision
device supports_usb_power_delivery
power uevent
More examples are available in USB overview articles: please refer to How to use typec from sysfs and How to perform USB data role swap or power role swap from sysfs.
4. Firmware update[edit | edit source]
4.1. On STM32 Arm® Cortex® MPUs
with external STM32G0[edit | edit source]
The X-CUBE-UCSI Firmware Package can be updated into the STM32G0 flash memory:
- Place the updated firmware in /lib/firmware/
- The Linux® UCSI driver will compare firmware version found into the filesystem in /lib/firmware with the flashed firmware.
- If a different firmware version is found in /lib/firmware. Kernel will replace old firmware with new firmware.
- In case the STM32G0 isn't flashed, and it's in I2C bootloader mode (refer to AN4221), the kernel will flash the firmware.
The firmware name must be specified in the board device-tree, to activate the update mechanism. For example, on the STM32MP135F-DK Discovery kit , it is located in arch/arm/boot/dts/st/stm32mp135f-dk.dts :
&i2c1 {
typec@53 {
compatible = "st,stm32g0-typec";
reg = <0x53>;
...
firmware-name = "stm32g0-ucsi.mp135f-dk.fw";
...
};
};
In order trigger the update mechanism, the driver must be re-loaded. This can be done in various ways:
reboot # or reload the module: rmmod ucsi_stm32g0 && modprobe ucsi_stm32g0 # alternatively unbind, then bind the driver: cd /sys/bus/i2c/drivers/ucsi-stm32g0-i2c/ ls 0-0053 bind module uevent unbind echo 0-0053 > unbind && echo 0-0053 > bind
In case no firmware is found on the STM32G0 MCU, the following message will come in dmesg log:
ucsi-stm32g0-i2c 0-0053: i2c read 53, 00 error: -6
During the firmware update process the following log will come on dmesg logs
ucsi-stm32g0-i2c 0-0053: Bootloader Version 0x12 ucsi-stm32g0-i2c 0-0053: Starting, option bytes:0xfffffeaa
4.2. On STM32MP23x lines
and STM32MP25x lines
with the Cortex®-M33 for A35-TD flavor
[edit | edit source]
The application should be loaded on the Arm® Cortex®-M33 processor by using the Linux remoteproc framework.
In OpenSTLinux, a systemctl service is used to load the firmware, depending on the board variant, and on how it is configured. These firmware are available, for each board in:
ls /usr/local/Cube-M33-examples/ .... STM32MP257F-DK STM32MP257F-EV1 # For STM32MP257F-DK: ls /usr/local/Cube-M33-examples/STM32MP257F-DK/Demonstrations/USBPD_DRP_UCSI/lib/firmware/ USBPD_DRP_UCSI_CM33_NonSecure_sign.bin USBPD_DRP_UCSI_CM33_NonSecure_stripped.elf
The systemctl to abstracts the image format supported, as described in Remote processor boot through sysfs section:
cat /sys/class/remoteproc/remoteproc1/name # check remoteprocX is the m33 m33 cat /sys/class/remoteproc/remoteproc1/fw_format
- ELF: USBPD_DRP_UCSI_CM33_NonSecure_stripped.elf needs to be updated
- TEE: USBPD_DRP_UCSI_CM33_NonSecure_sign.bin needs to be updated
Place the updated firmware in the relevant board folder:
cp <firmware> /usr/local/Cube-M33-examples/<board>/Demonstrations/USBPD_DRP_UCSI/lib/firmware/ # For ELF format, on STM32MP257F-DK board: cp USBPD_DRP_UCSI_CM33_NonSecure_stripped.elf /usr/local/Cube-M33-examples/STM32MP257F-DK/Demonstrations/USBPD_DRP_UCSI/lib/firmware/
- Run the following commands on device console to run the new firmware
systemctl stop st-m33firmware-load.service # Stops the firmware currently running systemctl start st-m33firmware-load.service # Loads and starts the new firmware
In order to permanently disable or enable the firmware service at boot time, following commands can be used
systemctl disable st-m33firmware-load.service systemctl enable st-m33firmware-load.service
An alternative solution to start the Stm32Cube UCSI application can be found in remote processor boot section.
5. How to trace and debug[edit | edit source]
5.1. Tracing Linux UCSI core with ftrace[edit | edit source]
The Linux UCSI core proposes some trace points that can be traced by the Linux® kernel Ftrace tool. I2C layer can also be traced, as it is used to communicate with the UCSI controller.
echo 1 > /sys/kernel/debug/tracing/events/ucsi/enable # Tracing UCSI Events echo 1 > /sys/kernel/debug/tracing/events/i2c/enable # Tracing I2C Events echo 1 > /sys/kernel/debug/tracing/tracing_on
Once ftrace has been enabled, any event on the Type-C connector can be traced (plug, unplug, or power event).
cat /sys/kernel/debug/tracing/trace ... irq/61-0-0053-410 [000] ..... 292.223643: i2c_write: i2c-0 #0 a=053 f=0000 l=1 [04] irq/61-0-0053-410 [000] ..... 292.223652: i2c_read: i2c-0 #1 a=053 f=0001 l=4 irq/61-0-0053-410 [000] ..... 292.223890: i2c_reply: i2c-0 #1 a=053 f=0001 l=4 [02-00-00-20] irq/61-0-0053-410 [000] ..... 292.223896: i2c_result: i2c-0 n=2 ret=2 ... kworker/0:0-6 [000] ..... 292.225223: ucsi_connector_change: port0 status: change=5004, opmode=4, connected=1, sourcing=0, partner_flags=1, partner_type=1, request_data_obj=00000000, BC status=0 ...
5.2. Tracing STM32Cube UCSI application with STM32CubeMonitor-UCPD tool[edit | edit source]
The STM32CubeMonitor-UCPD[4] allows tracing:
- the USB Power delivery stack
- the UCSI notifications and messages
It requires the _TRACE compilation switch to be activated when building the STM32Cube UCSI application. It is enabled by default:
- On STM32MP135F-DK
, the STLink exposes two VCP (virtual COM ports):
- On STM32MP257F-EV1
, STM32MP257F-DK
and STM32MP257F-DK
for STM32MP23x lines evaluation
, traces are available on USART6 on EXPANSION connector.
The UART port used for tracing can be configured:
- On STM32MP135F-DK
, in tracer_emb_conf.h,
- On STM32MP257F-EV1
, STM32MP257F-DK
and STM32MP257F-DK
for STM32MP23x lines evaluation
, in tracer_emb_conf.h .
- - It should also be properly assigned to the Cortex®-M33, e.g. set non-secure CID2 in the RIFSC peripheral. Please refer to the "How to assign an internal peripheral to an execution context" article for further details.
To read and decode the traces:
- First, plugin the serial port used for tracing, to a computer running STM32CubeMonitor-UCPD[4].
- Then click on "Select Tracer Port", on the entry corresponding to the second port.
- Last, generate some activity on the USB Type-C port (e.g. plug-in or remove a USB device).
Note that when nothing has been plugged-in on the dual role Type-C port toggles its CC lines, from source (SRC) to sink (SNK) as seen above. Then some activity on USB Power delivery stack and on UCSI is seen upon cable attach.
5.3. I2C debug commands[edit | edit source]
5.3.1. On the primary I2C address, dedicated to UCSI protocol[edit | edit source]
The UCSI driver module should be unloaded, before performing any direct I2C access:
rmmod ucsi_stm32g0
Identify the I2C bus number:
i2cdetect -l i2c-0 i2c STM32F7 I2C(0x40012000) I2C adapter i2c-1 i2c STM32F7 I2C(0x4c006000) I2C adapter
i2cdetect -l i2c-0 i2c STM32F7 I2C(0x0000000040130000) I2C adapter i2c-1 i2c rpmsg_i2c-0x401 adapter I2C adapter
Check the STM32G0 is responding on I2C bus, on the STM32MP135F-DK :
i2cdetect -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- 51 -- 53 -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Read UCSI version, on the primary I2C address:
i2ctransfer -f -y 0 w1@0x53 0x00 r2 0x20 0x01
i2ctransfer -f -y 1 w1@0x35 0x00 r2 0x20 0x01
5.3.2. On the secondary I2C address[edit | edit source]
On STM32 Arm® Cortex® MPUs with external STM32G0, the X-CUBE-UCSI Firmware Package uses a secondary I2C address, to control the firmware.
The UCSI application responds to below commands on the secondary I2C address:
Command code | Command answer | Description |
0x00, 0xff | 4 bytes | Get firmware version |
0x21, 0xde | 0 bytes | Reset directly, go to bootloader mode |
The UCSI driver module should be unloaded, before performing any direct I2C access:
rmmod ucsi_stm32g0
For example, on the STM32MP135F-DK Discovery kit , read the firmware version, on the secondary I2C address:
i2ctransfer -f -y 0 w2@0x51 0x00 0xff r4 0x02 0x06 0x22 0x20
Go to bootloader mode
i2cset -f -y 0 0x51 0x21 0xde
Then only the bootloader i2c address can be detected (e.g. 0x51)
root@stm32mp1-e3-5b-21:~# i2cdetect -y 0 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- 51 -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
6. Source code location[edit | edit source]
The UCSI Linux drivers to control USB Type-C® and USB Power Delivery are located in:
- drivers/usb/typec/ucsi/ucsi.c , the generic core driver
- drivers/usb/typec/ucsi/ucsi_stm32g0.c , the STM32 low level driver.
The UCSI firmware used either in the Cortex®-M33 coprocessor or in an external STM32G0, can be found:
- X-CUBE-UCSI Firmware Package
- USBPD_DRP_UCSI application , on STM32MP23x lines
and STM32MP25x lines
7. To go further[edit | edit source]
Linux® documentation and support:
- USB Type-C connector class
- UCSI, TCPM, PD, AltModes: Demystifying USB-C and Its Support in Linux - Dmitry Baryshkov, Linaro Ltd
8. References[edit | edit source]