Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-lmm.c
26498 views
// SPDX-License-Identifier: GPL-2.01/*2* System control and Management Interface (SCMI) NXP LMM Protocol3*4* Copyright 2025 NXP5*/67#include <linux/bits.h>8#include <linux/io.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/platform_device.h>12#include <linux/scmi_protocol.h>13#include <linux/scmi_imx_protocol.h>1415#include "../../protocols.h"16#include "../../notify.h"1718#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x100001920enum scmi_imx_lmm_protocol_cmd {21SCMI_IMX_LMM_ATTRIBUTES = 0x3,22SCMI_IMX_LMM_BOOT = 0x4,23SCMI_IMX_LMM_RESET = 0x5,24SCMI_IMX_LMM_SHUTDOWN = 0x6,25SCMI_IMX_LMM_WAKE = 0x7,26SCMI_IMX_LMM_SUSPEND = 0x8,27SCMI_IMX_LMM_NOTIFY = 0x9,28SCMI_IMX_LMM_RESET_REASON = 0xA,29SCMI_IMX_LMM_POWER_ON = 0xB,30SCMI_IMX_LMM_RESET_VECTOR_SET = 0xC,31};3233struct scmi_imx_lmm_priv {34u32 nr_lmm;35};3637#define SCMI_IMX_LMM_NR_LM_MASK GENMASK(5, 0)38#define SCMI_IMX_LMM_NR_MAX 1639struct scmi_msg_imx_lmm_protocol_attributes {40__le32 attributes;41};4243struct scmi_msg_imx_lmm_attributes_out {44__le32 lmid;45__le32 attributes;46__le32 state;47__le32 errstatus;48u8 name[LMM_MAX_NAME];49};5051struct scmi_imx_lmm_reset_vector_set_in {52__le32 lmid;53__le32 cpuid;54__le32 flags; /* reserved for future extension */55__le32 resetvectorlow;56__le32 resetvectorhigh;57};5859struct scmi_imx_lmm_shutdown_in {60__le32 lmid;61#define SCMI_IMX_LMM_SHUTDOWN_GRACEFUL BIT(0)62__le32 flags;63};6465static int scmi_imx_lmm_validate_lmid(const struct scmi_protocol_handle *ph, u32 lmid)66{67struct scmi_imx_lmm_priv *priv = ph->get_priv(ph);6869if (lmid >= priv->nr_lmm)70return -EINVAL;7172return 0;73}7475static int scmi_imx_lmm_attributes(const struct scmi_protocol_handle *ph,76u32 lmid, struct scmi_imx_lmm_info *info)77{78struct scmi_msg_imx_lmm_attributes_out *out;79struct scmi_xfer *t;80int ret;8182ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_ATTRIBUTES, sizeof(u32), 0, &t);83if (ret)84return ret;8586put_unaligned_le32(lmid, t->tx.buf);87ret = ph->xops->do_xfer(ph, t);88if (!ret) {89out = t->rx.buf;90info->lmid = le32_to_cpu(out->lmid);91info->state = le32_to_cpu(out->state);92info->errstatus = le32_to_cpu(out->errstatus);93strscpy(info->name, out->name);94dev_dbg(ph->dev, "i.MX LMM: Logical Machine(%d), name: %s\n",95info->lmid, info->name);96} else {97dev_err(ph->dev, "i.MX LMM: Failed to get info of Logical Machine(%u)\n", lmid);98}99100ph->xops->xfer_put(ph, t);101102return ret;103}104105static int106scmi_imx_lmm_power_boot(const struct scmi_protocol_handle *ph, u32 lmid, bool boot)107{108struct scmi_xfer *t;109u8 msg_id;110int ret;111112ret = scmi_imx_lmm_validate_lmid(ph, lmid);113if (ret)114return ret;115116if (boot)117msg_id = SCMI_IMX_LMM_BOOT;118else119msg_id = SCMI_IMX_LMM_POWER_ON;120121ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t);122if (ret)123return ret;124125put_unaligned_le32(lmid, t->tx.buf);126ret = ph->xops->do_xfer(ph, t);127128ph->xops->xfer_put(ph, t);129130return ret;131}132133static int scmi_imx_lmm_reset_vector_set(const struct scmi_protocol_handle *ph,134u32 lmid, u32 cpuid, u32 flags, u64 vector)135{136struct scmi_imx_lmm_reset_vector_set_in *in;137struct scmi_xfer *t;138int ret;139140ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_RESET_VECTOR_SET, sizeof(*in),1410, &t);142if (ret)143return ret;144145in = t->tx.buf;146in->lmid = cpu_to_le32(lmid);147in->cpuid = cpu_to_le32(cpuid);148in->flags = cpu_to_le32(0);149in->resetvectorlow = cpu_to_le32(lower_32_bits(vector));150in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector));151ret = ph->xops->do_xfer(ph, t);152153ph->xops->xfer_put(ph, t);154155return ret;156}157158static int scmi_imx_lmm_shutdown(const struct scmi_protocol_handle *ph, u32 lmid,159u32 flags)160{161struct scmi_imx_lmm_shutdown_in *in;162struct scmi_xfer *t;163int ret;164165ret = scmi_imx_lmm_validate_lmid(ph, lmid);166if (ret)167return ret;168169ret = ph->xops->xfer_get_init(ph, SCMI_IMX_LMM_SHUTDOWN, sizeof(*in),1700, &t);171if (ret)172return ret;173174in = t->tx.buf;175in->lmid = cpu_to_le32(lmid);176if (flags & SCMI_IMX_LMM_SHUTDOWN_GRACEFUL)177in->flags = cpu_to_le32(SCMI_IMX_LMM_SHUTDOWN_GRACEFUL);178else179in->flags = cpu_to_le32(0);180ret = ph->xops->do_xfer(ph, t);181182ph->xops->xfer_put(ph, t);183184return ret;185}186187static const struct scmi_imx_lmm_proto_ops scmi_imx_lmm_proto_ops = {188.lmm_power_boot = scmi_imx_lmm_power_boot,189.lmm_info = scmi_imx_lmm_attributes,190.lmm_reset_vector_set = scmi_imx_lmm_reset_vector_set,191.lmm_shutdown = scmi_imx_lmm_shutdown,192};193194static int scmi_imx_lmm_protocol_attributes_get(const struct scmi_protocol_handle *ph,195struct scmi_imx_lmm_priv *priv)196{197struct scmi_msg_imx_lmm_protocol_attributes *attr;198struct scmi_xfer *t;199int ret;200201ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,202sizeof(*attr), &t);203if (ret)204return ret;205206attr = t->rx.buf;207208ret = ph->xops->do_xfer(ph, t);209if (!ret) {210priv->nr_lmm = le32_get_bits(attr->attributes, SCMI_IMX_LMM_NR_LM_MASK);211if (priv->nr_lmm > SCMI_IMX_LMM_NR_MAX) {212dev_err(ph->dev, "i.MX LMM: %d:Exceed max supported Logical Machines\n",213priv->nr_lmm);214ret = -EINVAL;215} else {216dev_info(ph->dev, "i.MX LMM: %d Logical Machines\n", priv->nr_lmm);217}218}219220ph->xops->xfer_put(ph, t);221222return ret;223}224225static int scmi_imx_lmm_protocol_init(const struct scmi_protocol_handle *ph)226{227struct scmi_imx_lmm_priv *info;228u32 version;229int ret;230231ret = ph->xops->version_get(ph, &version);232if (ret)233return ret;234235dev_info(ph->dev, "NXP SM LMM Version %d.%d\n",236PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));237238info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);239if (!info)240return -ENOMEM;241242ret = scmi_imx_lmm_protocol_attributes_get(ph, info);243if (ret)244return ret;245246return ph->set_priv(ph, info, version);247}248249static const struct scmi_protocol scmi_imx_lmm = {250.id = SCMI_PROTOCOL_IMX_LMM,251.owner = THIS_MODULE,252.instance_init = &scmi_imx_lmm_protocol_init,253.ops = &scmi_imx_lmm_proto_ops,254.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,255.vendor_id = SCMI_IMX_VENDOR,256.sub_vendor_id = SCMI_IMX_SUBVENDOR,257};258module_scmi_protocol(scmi_imx_lmm);259260MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_LMM) "-" SCMI_IMX_VENDOR);261MODULE_DESCRIPTION("i.MX SCMI LMM driver");262MODULE_LICENSE("GPL");263264265