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 <peng.fan@nxp.com> Reviewed-by: Alice Guo <alice.guo@nxp.com>
This commit is contained in:
8
drivers/firmware/scmi/vendors/imx/Kconfig
vendored
8
drivers/firmware/scmi/vendors/imx/Kconfig
vendored
@@ -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
|
||||
|
||||
1
drivers/firmware/scmi/vendors/imx/Makefile
vendored
1
drivers/firmware/scmi/vendors/imx/Makefile
vendored
@@ -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
|
||||
|
||||
179
drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c
vendored
Normal file
179
drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c
vendored
Normal file
@@ -0,0 +1,179 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* i.MX SCMI CPU protocol
|
||||
*
|
||||
* Copyright 2025 NXP
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <misc.h>
|
||||
#include <scmi_agent.h>
|
||||
#include <scmi_agent-uclass.h>
|
||||
#include <scmi_protocols.h>
|
||||
#include <scmi_nxp_protocols.h>
|
||||
|
||||
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);
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#define SCMI_PROTOCOL_ID_IMX_LMM 0x80
|
||||
#define SCMI_PROTOCOL_ID_IMX_CPU 0x82
|
||||
#define SCMI_PROTOCOL_ID_IMX_MISC 0x84
|
||||
|
||||
#define SCMI_PAYLOAD_LEN 100
|
||||
@@ -95,4 +96,27 @@ static inline int scmi_imx_lmm_shutdown(struct udevice *dev, u32 lmid, bool flag
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if IS_ENABLED(CONFIG_IMX_SM_CPU)
|
||||
int scmi_imx_cpu_started(struct udevice *dev, u32 cpuid, bool *started);
|
||||
int scmi_imx_cpu_reset_vector_set(struct udevice *dev, u32 cpuid, u32 flags, u64 vector,
|
||||
bool start, bool boot, bool resume);
|
||||
int scmi_imx_cpu_start(struct udevice *dev, u32 cpuid, bool start);
|
||||
#else
|
||||
static inline int scmi_imx_cpu_started(struct udevice *dev, u32 cpuid, bool *started)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int scmi_imx_cpu_reset_vector_set(struct udevice *dev, u32 cpuid, u32 flags,
|
||||
u64 vector, bool start, bool boot, bool resume)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int scmi_imx_cpu_start(struct udevice *dev, u32 cpuid, bool start)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user