1. Purpose[edit | edit source]
This article describes the configuration of the PWR wake-up pins for a usage in Linux, based on OP-TEE driver.
The PWR Wake-up pins are used to wake-up from Standby from an external device.
This article is applicable only if the PWR peripherals is assigned only to OP-TEE, for all STM32 Arm® Cortex® MPUs
except STM32MP15x lines
.
For STM32MP15x lines
, the PWR Wake-up is handled in Linux pwr_irq irqchip driver.
2. Overview[edit | edit source]
- Hardware:
- Button: one external device plugged to a wake-up pin. Could also be a PMIC.
- PWR: PWR internal peripheral
- OP-TEE in Secure world:
- PWR IRQ driver: driver in charge of PWR peripheral that provides access to the wake-up pin via an interrupts interface.
- EXTI driver: manage wake-up IRQ , include PWR interruptions
- STM32 IRQ notifier: driver used to manage interruption and forward events as notifications to the non-secure world.
- OP-TEE notification: stack in charge of communication with the non secure world.
- Linux Kernel space:
- Linaro OP-TEE driver: stack in charge of communication with secure world. Transform OP-TEE notifications to interrupts.
- GPIO keys driver: Linux driver using a wake-up pin handled by OP-TEE. Could be any driver able to handle Linux interrupts.
3. Wake-up pin configuration[edit | edit source]
3.1. OP-TEE configuration[edit | edit source]
PWR in OP-TEE is a interruption provider, each WKUP pin is associated to an interruption line. In SoC device tree, the PWR interruption identified by index 0 for WKUP1 up to 5 for WKUP6 is associated to each the corresponding EXTI (see reference manual for details):
For STM32MP13x lines
, EXTI 55 to EXTI 60 (see description example in core/arch/arm/dts/stm32mp131.dtsi )
exti: interrupt-controller@5000d000 {
compatible = "st,stm32mp1-exti";
...
<&pwr_irq 0 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP1
<&pwr_irq 1 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP2
<&pwr_irq 2 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP3
<&pwr_irq 3 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP4
<&pwr_irq 4 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP5
<&pwr_irq 5 IRQ_TYPE_EDGE_FALLING>, /* EXTI_60 */ interruption for WKUP6
...
For STM32MP2 series, EXTI1 52 to EXTI1 57 (see description example in core/arch/arm/dts/stm32mp251.dtsi )
exti1: interrupt-controller@44220000 {
compatible = "st,stm32mp1-exti", "syscon";
interrupts-extended =
...
<&intc GIC_SPI 210 IRQ_TYPE_LEVEL_HIGH>, /* EXTI_50 */
<0>,
<&pwr 0 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP1
<&pwr 1 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP2
<&pwr 2 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP3
<&pwr 3 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP4
<&pwr 4 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP5
<&pwr 5 IRQ_TYPE_EDGE_FALLING>, interruption for WKUP6
<0>,
...
The WKUP user defined in device tree OP-TEE device tree manages this EXTI interruption to enable the configuration of the associate WKUP pin in PWR driver; this EXTI interruption is identified by the generic interrupts-extended device tree property (see Interrupt overview page for details) and provides its polarity by IRQ_TYPE_EDGE_RISING or IRQ_TYPE_EDGE_FALLING.
Each PWR WKUP pins are activated in OP-TEE via device-tree in pwr node with wakeup-gpios properties and the generic GPIO device tree configuration.
Each WKUP pin is free by default in SoC device tree with:
wakeup-gpios = <0>, <0>, <0>, <0>, <0>, <0>;
In board you configure the 6 GPIO of WKUP pins with this wakeup-gpios properties: the free WKUP are indicated in the list by <0> and the wake-up pull configuration (maintained in Standby modes): GPIO_PULL_UP, GPIO_PULL_DOWN or GPIO_ACTIVE_HIGH (no pull).
NB: each WKUP pin is defined in each STM32 MPU datasheet and is checked by OP-TE the PWR IRQ driver:
- For STM32MP2 series in core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr_irq.c :
#ifdef CFG_STM32MP13
static const struct stm32_pwr_pin_map pin_map[PWR_NB_WAKEUPPINS] = {
{ .bank = GPIO_BANK('F'), .pin = 8, },
{ .bank = GPIO_BANK('I'), .pin = 3, },
{ .bank = GPIO_BANK('C'), .pin = 13, },
{ .bank = GPIO_BANK('I'), .pin = 1, },
{ .bank = GPIO_BANK('I'), .pin = 2, },
{ .bank = GPIO_BANK('A'), .pin = 3, },
};
#endif
#ifdef CFG_STM32MP15
static const struct stm32_pwr_pin_map pin_map[PWR_NB_WAKEUPPINS] = {
{ .bank = GPIO_BANK('A'), .pin = 0, },
{ .bank = GPIO_BANK('A'), .pin = 2, },
{ .bank = GPIO_BANK('C'), .pin = 13, },
{ .bank = GPIO_BANK('I'), .pin = 8, },
{ .bank = GPIO_BANK('I'), .pin = 11, },
{ .bank = GPIO_BANK('C'), .pin = 1, },
};
#
- For STM32MP2 series in core/arch/arm/plat-stm32mp2/drivers/stm32mp25_pwr_irq.c :
static const struct stm32_pwr_pin_map pin_map[PWR_NB_WAKEUPPINS] = {
{ .bank = GPIO_BANK('A'), .pin = 0, },
{ .bank = GPIO_BANK('H'), .pin = 5, },
{ .bank = GPIO_BANK('G'), .pin = 1, },
{ .bank = GPIO_BANK('I'), .pin = 6, },
{ .bank = GPIO_BANK('G'), .pin = 2, },
{ .bank = GPIO_BANK('G'), .pin = 3, },
};
- WKUP pins are PA0 PH5 PG1 PI6 PG2 PG3
See binding for details: documentation/devicetree/bindings/mfd/st,stm32mp25-pwr.yaml
A stm32-irq-notifier node can be instantiated on the EXTI associated to PWR WKUP to handle the desired wake-up pin; when the associated interruption occur its driver sends a OP-TEE notification with identifier st,notif-it-id to Linux in non secure world:
- binding documentation: documentation/devicetree/bindings/soc/stm32/st,stm32-irq-notifier.yaml
- driver: core/drivers/stm32_irq_notif.c
3.2. Linux configuration[edit | edit source]
Linux does not handle wake-up pin, but it can handle an OP-TEE notification as an interrupt.
This is configured via the interrupts-extended device tree property[1] and index of notification as defined in OP-TEE device tree with st,notif-it-id.
See Documentation/devicetree/bindings/arm/firmware/linaro,optee-tz.yaml for detials.
4. Examples[edit | edit source]
4.1. wake-up pin 2[edit | edit source]
In the simple example below, the wake-up pin number 2 (EXTI 56 and GPIO PI3) is configured by OP-TEE, triggered by falling edge and with pull -up, forwarded as notification number 4 to Linux, and used by "gpio-keys" driver in Linux to generate a key-press.
OP-TEE device tree:
wakeup_button: wakeup-button {
compatible = "st,stm32-irq-notifier";
interrupts-extended = <&exti 56 IRQ_TYPE_EDGE_FALLING>;
wakeup-source;
status = "okay";
};
};
&pwr_irq {
wakeup-gpios = <0>, <&gpioi 3 GPIO_PULL_UP>, <0>, <0>, <0>, <0>;
status = "okay";
};
Linux device tree:
wake_up {
compatible = "gpio-keys";
status = "okay";
button {
label = "wake-up";
linux,code = <KEY_WAKEUP>;
interrupts-extended = <&optee 4>;
status = "okay";
};
};
4.2. STM32MP135F-DK
[edit | edit source]
You can also found usage for PWR IRQ in OP-TEE device tree for STM32MP135F-DK
: core/arch/arm/dts/stm32mp135f-dk.dts
\ {
magic_wol: magic_wol {
compatible = "st,stm32-irq-notifier";
interrupts-extended = <&exti 56 IRQ_TYPE_EDGE_FALLING>; interruption for WKUP2
wakeup-source;
status = "okay";
};
typec_wakeup: typec_wakeup {
compatible = "st,stm32-irq-notifier";
interrupts-extended = <&exti 59 IRQ_TYPE_EDGE_FALLING>; interruption for WKUP5
wakeup-source;
st,notif-it-id = <1>; notification identifier for Linux
status = "okay";
};
};
&i2c4 {
pinctrl-names = "default";
pinctrl-0 = <&i2c4_pins_a>;
i2c-scl-rising-time-ns = <185>;
i2c-scl-falling-time-ns = <20>;
clock-frequency = <400000>;
status = "okay";
pmic: stpmic@33 {
compatible = "st,stpmic1";
reg = <0x33>;
status = "okay";
interrupts-extended = <&exti 55 IRQ_TYPE_EDGE_FALLING>; interruption for WKUP1
...
};
};
&pwr_irq {
status = "okay";
wakeup-gpios = <&gpiof 8 GPIO_ACTIVE_HIGH>, GPIO configuration for WKUP1
<&gpioi 3 GPIO_ACTIVE_HIGH>, GPIO configuration for WKUP2
<0>,
<0>,
<&gpioi 2 GPIO_PULL_UP>, GPIO configuration for WKUP5
<0>;
};
In Linux device tree in arch/arm/boot/dts/st/stm32mp135f-dk.dts :
&i2c1 {
...
typec@53 {
compatible = "st,stm32g0-typec";
reg = <0x53>;
/* Alert pin on PI2 (PWR wakeup pin), managed by optee */
interrupts-extended = <&optee 1>;
firmware-name = "stm32g0-ucsi.mp135f-dk.fw";
wakeup-source;
connector {
compatible = "usb-c-connector";
label = "USB-C";
port {
con_usb_c_g0_ep: endpoint {
remote-endpoint = <&usbotg_hs_ep>;
};
};
};
};
};
5. Source code location[edit | edit source]
The source files are located inside the OP-TEE.
- OP-TEE PWR IRQ driver:
- core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr_irq.c for STM32MP13x lines

- core/arch/arm/plat-stm32mp2/drivers/stm32mp25_pwr_irq.c for STM32MP25x lines

- core/arch/arm/plat-stm32mp1/drivers/stm32mp1_pwr_irq.c for STM32MP13x lines
- OP-TEE STM32 IRQ notifier:
6. References[edit | edit source]
- ↑ Generic interrupts bindings documentation: Documentation/devicetree/bindings/interrupt-controller/interrupts.txt