Last edited 2 months ago

How to configure PWR Wake-up pins

Applicable for STM32MP13x lines, STM32MP21x lines, STM32MP23x lines, STM32MP25x lines

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 More info.png except STM32MP15x lines More info.png.

For STM32MP15x lines More info.png, the PWR Wake-up is handled in Linux pwr_irq irqchip driver.

2. Overview[edit | edit source]

Error creating thumbnail: File missing
Wake-up pins overview
  • 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 More info.png, 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:

#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 STM32MP13x lines More info.png, WKUP pins are PF8 PI3 PC13 PI1 PI2 PA3
  • for STM32MP15x lines More info.png, WKUP pins are PA0 PA2 PC13 PI8 PI11 PC1
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:

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 More info green.png[edit | edit source]

You can also found usage for PWR IRQ in OP-TEE device tree for STM32MP135F-DK More info green.png: 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.

6. References[edit | edit source]