SCMI device tree configuration

Revision as of 11:30, 21 January 2023 by Registered User (→‎DT bindings documentation)




1. Article purpose[edit source]

The purpose of this article is to explain how the SCMI resources configuration are defined in U-Boot bootloader and Linux® kernel.

The configuration is performed using the device tree mechanism[1].

2. DT bindings documentation[edit source]

The SCMI services device tree bindings are defined in the Linux kernel source tree, in Arm SCMI DT bindings[2] documentation. This documentation only defines the SCMI agent configuration, to be used in U-Boot or Linux kernel device trees.

An SCMI agent, in U-Boot or Linux kernel is represented by a node name scmi in the device tree. Each SCMI protocol used is represented by a subnode that defines and registers resources enumerated by the server or listed in the agent's device tree.

For example, the SCMI specification[3]) defines the SCMI power domain management protocol with the protocol ID 0x11. Device tree represents this SCMI protocol as a power domain controller, also called a PM domain provider in [4] documentation, that exposes power domains to Linux kernel drivers. From SCMI communication, agent and server for that platform use well defined ID numbers for each power domain, called the domain ID in SCMI litterature.

As shown in the source code snipet below, the power domain provider is a subnode named protocol@11 of the scmi node. Each power domain exposed through this protocol is idetified by 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 snipet 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>;
            };

        };
    };

3. DT configuration[edit source]

When STM32MP1 platform is to operate with an SCMI server in secure OP-TEE world, it needs to be described in Linux kernel and U-Boot bootloader device tree data.

The SCMI devices are described by a node named scmi. Devices and providers registered by the SCMI agent driver are described by subnodes, one per SCMI protocol used by the agent using reg bindings rules to carry the protocol ID number. Property "compatible" defines the SCMI transport layer used, either arm,scmi-smc"" or "linaro,scmi-optee" whether embedding TF-A or OP-TEE respectively.

Compatible requires a specific property in the device tree node: = that defines the platform SCM function ID used for SCMI message notification.

Compatible requires a specific property in the device node: linaro,optee-channel-id = <SOME_VALUE>; where SOME_VALUE is the channel ID defined for the communication. OP-TEE SCMI DT bindings permits SCMI protocol to be carried on specific channels, allows concurrent sending of messages. In such cases, the protocol subnode shall have property 'linaro,optee-channel-id defined with the expect channel ID.

When the using a predefined area of sram compatible memory for exchanging SCMI messages between non-secure and secure worlds, the platform must represent a related "arm,scmi-shmem" compatible nodes in the device tree to describe the shared memory.

The example below defines an SCMI server exposes embedded in an OP-TEE firmware and that exposes clocks and reset controllers.

	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";
			#address-cells = <1>;
			#size-cells = <0>;
			linaro,optee-channel-id = <0>;
			shmem = <&scmi_shm>;

			scmi_clk: protocol@14 {
				reg = <0x14>;
				#clock-cells = <1>;
			};

			scmi_reset: protocol@16 {
				reg = <0x16>;
				#reset-cells = <1>;
			};
		};
	};

All devices using SCMI clocks and reset controllers refer to the phandle of the related SCMI clock contoller node scmi_clk or SCMI reset controller 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 point also examples for I2C4 bus node or RTC node:

		i2c4: i2c@5c002000 {
			compatible = "st,stm32mp15-i2c";
			reg = <0x5c002000 0x400>;
			(...)
			clocks = <&scmi_clk CK_SCMI_I2C4>;
			resets = <&scmi_reset RST_SCMI_I2C4>;
			(...)
		};

		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>;
			status = "disabled";
		};

4. References[edit source]

Please refer to the following links for additional information: