From: Peng Fan Date: Fri, 17 Oct 2025 09:32:33 +0000 (+0800) Subject: firmware: scmi: Add i.MX95 SCMI LMM protocol driver X-Git-Tag: v2026.01-rc1~4^2~1 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3f20ea3675c466ab16761c9b280e6c382bae02c3;p=pandora-u-boot.git 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 --- 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); diff --git a/include/scmi_nxp_protocols.h b/include/scmi_nxp_protocols.h index 7e2143b16ea..1c79bc2282b 100644 --- a/include/scmi_nxp_protocols.h +++ b/include/scmi_nxp_protocols.h @@ -9,6 +9,7 @@ #include #include +#define SCMI_PROTOCOL_ID_IMX_LMM 0x80 #define SCMI_PROTOCOL_ID_IMX_MISC 0x84 #define SCMI_PAYLOAD_LEN 100 @@ -50,4 +51,48 @@ struct scmi_imx_misc_reset_reason_out { u32 extInfo[MISC_MAX_EXTINFO]; }; +#define LMM_ID_DISCOVER 0xFFFFFFFFU +#define LMM_MAX_NAME 16 + +enum scmi_imx_lmm_state { + LMM_STATE_LM_OFF, + LMM_STATE_LM_ON, + LMM_STATE_LM_SUSPEND, + LMM_STATE_LM_POWERED, +}; + +struct scmi_imx_lmm_info { + u32 lmid; + enum scmi_imx_lmm_state state; + u32 errstatus; + u8 name[LMM_MAX_NAME]; +}; + +#if IS_ENABLED(CONFIG_IMX_SM_LMM) +int scmi_imx_lmm_info(struct udevice *dev, u32 lmid, struct scmi_imx_lmm_info *info); +int scmi_imx_lmm_power_boot(struct udevice *dev, u32 lmid, bool boot); +int scmi_imx_lmm_reset_vector_set(struct udevice *dev, u32 lmid, u32 cpuid, u32 flags, u64 vector); +int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flags); +#else +static inline int scmi_imx_lmm_info(struct udevice *dev, u32 lmid, struct scmi_imx_lmm_info *info) +{ + return -EOPNOTSUPP; +} + +static inline int scmi_imx_lmm_power_boot(struct udevice *dev, u32 lmid, bool boot) +{ + return -EOPNOTSUPP; +} + +static inline int +scmi_imx_lmm_reset_vector_set(struct udevice *dev, u32 lmid, u32 cpuid, u32 flags, u64 vector) +{ + return -EOPNOTSUPP; +} + +static inline int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flags) +{ + return -EOPNOTSUPP; +} +#endif #endif