summaryrefslogtreecommitdiff
path: root/drivers/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/firmware')
-rw-r--r--drivers/firmware/firmware-zynqmp.c36
-rw-r--r--drivers/firmware/scmi/Kconfig8
-rw-r--r--drivers/firmware/scmi/Makefile1
-rw-r--r--drivers/firmware/scmi/sandbox-scmi_agent.c4
-rw-r--r--drivers/firmware/scmi/scmi_agent-uclass.c40
-rw-r--r--drivers/firmware/scmi/smt.c14
-rw-r--r--drivers/firmware/scmi/vendors/imx/Kconfig15
-rw-r--r--drivers/firmware/scmi/vendors/imx/Makefile8
-rw-r--r--drivers/firmware/scmi/vendors/imx/imx-sm-cpu.c179
-rw-r--r--drivers/firmware/scmi/vendors/imx/imx-sm-lmm.c213
-rw-r--r--drivers/firmware/ti_sci.c12
11 files changed, 496 insertions, 34 deletions
diff --git a/drivers/firmware/firmware-zynqmp.c b/drivers/firmware/firmware-zynqmp.c
index e07ec3929b2..3742467caee 100644
--- a/drivers/firmware/firmware-zynqmp.c
+++ b/drivers/firmware/firmware-zynqmp.c
@@ -3,6 +3,7 @@
* Xilinx Zynq MPSoC Firmware driver
*
* Copyright (C) 2018-2019 Xilinx, Inc.
+ * Copyright (C) 2022 - 2025, Advanced Micro Devices, Inc.
*/
#include <asm/arch/hardware.h>
@@ -158,7 +159,7 @@ unsigned int zynqmp_firmware_version(void)
if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) {
ret = xilinx_pm_request(PM_GET_API_VERSION, 0, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
panic("PMUFW is not found - Please load it!\n");
@@ -202,7 +203,7 @@ int zynqmp_pm_set_gem_config(u32 node, enum pm_gem_config_type config, u32 value
int ret;
ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_GEM_CONFIG,
- config, value, NULL);
+ config, value, 0, 0, NULL);
if (ret)
printf("%s: node %d: set_gem_config %d failed\n",
__func__, node, config);
@@ -215,7 +216,7 @@ int zynqmp_pm_set_sd_config(u32 node, enum pm_sd_config_type config, u32 value)
int ret;
ret = xilinx_pm_request(PM_IOCTL, node, IOCTL_SET_SD_CONFIG,
- config, value, NULL);
+ config, value, 0, 0, NULL);
if (ret)
printf("%s: node %d: set_sd_config %d failed\n",
__func__, node, config);
@@ -236,7 +237,7 @@ u32 zynqmp_pm_get_bootmode_reg(void)
}
ret = xilinx_pm_request(PM_IOCTL, CRP_BOOT_MODE_REG_NODE, IOCTL_READ_REG,
- CRP_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ CRP_BOOT_MODE_REG_OFFSET, 0, 0, 0, ret_payload);
if (ret) {
printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
__func__, CRP_BOOT_MODE_REG_NODE, CRP_BOOT_MODE_REG_OFFSET);
@@ -259,7 +260,8 @@ u32 zynqmp_pm_get_pmc_multi_boot_reg(void)
}
ret = xilinx_pm_request(PM_IOCTL, PM_REG_PMC_GLOBAL_NODE, IOCTL_READ_REG,
- PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, ret_payload);
+ PMC_MULTI_BOOT_MODE_REG_OFFSET, 0, 0, 0,
+ ret_payload);
if (ret) {
printf("%s: node 0x%x: get_bootmode 0x%x failed\n",
__func__, PM_REG_PMC_GLOBAL_NODE, PMC_MULTI_BOOT_MODE_REG_OFFSET);
@@ -276,7 +278,7 @@ int zynqmp_pm_feature(const u32 api_id)
/* Check feature check API version */
ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -296,7 +298,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
/* Check feature check API version */
ret = xilinx_pm_request(PM_FEATURE_CHECK, PM_FEATURE_CHECK, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -308,7 +310,7 @@ int zynqmp_pm_is_function_supported(const u32 api_id, const u32 id)
*/
ret = xilinx_pm_request(PM_FEATURE_CHECK, api_id, 0, 0, 0,
- ret_payload);
+ 0, 0, ret_payload);
if (ret)
return ret;
@@ -340,7 +342,7 @@ int zynqmp_pmufw_load_config_object(const void *cfg_obj, size_t size)
flush_dcache_range((ulong)cfg_obj, (ulong)(cfg_obj + size));
err = xilinx_pm_request(PM_SET_CONFIGURATION, (u32)(u64)cfg_obj, 0, 0,
- 0, ret_payload);
+ 0, 0, 0, ret_payload);
if (err == XST_PM_NO_ACCESS) {
return -EACCES;
}
@@ -425,13 +427,14 @@ U_BOOT_DRIVER(zynqmp_power) = {
smc_call_handler_t __data smc_call_handler;
static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
- u32 arg3, u32 *ret_payload)
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
struct pt_regs regs;
regs.regs[0] = PM_SIP_SVC | api_id;
regs.regs[1] = ((u64)arg1 << 32) | arg0;
regs.regs[2] = ((u64)arg3 << 32) | arg2;
+ regs.regs[3] = arg4;
smc_call(&regs);
@@ -441,16 +444,18 @@ static int smc_call_legacy(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
ret_payload[2] = (u32)regs.regs[1];
ret_payload[3] = upper_32_bits(regs.regs[1]);
ret_payload[4] = (u32)regs.regs[2];
+ ret_payload[5] = upper_32_bits((u32)regs.regs[2]);
+ ret_payload[6] = (u32)regs.regs[3];
}
return (ret_payload) ? ret_payload[0] : 0;
}
int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
- u32 arg3, u32 *ret_payload)
+ u32 arg3, u32 arg4, u32 arg5, u32 *ret_payload)
{
- debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n",
- __func__, current_el(), api_id, arg0, arg1, arg2, arg3);
+ debug("%s at EL%d, API ID: 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x, 0x%0x\n",
+ __func__, current_el(), api_id, arg0, arg1, arg2, arg3, arg4, arg5);
if (IS_ENABLED(CONFIG_XPL_BUILD) || current_el() == 3) {
#if defined(CONFIG_ZYNQMP_IPI)
@@ -459,7 +464,7 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
* is capable to handle PMUFW_PAYLOAD_ARG_CNT bytes but the
* firmware API is limited by the SMC call size
*/
- u32 regs[] = {api_id, arg0, arg1, arg2, arg3};
+ u32 regs[] = {api_id, arg0, arg1, arg2, arg3, arg4, arg5};
int ret;
if (api_id == PM_FPGA_LOAD) {
@@ -481,7 +486,8 @@ int __maybe_unused xilinx_pm_request(u32 api_id, u32 arg0, u32 arg1, u32 arg2,
#endif
}
- return smc_call_handler(api_id, arg0, arg1, arg2, arg3, ret_payload);
+ return smc_call_handler(api_id, arg0, arg1, arg2, arg3, arg4,
+ arg5, ret_payload);
}
static const struct udevice_id zynqmp_firmware_ids[] = {
diff --git a/drivers/firmware/scmi/Kconfig b/drivers/firmware/scmi/Kconfig
index 8cf85f0d7a1..33e089c460b 100644
--- a/drivers/firmware/scmi/Kconfig
+++ b/drivers/firmware/scmi/Kconfig
@@ -41,3 +41,11 @@ 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
+
+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/sandbox-scmi_agent.c b/drivers/firmware/scmi/sandbox-scmi_agent.c
index 74a87832dcb..5b242a039c2 100644
--- a/drivers/firmware/scmi/sandbox-scmi_agent.c
+++ b/drivers/firmware/scmi/sandbox-scmi_agent.c
@@ -828,7 +828,7 @@ static int sandbox_scmi_clock_rate_get(struct udevice *dev,
static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
{
- struct scmi_clk_state_in *in = NULL;
+ struct scmi_clk_state_in_v1 *in = NULL;
struct scmi_clk_state_out *out = NULL;
struct sandbox_scmi_clk *clk_state = NULL;
@@ -836,7 +836,7 @@ static int sandbox_scmi_clock_gate(struct udevice *dev, struct scmi_msg *msg)
!msg->out_msg || msg->out_msg_sz < sizeof(*out))
return -EINVAL;
- in = (struct scmi_clk_state_in *)msg->in_msg;
+ in = (struct scmi_clk_state_in_v1 *)msg->in_msg;
out = (struct scmi_clk_state_out *)msg->out_msg;
clk_state = get_scmi_clk_state(in->clock_id);
diff --git a/drivers/firmware/scmi/scmi_agent-uclass.c b/drivers/firmware/scmi/scmi_agent-uclass.c
index 69a277e8786..ad825d66da2 100644
--- a/drivers/firmware/scmi/scmi_agent-uclass.c
+++ b/drivers/firmware/scmi/scmi_agent-uclass.c
@@ -86,21 +86,41 @@ 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
+#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");
proto = NULL;
@@ -139,21 +159,41 @@ 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
+#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");
return -EPROTO;
diff --git a/drivers/firmware/scmi/smt.c b/drivers/firmware/scmi/smt.c
index 237871559f0..cd1c0801f72 100644
--- a/drivers/firmware/scmi/smt.c
+++ b/drivers/firmware/scmi/smt.c
@@ -61,20 +61,6 @@ int scmi_dt_get_smt_buffer(struct udevice *dev, struct scmi_smt *smt)
if (device_is_compatible(dev, "arm,scmi") && ofnode_has_property(dev_ofnode(dev), "mboxes"))
scmi_smt_enable_intr(smt, true);
-#ifdef CONFIG_ARM
- if (dcache_status()) {
- u32 align_size;
-
- if (IS_ENABLED(CONFIG_ARM64))
- align_size = PAGE_SIZE;
- else
- align_size = MMU_SECTION_SIZE;
-
- mmu_set_region_dcache_behaviour(ALIGN_DOWN((uintptr_t)smt->buf, align_size),
- ALIGN(smt->size, align_size), DCACHE_OFF);
- }
-#endif
-
return 0;
}
diff --git a/drivers/firmware/scmi/vendors/imx/Kconfig b/drivers/firmware/scmi/vendors/imx/Kconfig
new file mode 100644
index 00000000000..16850502bbb
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/Kconfig
@@ -0,0 +1,15 @@
+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
+ 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..59ff8640dc1
--- /dev/null
+++ b/drivers/firmware/scmi/vendors/imx/Makefile
@@ -0,0 +1,8 @@
+#
+# Copyright 2025 NXP
+#
+# 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 <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);
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 <compiler.h>
+#include <dm.h>
+#include <dm/device_compat.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_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/drivers/firmware/ti_sci.c b/drivers/firmware/ti_sci.c
index 8013afef304..6f57dcfe8de 100644
--- a/drivers/firmware/ti_sci.c
+++ b/drivers/firmware/ti_sci.c
@@ -191,9 +191,9 @@ static int ti_sci_get_response(struct ti_sci_info *info,
/* Sanity check for message response */
if (hdr->seq != info->seq) {
- dev_dbg(info->dev, "%s: Message for %d is not expected\n",
+ dev_err(info->dev, "%s: Message for %d is not expected\n",
__func__, hdr->seq);
- return ret;
+ return -EINVAL;
}
if (msg->len > info->desc->max_msg_size) {
@@ -1365,6 +1365,8 @@ static int ti_sci_cmd_clk_get_parent(const struct ti_sci_handle *handle,
if (ret)
return ret;
+ resp = (struct ti_sci_msg_resp_get_clock_parent *)xfer->tx_message.buf;
+
*parent_id = resp->parent_id;
return ret;
@@ -3083,7 +3085,10 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
dev_err(dev, "%s resource type ids not available\n", of_prop);
return ERR_PTR(sets);
}
- temp = malloc(sets);
+ temp = devm_kmalloc(dev, sets, GFP_KERNEL);
+ if (!temp)
+ return ERR_PTR(-ENOMEM);
+
sets /= sizeof(u32);
res->sets = sets;
@@ -3123,6 +3128,7 @@ devm_ti_sci_get_of_resource(const struct ti_sci_handle *handle,
return ERR_PTR(-ENOMEM);
}
+ devm_kfree(dev, temp);
if (valid_set)
return res;