# SCMI & TF-A study notes [hackweek22 project link](https://hackweek.opensuse.org/22/projects/arm-scmi-study) ## The interface defined by SCMI provides two levels of abstraction: * **Protocols** Each group of related functions is referred to as a protocol. The SCMI interface structure is extensible, and therefore other protocols could be added in the future. * **Transports** The protocols communicate through transports. A transport specification describes how protocol messages are communicated between agents using the interface and the platform components that implement the protocol messages. The interface is intended to be described in firmware, using either the Flattened Device Tree (FDT) or Advanced Configuration and Power Interface (ACPI) specification. For more information, see [FDT] and [ACPI]. Because the protocols are intended to be generic, they result in generic kernel code to drive them. However, in the ACPI case, the interface can also be driven from ASL methods. * Tranport types in the spec: * Shared Memory based Transport. * In some agents, **Shared Memory based Transport** could also mean **SMT**, please see SMCI v3.1 spec - **section 5.1.2** for the header/struct layout description. For example: * [The SMT header in u-boot](https://github.com/u-boot/u-boot/blob/master/drivers/firmware/scmi/smt.h#L19) * [struct scmi_shared_mem {} in kernel](https://github.com/torvalds/linux/blob/master/drivers/firmware/arm_scmi/shmem.c#L17) * [SMT header in TF-A](https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/scmi-msg/smt.c#L25) * Other ref: Merged u-boot [patch](https://patchwork.ozlabs.org/project/uboot/patch/20220531160929.931150-2-etienne.carriere@linaro.org/) related to SMT. * ACPI-based Transport. * Shared Memory or MMIO-based Transport for FastChannels. * Virtio-based Transport. ## Glossaries in TF-A **SP**: SP means Security Payload, they are usually secure Apps/Trusted OS run in secure EL1, such as OPTEE. **SPD**: This is the Secure Payload Dispatcher (SPD). The dispatcher is meant to be a plug-in component to the Secure , registered as a runtime service. The SPD is expected to be a functional extension of the Secure Payload (SP) that executes in Secure EL1. The Secure Monitor will delegate all SMCs targeting the Trusted OS/Applications range to the dispatcher. The SPD will either handle the request locally or delegate it to the Secure Payload. It is also responsible for initialising and maintaining communication with the SP. **tsp**: Test Security Payload, it's used for testing the communications between the service SPD [Service Payload Dispatcher] and SPs. ## Supported SCMI protocols in latest upstream TF-A (1678bbb57249b6 Jan 26, 2023) ###### Note: The platform-specific functions still need to be implemented/overwritten under the common protocol functions. * **Base**: This protocol describes the properties of the implementation and provides generic error management. * **Power Domain**: A power domain is defined as a group of components that are powered together. For example, a set of components that share a power source, and can only be turned ON or OFF as a group, form a power domain. * **Clock**: This protocol is intended for the management of clocks. It is used to enable or disable clocks, and to set rates. * **Reset Domain**: This protocol is intended for control of reset capable domains in the platform. * **Unsupported protocol in TF-A:** System Power, Perf (e.g DVFS), Sensor, Voltage, Pin. ## Platform Porting ### 1. Platforms can implement its own BL1/BL2/BL31/BL32 platform functions, such as: * **BL31**: (EL3) bl31_platform_setup() * imx, s32, rpi, etc, which is called in bl31_main.c * **BL32**: (Secure EL1) sp_min_platform_setup() [rockchip, stm32] * rockchip, stm32 For more info about all overwritable BLx functions please check docs/getting_started/porting-guide.rst. ### 2. SCMI function overwriting * TF-A has common/empty platform SCMI APIs decared as public **[weak](https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/scmi-msg/clock.c#L15)** functions, which can be inclued via [scmi-msg.h](https://github.com/nxp-auto-linux/arm-trusted-firmware/blob/release/bsp35.0-2.5/include/drivers/scmi-msg.h). The platform developers can overwrite them based on design requirements, such as [s32-specific platform clock](https://github.com/nxp-auto-linux/arm-trusted-firmware/blob/release/bsp35.0-2.5/plat/nxp/s32/s32_scmi_clk.c), for example: * **plat_scmi_vendor_name** called by discover_vendor * **plat_scmi_clock_set_rate** called by scmi_clock_rate_set. * **plat_scmi_clock_get_rate** called by scmi_clock_rate_get * plat_scmi_perf_domain_count, plat_scmi_rstd_count, .. etc. ## SCMI message handling: * [Message structure](https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/scmi-msg/common.h#L76) * scmi_process_message() * upstream approach: * scmi_proccess_smt() -> scmi_process_message() * Seems to be used by stm32 only * 2nd approach: platform-specific-handler ([example](https://github.com/nxp-auto-linux/arm-trusted-firmware/blob/release/bsp35.0-2.5/plat/nxp/s32/s32_svc.c#L85)) -> scmi_process_message -> return the result msg buffer. ## Protocol Bus Registration (Linux) * A virtual scmi bus to handle SCMI device registration, such as clock, power, reset, ... etc. * struct bus_type scmi_bus_type {} * scmi_driver_register() and scmi_driver_unregister() * referred by helper macros: scmi_register and scmi_unregister() ## Driver registeration (Linux) * driver.c * An abstraction controller to initialize all arm_scmi **firmware** drivers and offer APIs to other subsystems' scmi driver. * Main flow * Initialize all SCMI supported drivers via driver/firmware/arm_scmi subsystem first. * base.c * Code impl for base protocols. * clock.c * perf.c * power.c * powercap.c * reset.c * sensors.c * system.c * voltage.c * When a specific subsystem's scmi driver is, * [struct scmi_protocol](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/protocols.h#n304) * Each SCMI **firmware** driver has to register a scmi_protocol, which declare ops, init/deinit functions, and event handlers * DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(reset, scmi_reset) * A helper to declare each type of scmi driver based on its **struct scmi_protocol**. * reset-scmi.c * * clock * [scmi_driver_init()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/driver.c#n2998) * arm_scmi/firmware procotol drivers' init entry. * Call each type of arm_scmi fw protocol driver registered via DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER. * Establish each protocol's register functions, which actually call scmi_protocol_register() and scmi_protocol_unregister() ## Transports * [struct scmi_transport_ops](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/common.h#n200) * A major DS to register callbacks needed by a specific tranposr, such as SMC or OPTEE, such as chan_setup, chan_free, send_message, mark_txdone, fet_response, .. etc. * [struct scmi_desc](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/common.h#n220) * A tranport descriptor which has a set of scmi_transport_ops and its related information such as max_msg, atomic_enabled, transport init/exit functions.. etc. * [Mailbox](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/mailbox.c#n235) * [OTEE](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/optee.c#n636) * [SMC call <Shared-memory based / MMIO>](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/smc.c#n227) * Still based on SMT but needs SMCCC to notify SCMI server. * Virtio ## S32G2 specific * SMC call handler * s32_svc_smc_handler * [code](https://github.com/nxp-auto-linux/arm-trusted-firmware/blob/release/bsp35.0-2.5/plat/nxp/s32/s32_svc.c#L115) * Registered as a [runtime service](https://github.com/nxp-auto-linux/arm-trusted-firmware/blob/release/bsp35.0-2.5/plat/nxp/s32/s32_svc.c#L139) (Fast Call) via the SMC function ID **0xc20000fe** * [EL3 Runtime Service Writer's Guide](https://trustedfirmware-a.readthedocs.io/en/latest/getting_started/rt-svc-writers-guide.html?highlight=SMC_TYPE_FAST#introduction) * NXP implemented the **PERF** protocol in their downstream TF-A. ## PSCI vs SCMI * Rich operating systems, like Linux and Windows, use PSCI for CPU and overall system power management. The interface covers the following scenarios: * Core idle management. * Power state system topologies and coordination * CPU hotplug and secondary CPU boot. * System shutdown and reset. * The interface **does not cover Dynamic Voltage and Frequency Scaling (DVFS) or device power management** (for example, management of peripherals, such as GPUs). **SCMI** does provide standard interfaces for this purpose. * Todo: TF-A vs SCP? ## TF-A working model * TF-A can implement PSCI directly, or proxy the PSCI requests to * SCMI framework is based on **SMC** instructions, which are defined by **[SMCCC](https://developer.arm.com/documentation/den0028/latest)**. * **Secure Monitor Call (SMC)** * In the Arm architecture, synchronous control is transferred between the normal Non-secure state and the Secure state through Secure Monitor Call (SMC) exceptions. SMC exceptions are generated by the SMC instruction, and are handled by the Secure Monitor. The operation of the Secure Monitor is determined by the parameters that are passed in through registers. * **Ref:** SMCCC spec 1.4, Section 2.1 ![](https://i.imgur.com/BT5YSWu.png) Diagram 2 ![](https://i.imgur.com/UBk7kfg.png) ## Linux Study ## How agents handle messages via SMC transport * U-Boot * drivers/firmware/scmi * [scmi_smccc_process_msg()](https://source.denx.de/u-boot/u-boot/-/blob/v2023.01/drivers/firmware/scmi/smccc_agent.c#L41) * Linux Kernel * drivers/firmware/arm_scmi * [smc_send_message()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/smc.c?h=v6.1#n179) * [smc_fetch_response()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/smc.c?h=v6.1#n204) * Synchronous mesg handling. * do_xfer() -> send_message() -> scmi_wait_for_message_response() -> wait_for_completion_timeout(&xfer->done, ...) * if poll_competion=1 (need transport support) * fetch_response -> * else (poll=0) * wait_for_completion_timeout(&xfer->done, ..) * Sync mesg handling with delayed response. * do_xfer_with_response() -> do_xfer() -> wait_for_completion_timeout(xfer->async_done, timeout) * Aasync mesg handler (Notification / Delayed Response) * In [smc_chan_setup()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/smc.c?h=v6.1#n100), an [smc_msg_done_isr()](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/firmware/arm_scmi/smc.c?h=v6.1#n45) can be registered for handling a specific interrupt called **a2p** although none of such interrupt is present in upstream kernel DT. * smc_msg_done_isr() -> scmi_rx_callback() -> * scmi_handle_notification or scmi_handle_response * scmi_handle_response() -> * **clear DELAYED_RESP flag:** complete(xfer->async_done); * **clear normal flag:**: complete(&xfer->done); ## References #### Tech overview of TF-A (2020 Open Source Summit North America) * https://www.youtube.com/watch?v=0ALBfpjJoC4 ### SCMI-SMC mediator * https://www.mail-archive.com/xen-devel@lists.xenproject.org/msg113864.html #### SCMI v2.0 presentation * LVC20: SCMI server in TEE * https://www.youtube.com/watch?v=67hCiGMikDc * LVC20: * https://www.youtube.com/watch?v=hrUDSjDjprE&list=PLKZSArYQptsMbk293t64TnZmxzLp-bRib * Some updates about v3.0, ACPI-compliant and Virtio transport. * A Guide to enabling new Power Management & System Control Models via Arm SCMIv2.0 (Linaro BKK 2019) * https://www.youtube.com/watch?v=ei341v8aQ4I&t=2s * SAN19-207 SCMI server in secure world (Linaro San Diego 2019) * https://www.youtube.com/watch?v=MvggjC3telA * Ref: https://linaroconnectsandiego.sched.com/speaker/souvik.chakravarty #### TEE impl in Linux kernel * https://www.youtube.com/watch?v=kk3_DUMJrTI ## Patches [0/2 Allow parameter in smc/hvc calls](https://lore.kernel.org/lkml/20230417174401.19563-1-quic_nkela@quicinc.com/T/) [v3 0/2 Add SCMI support for mailbox unidirectional channels](https://www.spinics.net/lists/arm-kernel/msg1061753.html) [rfc v1 0/2 Introducing generic SCMI pinctrl driver implementation](https://lore.kernel.org/linux-arm-kernel/ZDb8JvQd3Sv3xfRn@e120937-lin/T/) ## ToDo * What agents use SMT header in general? * **Shared Memory based Transport** could also mean **SMT**, please see SMCI v3.1 spec - **section 5.1.2** for the header/struct layout description. For example: * [The SMT header in u-boot](https://github.com/u-boot/u-boot/blob/master/drivers/firmware/scmi/smt.h#L19) * [struct scmi_shared_mem {} in kernel](https://github.com/torvalds/linux/blob/master/drivers/firmware/arm_scmi/shmem.c#L17) * [SMT header in TF-A](https://github.com/ARM-software/arm-trusted-firmware/blob/master/drivers/scmi-msg/smt.c#L25) * Merged u-boot [patch](https://patchwork.ozlabs.org/project/uboot/patch/20220531160929.931150-2-etienne.carriere@linaro.org/) related to SMT. * How SCMI works ARM RME [Realm Management Extensions]? * The Arm Realm Management Extension [RME, RMESYS] introduces two new Security States, Realm and Root, in addition to the existing Secure and Non-Secure states. It also adds two new Physical Address Spaces (PASs), Realm and Root, in addition to the existing Secure and Non-secure PAS. A system implementing SCMI can have channels residing in the Root, Secure, and Non-secure PAS. * Agents can be in the Root, Secure or Non-secure Security state. Access to resources through a channel in a specific PAS depends on the Security State of the agent making the access in accordance with RME PAS access rules, as specified in [RME]. The following table specifies the access rules in the context of SCMI agents, channels, and resources. ![](https://i.imgur.com/OkEdNkI.png) ![](https://i.imgur.com/RF8w408.png) * How Secure Monitor is implmeneted? * Who assigns agent IDs? * *[From spec]* The platform **statically assigns an agent identifier to every channel**. An agent can discover the identifier assigned to it through the channel that the agent owns. This discovery is done using the Base protocol. * In Linux kernel, SCMI init issues the BASE_DISCOVER_AGENT command with input agent id = 0 to discover itself. [Code](https://github.com/torvalds/linux/blob/master/drivers/firmware/arm_scmi/base.c#L250) * Differences between SCP and TF-A and What role that SCMI might have in them. **(Answered by chatGPT)** * ARM SCP (System Control Processor) firmware and ARM Trusted Firmware (ATF) are two different firmware components used in ARM-based systems, but they serve different purposes. ARM SCP firmware is responsible for managing the power, clock, and reset signals in the system, as well as controlling the boot process and initializing the system hardware. The SCP firmware runs on a separate processor core, usually a smaller and simpler core, that is dedicated to these tasks. On the other hand, ARM Trusted Firmware is a set of software components that provide a level of security and trust in the system. It includes a boot loader, a secure monitor, and other components that help establish a trusted execution environment (TEE) on the system. The ATF is responsible for verifying the integrity of the firmware and software components loaded during the boot process, and it provides a secure foundation for running other trusted software, such as a Trusted Execution Environment (TEE). * While the SCP firmware is focused on **low-level system management tasks**, the ATF is focused on **establishing a secure environment for running higher-level software**. Both firmware components are important for the proper operation and security of an ARM-based system, but they serve different purposes. * How SCP implements SCMI? * See [SCP_BL2](https://trustedfirmware-a.readthedocs.io/en/latest/design/firmware-design.html) * [TF-A on Juno](https://trustedfirmware-a.readthedocs.io/en/latest/plat/arm/juno/index.html) * [RFCs and P-Rs for building a SCMI server in OP-TEE ](https://github.com/ARM-software/SCP-firmware/issues/385) * How OPTEE-OS implements SCMI? * optee-os/core/drivers/scmi-msg/ * The alternative is to fetch/build from the SCP firmware's SCMI server tree via CFG_SCMI_SCPFW. * How does OP-TEE work with TF-A? * OP-TEE works as Secure-L1/BL32 in **secure** world, which also needs a separate build in order to be integrated with TF-A as we usually do for u-boot. * [An example of iMX.7](https://trustedfirmware-a.readthedocs.io/en/latest/plat/warp7.html#) * Boot-flow * BootROM –> TF-A BL2 –> BL32(OP-TEE) –> BL33(U-Boot) –> Linux * Upstream discussion * [Mixing SCMI and ACPI?](https://lore.kernel.org/linux-arm-kernel/20220207101024.rpcbbhtd6y6g7ykc@bogus/t/) * FastChannel related * In Linux kernel, only perf and powercap set FastChannel. * How SCMI works with PSCI in SCP * Having ACPI is just one of impl methods, the ACPI FW could also rely on SMC/FFA calls to work with FW (Such as AP<->TF-A) ![](https://i.imgur.com/TNBnY1L.png) * Interface != Firmware * PSCI and SCMI are just interface specs which defines protocols and communicate messages, which means they are abstractions rather than firmware implementations such as SCP or TF-A. * VirtIO scmi related * Jira [Stratos from Linaro](https://linaro.atlassian.net/jira/software/c/projects/STR/issues/STR-14?jql=project%20%3D%20%22STR%22%20AND%20text%20~%20%22SCMI%22%20ORDER%20BY%20created%20DESC) * Jira [SCMI-8: SCMI server in a VM](https://linaro.atlassian.net/browse/SCMI-8) * Jira [SCMI-21: Add SCMI server support in guest VM](https://linaro.atlassian.net/browse/SCMI-21)