firmware: imx: Add i.MX95 SCMI LMM driver
authorPeng Fan <peng.fan@nxp.com>
Tue, 8 Apr 2025 08:44:29 +0000 (16:44 +0800)
committerSudeep Holla <sudeep.holla@arm.com>
Mon, 14 Apr 2025 12:55:04 +0000 (13:55 +0100)
The i.MX95 System manager exports SCMI LMM protocol for linux to manage
Logical Machines. The driver is to use the LMM Protocol interface to
boot, shutdown a LM.

Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Message-Id: <20250408-imx-lmm-cpu-v4-5-4c5f4a456e49@nxp.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>
drivers/firmware/arm_scmi/vendors/imx/Kconfig
drivers/firmware/imx/Kconfig
drivers/firmware/imx/Makefile
drivers/firmware/imx/sm-lmm.c [new file with mode: 0644]
include/linux/firmware/imx/sm.h

index b5f13d0e40155e485f4d1696e9550645d888ef44..0a396d36262872d10ecb5be72d3dc855bf834165 100644 (file)
@@ -26,6 +26,7 @@ config IMX_SCMI_CPU_EXT
 config IMX_SCMI_LMM_EXT
        tristate "i.MX SCMI LMM EXTENSION"
        depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+       depends on IMX_SCMI_LMM_DRV
        default y if ARCH_MXC
        help
          This enables i.MX System Logical Machine Protocol to
index c964f4924359fcd375560ee8263021b0fe65db1b..cd4bf996fe612c1ce7f8cda5a38b05335948377b 100644 (file)
@@ -23,6 +23,17 @@ config IMX_SCU
          This driver manages the IPC interface between host CPU and the
          SCU firmware running on M4.
 
+config IMX_SCMI_LMM_DRV
+       tristate "IMX SCMI LMM Protocol driver"
+       depends on ARCH_MXC || COMPILE_TEST
+       default y if ARCH_MXC
+       help
+         The System Controller Management Interface firmware (SCMI FW) is
+         a low-level system function which runs on a dedicated Cortex-M
+         core that could provide Logical Machine management features.
+
+         This driver can also be built as a module.
+
 config IMX_SCMI_MISC_DRV
        tristate "IMX SCMI MISC Protocol driver"
        depends on ARCH_MXC || COMPILE_TEST
index 8d046c341be878bb6dd1e6277992ff66ae90e292..7762855d2a771169d4f1867d27e0d51be7c9ad03 100644 (file)
@@ -2,3 +2,4 @@
 obj-$(CONFIG_IMX_DSP)          += imx-dsp.o
 obj-$(CONFIG_IMX_SCU)          += imx-scu.o misc.o imx-scu-irq.o rm.o imx-scu-soc.o
 obj-${CONFIG_IMX_SCMI_MISC_DRV}        += sm-misc.o
+obj-${CONFIG_IMX_SCMI_LMM_DRV} += sm-lmm.o
diff --git a/drivers/firmware/imx/sm-lmm.c b/drivers/firmware/imx/sm-lmm.c
new file mode 100644 (file)
index 0000000..6807bf5
--- /dev/null
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright 2025 NXP
+ */
+
+#include <linux/firmware/imx/sm.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/scmi_protocol.h>
+#include <linux/scmi_imx_protocol.h>
+
+static const struct scmi_imx_lmm_proto_ops *imx_lmm_ops;
+static struct scmi_protocol_handle *ph;
+
+int scmi_imx_lmm_info(u32 lmid, struct scmi_imx_lmm_info *info)
+{
+       if (!ph)
+               return -EPROBE_DEFER;
+
+       if (!info)
+               return -EINVAL;
+
+       return imx_lmm_ops->lmm_info(ph, lmid, info);
+};
+EXPORT_SYMBOL(scmi_imx_lmm_info);
+
+int scmi_imx_lmm_reset_vector_set(u32 lmid, u32 cpuid, u32 flags, u64 vector)
+{
+       if (!ph)
+               return -EPROBE_DEFER;
+
+       return imx_lmm_ops->lmm_reset_vector_set(ph, lmid, cpuid, flags, vector);
+}
+EXPORT_SYMBOL(scmi_imx_lmm_reset_vector_set);
+
+int scmi_imx_lmm_operation(u32 lmid, enum scmi_imx_lmm_op op, u32 flags)
+{
+       if (!ph)
+               return -EPROBE_DEFER;
+
+       switch (op) {
+       case SCMI_IMX_LMM_BOOT:
+               return imx_lmm_ops->lmm_power_boot(ph, lmid, true);
+       case SCMI_IMX_LMM_POWER_ON:
+               return imx_lmm_ops->lmm_power_boot(ph, lmid, false);
+       case SCMI_IMX_LMM_SHUTDOWN:
+               return imx_lmm_ops->lmm_shutdown(ph, lmid, flags);
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+EXPORT_SYMBOL(scmi_imx_lmm_operation);
+
+static int scmi_imx_lmm_probe(struct scmi_device *sdev)
+{
+       const struct scmi_handle *handle = sdev->handle;
+
+       if (!handle)
+               return -ENODEV;
+
+       if (imx_lmm_ops) {
+               dev_err(&sdev->dev, "lmm already initialized\n");
+               return -EEXIST;
+       }
+
+       imx_lmm_ops = handle->devm_protocol_get(sdev, SCMI_PROTOCOL_IMX_LMM, &ph);
+       if (IS_ERR(imx_lmm_ops))
+               return PTR_ERR(imx_lmm_ops);
+
+       return 0;
+}
+
+static const struct scmi_device_id scmi_id_table[] = {
+       { SCMI_PROTOCOL_IMX_LMM, "imx-lmm" },
+       { },
+};
+MODULE_DEVICE_TABLE(scmi, scmi_id_table);
+
+static struct scmi_driver scmi_imx_lmm_driver = {
+       .name = "scmi-imx-lmm",
+       .probe = scmi_imx_lmm_probe,
+       .id_table = scmi_id_table,
+};
+module_scmi_driver(scmi_imx_lmm_driver);
+
+MODULE_AUTHOR("Peng Fan <peng.fan@nxp.com>");
+MODULE_DESCRIPTION("IMX SM LMM driver");
+MODULE_LICENSE("GPL");
index 9b85a3f028d1b0a5287b453eb3ad8412a363fe6c..bc27b04afb2f68b048955f51c07a106f4c7e5852 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/bitfield.h>
 #include <linux/errno.h>
+#include <linux/scmi_imx_protocol.h>
 #include <linux/types.h>
 
 #define SCMI_IMX_CTRL_PDM_CLK_SEL      0       /* AON PDM clock sel */
 int scmi_imx_misc_ctrl_get(u32 id, u32 *num, u32 *val);
 int scmi_imx_misc_ctrl_set(u32 id, u32 val);
 
+enum scmi_imx_lmm_op {
+       SCMI_IMX_LMM_BOOT,
+       SCMI_IMX_LMM_POWER_ON,
+       SCMI_IMX_LMM_SHUTDOWN,
+};
+
+/* For shutdown pperation */
+#define SCMI_IMX_LMM_OP_FORCEFUL       0
+#define SCMI_IMX_LMM_OP_GRACEFUL       BIT(0)
+
+int scmi_imx_lmm_operation(u32 lmid, enum scmi_imx_lmm_op op, u32 flags);
+int scmi_imx_lmm_info(u32 lmid, struct scmi_imx_lmm_info *info);
+int scmi_imx_lmm_reset_vector_set(u32 lmid, u32 cpuid, u32 flags, u64 vector);
 #endif