From 251dd6bf0e89a587710fa7bfa320088617f8854e Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 17:32:30 +0800 Subject: firmware: scmi: Conditionally compile protocol support Add conditional compilation for SCMI protocol support in scmi_get_protocol() and scmi_add_protocol() based on corresponding Kconfig options. This ensures that only the enabled protocols are compiled and accessed, and reducing binary size. Signed-off-by: Peng Fan Reviewed-by: Alice Guo --- drivers/firmware/scmi/scmi_agent-uclass.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index 69a277e8786..f48c2fdb27b 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -86,21 +86,31 @@ struct udevice *scmi_get_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_BASE: proto = priv->base_dev; break; +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) case SCMI_PROTOCOL_ID_POWER_DOMAIN: proto = priv->pwdom_dev; break; +#endif +#if IS_ENABLED(CONFIG_CLK_SCMI) case SCMI_PROTOCOL_ID_CLOCK: proto = priv->clock_dev; break; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) case SCMI_PROTOCOL_ID_RESET_DOMAIN: proto = priv->resetdom_dev; break; +#endif +#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: proto = priv->voltagedom_dev; break; +#endif +#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI) case SCMI_PROTOCOL_ID_PINCTRL: proto = priv->pinctrl_dev; break; +#endif default: dev_err(dev, "Protocol not supported\n"); proto = NULL; @@ -139,21 +149,31 @@ static int scmi_add_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_BASE: priv->base_dev = proto; break; +#if IS_ENABLED(CONFIG_SCMI_POWER_DOMAIN) case SCMI_PROTOCOL_ID_POWER_DOMAIN: priv->pwdom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_CLK_SCMI) case SCMI_PROTOCOL_ID_CLOCK: priv->clock_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_RESET_SCMI) case SCMI_PROTOCOL_ID_RESET_DOMAIN: priv->resetdom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_DM_REGULATOR_SCMI) case SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN: priv->voltagedom_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_PINCTRL_IMX_SCMI) case SCMI_PROTOCOL_ID_PINCTRL: priv->pinctrl_dev = proto; break; +#endif default: dev_err(dev, "Protocol not supported\n"); return -EPROTO; -- cgit v1.2.3 From 7830ccc77a13dd2a9880a942734bb5687416c4d8 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 17:32:32 +0800 Subject: firmware: scmi: Support probe vendor ID 0x80 and 0x82 Preparing to add i.MX LMM and CPU protocol driver, support probe SCMI vendor ID 0x80(i.MX SCMI LMM ID) and 0x82(i.MX SCMI CPU ID). And use Kconfig option to support conditional compilation. Signed-off-by: Peng Fan Reviewed-by: Alice Guo --- drivers/firmware/scmi/Kconfig | 6 ++++++ drivers/firmware/scmi/scmi_agent-uclass.c | 20 ++++++++++++++++++++ 2 files changed, 26 insertions(+) (limited to 'drivers') diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index 8cf85f0d7a1..dca8fed9bd2 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -41,3 +41,9 @@ config SCMI_AGENT_OPTEE help Enable the SCMI communication channel based on OP-TEE transport for compatible "linaro,scmi-optee". + +config SCMI_ID_VENDOR_80 + bool + +config SCMI_ID_VENDOR_82 + bool diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c index f48c2fdb27b..ad825d66da2 100644 --- a/drivers/firmware/scmi/scmi_agent-uclass.c +++ b/drivers/firmware/scmi/scmi_agent-uclass.c @@ -110,6 +110,16 @@ struct udevice *scmi_get_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_PINCTRL: proto = priv->pinctrl_dev; break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80) + case SCMI_PROTOCOL_ID_VENDOR_80: + proto = priv->vendor_dev_80; + break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) + case SCMI_PROTOCOL_ID_VENDOR_82: + proto = priv->vendor_dev_82; + break; #endif default: dev_err(dev, "Protocol not supported\n"); @@ -173,6 +183,16 @@ static int scmi_add_protocol(struct udevice *dev, case SCMI_PROTOCOL_ID_PINCTRL: priv->pinctrl_dev = proto; break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_80) + case SCMI_PROTOCOL_ID_VENDOR_80: + priv->vendor_dev_80 = proto; + break; +#endif +#if IS_ENABLED(CONFIG_SCMI_ID_VENDOR_82) + case SCMI_PROTOCOL_ID_VENDOR_82: + priv->vendor_dev_82 = proto; + break; #endif default: dev_err(dev, "Protocol not supported\n"); -- cgit v1.2.3 From 3f20ea3675c466ab16761c9b280e6c382bae02c3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 17:32:33 +0800 Subject: firmware: scmi: Add i.MX95 SCMI LMM protocol driver Add Logical Machine Management(LMM) protocol which is intended for boot, shutdown, and reset of other logical machines (LM). It is usually used to allow one LM to manager another used as an offload or accelerator engine. Following Linux Kernel, created a separate folder for holding vendor protocol drivers. Signed-off-by: Peng Fan Reviewed-by: Alice Guo --- drivers/firmware/scmi/Kconfig | 2 + drivers/firmware/scmi/Makefile | 1 + drivers/firmware/scmi/vendors/imx/Kconfig | 7 + drivers/firmware/scmi/vendors/imx/Makefile | 7 + drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c | 213 +++++++++++++++++++++++++ 5 files changed, 230 insertions(+) create mode 100644 drivers/firmware/scmi/vendors/imx/Kconfig create mode 100644 drivers/firmware/scmi/vendors/imx/Makefile create mode 100644 drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c (limited to 'drivers') diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig index dca8fed9bd2..33e089c460b 100644 --- a/drivers/firmware/scmi/Kconfig +++ b/drivers/firmware/scmi/Kconfig @@ -47,3 +47,5 @@ config SCMI_ID_VENDOR_80 config SCMI_ID_VENDOR_82 bool + +source "drivers/firmware/scmi/vendors/imx/Kconfig" diff --git a/drivers/firmware/scmi/Makefile b/drivers/firmware/scmi/Makefile index dae42863589..6129726f817 100644 --- a/drivers/firmware/scmi/Makefile +++ b/drivers/firmware/scmi/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_SCMI_AGENT_MAILBOX) += mailbox_agent.o obj-$(CONFIG_SCMI_AGENT_OPTEE) += optee_agent.o obj-$(CONFIG_SCMI_POWER_DOMAIN) += pwdom.o obj-$(CONFIG_SANDBOX) += sandbox-scmi_agent.o sandbox-scmi_devices.o +obj-y += vendors/imx/ diff --git a/drivers/firmware/scmi/vendors/imx/Kconfig b/drivers/firmware/scmi/vendors/imx/Kconfig new file mode 100644 index 00000000000..211bb1f2244 --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/Kconfig @@ -0,0 +1,7 @@ +config IMX_SM_LMM + bool "Enable i.MX System Manager Logical Machine API" + depends on ARCH_IMX9 && SCMI_FIRMWARE + select SCMI_ID_VENDOR_80 + help + If you say Y here to enable i.MX System Manager Logical Machine + API to work on some NXP i.MX processors. diff --git a/drivers/firmware/scmi/vendors/imx/Makefile b/drivers/firmware/scmi/vendors/imx/Makefile new file mode 100644 index 00000000000..6031ad80520 --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/Makefile @@ -0,0 +1,7 @@ +# +# Copyright 2025 NXP +# +# SPDX-License-Identifier: GPL-2.0+ +# + +obj-$(CONFIG_IMX_SM_LMM) += imx-sm-lmm.o diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c new file mode 100644 index 00000000000..2fd791ca853 --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i.MX SCMI LMM protocol + * + * Copyright 2025 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum scmi_imx_lmm_protocol_cmd { + SCMI_IMX_LMM_ATTRIBUTES = 0x3, + SCMI_IMX_LMM_BOOT = 0x4, + SCMI_IMX_LMM_RESET = 0x5, + SCMI_IMX_LMM_SHUTDOWN = 0x6, + SCMI_IMX_LMM_WAKE = 0x7, + SCMI_IMX_LMM_SUSPEND = 0x8, + SCMI_IMX_LMM_NOTIFY = 0x9, + SCMI_IMX_LMM_RESET_REASON = 0xA, + SCMI_IMX_LMM_POWER_ON = 0xB, + SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC, +}; + +struct scmi_imx_lmm_priv { + u32 nr_lmm; +}; + +struct scmi_msg_imx_lmm_attributes_out { + __le32 status; + __le32 lmid; + __le32 attributes; + __le32 state; + __le32 errstatus; + u8 name[LMM_MAX_NAME]; +}; + +struct scmi_imx_lmm_reset_vector_set_in { + __le32 lmid; + __le32 cpuid; + __le32 flags; /* reserved for future extension */ + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +struct scmi_imx_lmm_shutdown_in { + __le32 lmid; +#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0) + __le32 flags; +}; + +int scmi_imx_lmm_info(struct udevice *dev, u32 lmid, struct scmi_imx_lmm_info *info) +{ + struct scmi_msg_imx_lmm_attributes_out out; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_ATTRIBUTES, + .in_msg = (u8 *)&lmid, + .in_msg_sz = sizeof(lmid), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + status = cpu_to_le32(out.status); + if (status) + return scmi_to_linux_errno(status); + + info->lmid = le32_to_cpu(out.lmid); + info->state = le32_to_cpu(out.state); + info->errstatus = le32_to_cpu(out.errstatus); + strcpy(info->name, out.name); + dev_dbg(dev, "i.MX LMM: Logical Machine(%d), name: %s\n", + info->lmid, info->name); + + return ret; +} + +int scmi_imx_lmm_power_boot(struct udevice *dev, u32 lmid, bool boot) +{ + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_POWER_ON, + .in_msg = (u8 *)&lmid, + .in_msg_sz = sizeof(lmid), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + if (boot) + msg.message_id = SCMI_IMX_LMM_BOOT; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_lmm_reset_vector_set(struct udevice *dev, u32 lmid, u32 cpuid, u32 flags, u64 vector) +{ + struct scmi_imx_lmm_reset_vector_set_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_RESET_VECTOR_SET, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.lmid = lmid; + in.cpuid = cpuid; + in.flags = flags; + in.resetvectorlow = vector & 0xFFFFFFFF; + in.resetvectorhigh = vector >> 32; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flags) +{ + struct scmi_imx_lmm_shutdown_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_80, + .message_id = SCMI_IMX_LMM_SHUTDOWN, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.lmid = lmid; + if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL) + in.flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL); + else + in.flags = cpu_to_le32(0); + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +static int scmi_imx_lmm_probe(struct udevice *dev) +{ + int ret; + + ret = devm_scmi_of_get_channel(dev); + if (ret) { + dev_err(dev, "failed to get channel (%d)\n", ret); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(scmi_imx_lmm) = { + .name = "scmi_imx_lmm", + .id = UCLASS_SCMI_BASE, + .probe = scmi_imx_lmm_probe, + .priv_auto = sizeof(struct scmi_imx_lmm_priv), +}; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_VENDOR_80}, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_lmm, match); -- cgit v1.2.3 From ac9b02dd1028d14b6326970c93dfc3c50daa16f1 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Fri, 17 Oct 2025 17:32:34 +0800 Subject: firmware: scmi: Add i.MX95 SCMI CPU Protocol This protocol allows an agent to start, stop a CPU or set reset vector. It is used to manage auxiliary CPUs in an LM (e.g. additional cores in an AP cluster). Signed-off-by: Peng Fan Reviewed-by: Alice Guo --- drivers/firmware/scmi/vendors/imx/Kconfig | 8 ++ drivers/firmware/scmi/vendors/imx/Makefile | 1 + drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c | 179 +++++++++++++++++++++++++ 3 files changed, 188 insertions(+) create mode 100644 drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c (limited to 'drivers') diff --git a/drivers/firmware/scmi/vendors/imx/Kconfig b/drivers/firmware/scmi/vendors/imx/Kconfig index 211bb1f2244..16850502bbb 100644 --- a/drivers/firmware/scmi/vendors/imx/Kconfig +++ b/drivers/firmware/scmi/vendors/imx/Kconfig @@ -1,3 +1,11 @@ +config IMX_SM_CPU + bool "Enable i.MX System Manager CPU API" + depends on ARCH_IMX9 && SCMI_FIRMWARE + select SCMI_ID_VENDOR_82 + help + If you say Y here to enable i.MX System Manager CPU + API to work on some NXP i.MX processors. + config IMX_SM_LMM bool "Enable i.MX System Manager Logical Machine API" depends on ARCH_IMX9 && SCMI_FIRMWARE diff --git a/drivers/firmware/scmi/vendors/imx/Makefile b/drivers/firmware/scmi/vendors/imx/Makefile index 6031ad80520..59ff8640dc1 100644 --- a/drivers/firmware/scmi/vendors/imx/Makefile +++ b/drivers/firmware/scmi/vendors/imx/Makefile @@ -4,4 +4,5 @@ # SPDX-License-Identifier: GPL-2.0+ # +obj-$(CONFIG_IMX_SM_CPU) += imx-sm-cpu.o obj-$(CONFIG_IMX_SM_LMM) += imx-sm-lmm.o diff --git a/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c new file mode 100644 index 00000000000..28dfac642ec --- /dev/null +++ b/drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c @@ -0,0 +1,179 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i.MX SCMI CPU protocol + * + * Copyright 2025 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum scmi_imx_cpu_protocol_cmd { + SCMI_IMX_CPU_ATTRIBUTES = 0x3, + SCMI_IMX_CPU_START = 0x4, + SCMI_IMX_CPU_STOP = 0x5, + SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6, + SCMI_IMX_CPU_INFO_GET = 0xC, +}; + +struct scmi_imx_cpu_priv { + u32 nr_cpu; +}; + +struct scmi_imx_cpu_reset_vector_set_in { + __le32 cpuid; +#define CPU_VEC_FLAGS_RESUME BIT(31) +#define CPU_VEC_FLAGS_START BIT(30) +#define CPU_VEC_FLAGS_BOOT BIT(29) + __le32 flags; + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +struct scmi_imx_cpu_info_get_out { + __le32 status; +#define CPU_RUN_MODE_START 0 +#define CPU_RUN_MODE_HOLD 1 +#define CPU_RUN_MODE_STOP 2 +#define CPU_RUN_MODE_SLEEP 3 + __le32 runmode; + __le32 sleepmode; + __le32 resetvectorlow; + __le32 resetvectorhigh; +}; + +int scmi_imx_cpu_start(struct udevice *dev, u32 cpuid, bool start) +{ + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_STOP, + .in_msg = (u8 *)&cpuid, + .in_msg_sz = sizeof(cpuid), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + if (start) + msg.message_id = SCMI_IMX_CPU_START; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_cpu_reset_vector_set(struct udevice *dev, u32 cpuid, u32 flags, u64 vector, + bool start, bool boot, bool resume) +{ + struct scmi_imx_cpu_reset_vector_set_in in; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_RESET_VECTOR_SET, + .in_msg = (u8 *)&in, + .in_msg_sz = sizeof(in), + .out_msg = (u8 *)&status, + .out_msg_sz = sizeof(status), + }; + int ret; + + if (!dev) + return -EINVAL; + + in.cpuid = cpu_to_le32(cpuid); + in.flags = cpu_to_le32(0); + if (start) + in.flags |= CPU_VEC_FLAGS_START; + if (boot) + in.flags |= CPU_VEC_FLAGS_BOOT; + if (resume) + in.flags |= CPU_VEC_FLAGS_RESUME; + in.resetvectorlow = cpu_to_le32(lower_32_bits(vector)); + in.resetvectorhigh = cpu_to_le32(upper_32_bits(vector)); + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + if (status) + return scmi_to_linux_errno(status); + + return 0; +} + +int scmi_imx_cpu_started(struct udevice *dev, u32 cpuid, bool *started) +{ + struct scmi_imx_cpu_info_get_out out; + u32 mode; + s32 status; + struct scmi_msg msg = { + .protocol_id = SCMI_PROTOCOL_ID_VENDOR_82, + .message_id = SCMI_IMX_CPU_INFO_GET, + .in_msg = (u8 *)&cpuid, + .in_msg_sz = sizeof(cpuid), + .out_msg = (u8 *)&out, + .out_msg_sz = sizeof(out), + }; + int ret; + + if (!dev) + return -EINVAL; + + ret = devm_scmi_process_msg(dev, &msg); + if (ret) + return ret; + + status = cpu_to_le32(out.status); + if (status) + return scmi_to_linux_errno(status); + + mode = le32_to_cpu(out.runmode); + if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP) + *started = true; + + return 0; +} + +static int scmi_imx_cpu_probe(struct udevice *dev) +{ + int ret; + + ret = devm_scmi_of_get_channel(dev); + if (ret) { + dev_err(dev, "failed to get channel (%d)\n", ret); + return ret; + } + + return 0; +} + +U_BOOT_DRIVER(scmi_imx_cpu) = { + .name = "scmi_imx_cpu", + .id = UCLASS_SCMI_BASE, + .probe = scmi_imx_cpu_probe, + .priv_auto = sizeof(struct scmi_imx_cpu_priv), +}; + +static struct scmi_proto_match match[] = { + { .proto_id = SCMI_PROTOCOL_ID_VENDOR_82}, + { /* Sentinel */ } +}; + +U_BOOT_SCMI_PROTO_DRIVER(scmi_imx_cpu, match); -- cgit v1.2.3