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