1. Article purpose[edit source]
The purpose of this article is to explain how the SCMI resources are configured in U-Boot bootloader and Linux® kernel. The configuration is performed using the device tree mechanism[1].
SCMI services provided in STM32 MPU platforms are described in the SCMI overview article.
2. DT bindings documentation[edit source]
Generic information about SCMI is available in the SCMI overview article.
The device tree binding documents for SCMI resources are stored either in the given applicable components listed below, or in the Linux kernel repository:
- U-Boot, Linux® OS:
- Arm SCMI DT bindings: Documentation/devicetree/bindings/firmware/arm,scmi.yaml
SCMI agent is only present in U-Boot and Linux® OS, while SCMI server is integrated in TF-A or OP-TEE. The DT bindings documentation only defines the SCMI agent configuration, there are no bindings for SCMI server configuration part.
The SCMI agent DT node must reflect the services exposed by SCMI server embedded in TF-A or OP-TEE.
2.1. DT bindings documentation - additional information - scmi node basics[edit source]
An SCMI agent, in U-Boot or Linux kernel is represented by a node named scmi in the firmware node of the device tree. Property compatible in the scmi node defines the SCMI transport used. Valid values for compatible property are listed in the SCMI DT bindings [2]. Each SCMI protocol used is represented by a subnode of the scmi node.
firmware { scmi { compatible = "..."; #address-cells = <1>; #size-cells = <0>; (...) protocol@11 { reg = <0x11>; (...) }; protocol@14 { reg = <0x14>; (...) }; (...) }; };
For example, the SCMI specification[3] defines the SCMI power domain management protocol as identified with protocol ID 0x11. Device tree represents this SCMI protocol as a power domain controller in the Linux® kernel, also called a "PM domain provider" in the[4] documentation, that exposes power domains to Linux® kernel drivers. From SCMI communication perspective, the agent and server for that platform use well defined ID numbers for each power domain, called domain IDs in SCMI literature.
As shown in the source code snippet below, the Linux® power domain provider is a subnode named protocol@11 of the scmi node. Each power domain exposed through this protocol is identified by a well-known ID number. A device consuming the SCMI agent's power domain ID 2 would refer to that power domain using the SCMI protocol node phandle, scmi_devpd1 here, and use the SCMI power domain ID 2 as phandle argument: e.g. power-domains = <&scmi_devpd1 2>;. The below DTSI source code snippet is extracted from the SCMI DT bindings documentation[2].
firmware { scmi { compatible = "arm,scmi-smc"; shmem = <&cpu_scp_lpri0 &cpu_scp_lpri1>; arm,smc-id = <0xc3000001>; #address-cells = <1>; #size-cells = <0>; scmi_devpd1: protocol@11 { reg = <0x11>; #power-domain-cells = <1>; }; }; };
[edit source]
When the platform uses a predefined area of sram compatible memory for exchanging SCMI messages between non-secure and secure worlds, the platform must set property shmem = <SOME_PHANDLE> in the scmi node, and possibly in the SCMI protocol subnodes, in case such procotol uses a specifc channel. When using compatible="linaro,scmi-optee", SCMI communication can use OP-TEE dynamically allocated shared memory which is represented by the absence of property shmem in the related node.
The below example describes an OP-TEE SCMI firmware that exposes 2 channels. Channel 0 uses pre-defined sram shared memory and is used for SCMI base communication and for SCMI reset controls messaging. Channel 1 uses dynamically allocated OP-TEE shared memory and is used for a voltage regulator controller.
scmi_sram: sram@2ffff000 { compatible = "mmio-sram"; reg = <0x2ffff000 0x1000>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x2ffff000 0x1000>; scmi_shm: scmi_shm@0 { compatible = "arm,scmi-shmem"; reg = <0 0x80>; }; }; firmware { scmi: scmi { compatible = "linaro,scmi-optee"; linaro,optee-channel-id = <0>; shmem = <&scmi_shm>; #address-cells = <1>; #size-cells = <0>; scmi_clk: protocol@14 { reg = <0x14>; #clock-cells = <1>; }; protocol@17 { reg = <0x17>; linaro,optee-channel-id = <1>; regulators { #address-cells = <1>; #size-cells = <0>; scmi_reg11: reg11@0 { reg = <0>; regulator-name = "reg11"; regulator-min-microvolt = <1100000>; }; }; }; }; };
3. DT configuration[edit source]
This hardware description is a combination of the STM32 microprocessor device tree files (.dtsi extension) and board device tree files (.dts extension). See the Device tree for an explanation of the device-tree file organization. STM32CubeMX can be used to generate the board device tree.
3.1. DT configuration (STM32/SoC level)[edit source]
SoC level device tree data defines the SCMI node that represents SCMI communication means and SCMI protocols exposed by the SCMI server embedded in system secure world.
The node is defined in the SoC DTSI file stm32mp151.dtsi.
SCMI agent is described in the device tree by a node named scmi. This node uses property compatible to define the SCMI transport layer being used, either "arm,scmi-smc" or "linaro,scmi-optee" whether embedding TF-A or OP-TEE respectively. The SCMI protocols exposed by the server and used by the agent are represented by subnodes in the scmi node, each subnode defining the related SCMI protocol ID number using reg bindings rules.
Configuration when using an SCMI server embedded in TF-A services is described in the below section SCMI agent when TF-A in secure world.
Configuration when using an SCMI server embedded in OP-TEE services is described in the below section SCMI agent when OP-TEE in secure world. SCMI firmware embedded in OP-TEE exposes the service to the SCMI agent through communication channel number 0, hence property linaro,optee-channel-id is to be set to 0.
When the using a predefined area of sram compatible memory for exchanging SCMI messages between non-secure and secure worlds, the platform must have a shmem property in the scmi node that refers to the phandle of a related "arm,scmi-shmem" compatible node in the device tree to describe the shared memory. SCMI communication uses internal RAM (sram in device tree bindings) hence there is a 'shmem' property in the related SCMI node.
SoC level device tree configuration data defines the SCMI protocols exposed by the SCMI server related to SoC resources. These are:
- clock and reset controllers controlled by the SoC RCC subsystem and managed respectively through the SCMI clock protocol (protocol ID 0x14) and SCMI reset domain (protocol ID 0x16);
- voltage regulators controller by SoC PWR subsystem and managed through the SCMI voltage domain protocol (protocol ID 0x17);
- possibly CPU operating point exposed through the SCMI performance management protocol (protocol ID 0x13).
Description of how devices consume SCMI services is described in the below section DT_configuration_for_SCMI_resource_consumers.
3.2. DT configuration (board level)[edit source]
Board level device tree configuration data defines the controls exposed by the SCMI server related to board specific configuration, as voltage regulators (exposed through the SCMI voltage domain protocol) for regulators controlled from the Power Management Integrated Circuit (PMIC) device STPMIC1 on STM32MP13x lines boards.
Description of how device node binds to SCMI services is described in the below section DT configuration for SCMI resource consumers.
Remember that SCMI agent (Linux® kernel and U-Boot bootloader) device tree configuration data reflects the SCMI firmware services exposed by the SCMI server embedded in system secure world.
3.3. DT configuration examples[edit source]
3.3.1. SCMI agent when TF-A in secure world[edit source]
Compatible "arm,scmi-smc" requires node property shmem and a specific property: arm,smc-id = <FUNC_ID>; that defines the platform SMC function ID used for SCMI messages notification. When the platform defines a specific communication (couple SMC function ID and shared memory), the node of the SCMI protocol defines both arm,smc-id and shmem properties in the SCMI protocol subnode.
Note that STM32MP15 platforms currently use a single channel with pre-allocated SYSRAM shared memory for SCMI, to expose clock and reset controllers, as shown in the DTS extract below:
scmi_sram: sram@2ffff000 { compatible = "mmio-sram"; reg = <0x2ffff000 0x1000>; #address-cells = <1>; #size-cells = <1>; ranges = <0 0x2ffff000 0x1000>; scmi_shm: scmi_shm@0 { compatible = "arm,scmi-shmem"; reg = <0 0x80>; }; }; firmware { scmi: scmi { compatible = "arm,scmi-smc"; arm,smc-id = <0x82002000>; shmem = <&scmi_shm>; #address-cells = <1>; #size-cells = <0>; scmi_clk: protocol@14 { reg = <0x14>; #clock-cells = <1>; }; scmi_reset: protocol@16 { reg = <0x16>; #reset-cells = <1>; }; }; };
3.3.2. SCMI agent when OP-TEE in secure world[edit source]
When OP-TEE is embedded in secure world, SCMI communication uses OP-TEE transport.
Compatible "linaro,scmi-optee" requires a specific property in the device node: linaro,optee-channel-id = <CHANNEL_ID>; where CHANNEL_ID is the channel identifier defined for the SCMI communication. STM32MP15x lines and STM32MP13x lines currently exposes a single SCMI channel identified by ID value 0.
SCMI uses the last page of internal SYSRAM for SCMI communication. This is reflected by property shmem = <&scmi_shm>;.
The below example shows STM32MP13x lines SCMI device tree data using SCMI/OP-TEE transport over channel 0 using OP-TEE native shared memory and exposing clock, reset and voltage regulator controllers.
firmware { scmi: scmi { compatible = "linaro,scmi-optee"; linaro,optee-channel-id = <0>; #address-cells = <1>; #size-cells = <0>; scmi_clk: protocol@14 { reg = <0x14>; #clock-cells = <1>; }; scmi_reset: protocol@16 { reg = <0x16>; #reset-cells = <1>; }; protocol@17 { reg = <0x17>; linaro,optee-channel-id = <1>; regulators { #address-cells = <1>; #size-cells = <0>; scmi_reg11: voltd-reg11 { reg = <VOLTD_SCMI_REG11>; regulator-name = "reg11"; }; scmi_reg18: voltd-reg18 { reg = <VOLTD_SCMI_REG18>; regulator-name = "reg18"; }; scmi_usb33: voltd-usb33 { reg = <VOLTD_SCMI_USB33>; regulator-name = "usb33"; }; }; }; }; };
3.3.3. DT configuration for SCMI resource consumers[edit source]
All devices consuming SCMI resources refer to them using Device Tree phandle. For example, a device consuming clock and reset controllers refers to the phandle of the related SCMI clock protocol node scmi_clk or SCMI reset domain protocol node scmi_reset.
For example, the CPU references an SCMI clock:
cpus { #address-cells = <1>; #size-cells = <0>; cpu0: cpu@0 { compatible = "arm,cortex-a7"; device_type = "cpu"; reg = <0>; clocks = <&scmi_clk CK_SCMI_MPU>; clock-names = "cpu"; operating-points-v2 = <&cpu0_opp_table>; nvmem-cells = <&part_number_otp>; nvmem-cell-names = "part_number"; #cooling-cells = <2>; }; };
We can also point to examples for I2C4 bus that uses an SCMI clock and an SCMI reset controller ...
i2c4: i2c@5c002000 { compatible = "st,stm32mp15-i2c"; reg = <0x5c002000 0x400>; (...) clocks = <&scmi_clk CK_SCMI_I2C4>; resets = <&scmi_reset RST_SCMI_I2C4>; (...) };
... or the RTC device node.
rtc: rtc@5c004000 { compatible = "st,stm32mp1-rtc"; reg = <0x5c004000 0x400>; clocks = <&scmi_clk CK_SCMI_RTCAPB>, <&scmi_clk CK_SCMI_RTC>; clock-names = "pclk", "rtc_ck"; interrupts-extended = <&exti 19 IRQ_TYPE_LEVEL_HIGH>; (...) };
4. References[edit source]
Refer to the following links for additional information:
- ↑ Device tree
- ↑ 2.0 2.1 Documentation/devicetree/bindings/firmware/arm,scmi.yaml Arm SCMI DT bindings
- ↑ https://developer.arm.com/documentation/den0056
- ↑ Documentation/devicetree/bindings/power/power-domain.yaml Power Domains DT bindings