Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-cpu.c
26498 views
// SPDX-License-Identifier: GPL-2.01/*2* System control and Management Interface (SCMI) NXP CPU 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_cpu_protocol_cmd {21SCMI_IMX_CPU_ATTRIBUTES = 0x3,22SCMI_IMX_CPU_START = 0x4,23SCMI_IMX_CPU_STOP = 0x5,24SCMI_IMX_CPU_RESET_VECTOR_SET = 0x6,25SCMI_IMX_CPU_INFO_GET = 0xC,26};2728struct scmi_imx_cpu_info {29u32 nr_cpu;30};3132#define SCMI_IMX_CPU_NR_CPU_MASK GENMASK(15, 0)33struct scmi_msg_imx_cpu_protocol_attributes {34__le32 attributes;35};3637struct scmi_msg_imx_cpu_attributes_out {38__le32 attributes;39#define CPU_MAX_NAME 1640u8 name[CPU_MAX_NAME];41};4243struct scmi_imx_cpu_reset_vector_set_in {44__le32 cpuid;45#define CPU_VEC_FLAGS_RESUME BIT(31)46#define CPU_VEC_FLAGS_START BIT(30)47#define CPU_VEC_FLAGS_BOOT BIT(29)48__le32 flags;49__le32 resetvectorlow;50__le32 resetvectorhigh;51};5253struct scmi_imx_cpu_info_get_out {54#define CPU_RUN_MODE_START 055#define CPU_RUN_MODE_HOLD 156#define CPU_RUN_MODE_STOP 257#define CPU_RUN_MODE_SLEEP 358__le32 runmode;59__le32 sleepmode;60__le32 resetvectorlow;61__le32 resetvectorhigh;62};6364static int scmi_imx_cpu_validate_cpuid(const struct scmi_protocol_handle *ph,65u32 cpuid)66{67struct scmi_imx_cpu_info *info = ph->get_priv(ph);6869if (cpuid >= info->nr_cpu)70return -EINVAL;7172return 0;73}7475static int scmi_imx_cpu_start(const struct scmi_protocol_handle *ph,76u32 cpuid, bool start)77{78struct scmi_xfer *t;79u8 msg_id;80int ret;8182ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);83if (ret)84return ret;8586if (start)87msg_id = SCMI_IMX_CPU_START;88else89msg_id = SCMI_IMX_CPU_STOP;9091ret = ph->xops->xfer_get_init(ph, msg_id, sizeof(u32), 0, &t);92if (ret)93return ret;9495put_unaligned_le32(cpuid, t->tx.buf);96ret = ph->xops->do_xfer(ph, t);9798ph->xops->xfer_put(ph, t);99100return ret;101}102103static int scmi_imx_cpu_reset_vector_set(const struct scmi_protocol_handle *ph,104u32 cpuid, u64 vector, bool start,105bool boot, bool resume)106{107struct scmi_imx_cpu_reset_vector_set_in *in;108struct scmi_xfer *t;109int ret;110111ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);112if (ret)113return ret;114115ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_RESET_VECTOR_SET, sizeof(*in),1160, &t);117if (ret)118return ret;119120in = t->tx.buf;121in->cpuid = cpu_to_le32(cpuid);122in->flags = cpu_to_le32(0);123if (start)124in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_START);125if (boot)126in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_BOOT);127if (resume)128in->flags |= le32_encode_bits(1, CPU_VEC_FLAGS_RESUME);129in->resetvectorlow = cpu_to_le32(lower_32_bits(vector));130in->resetvectorhigh = cpu_to_le32(upper_32_bits(vector));131ret = ph->xops->do_xfer(ph, t);132133ph->xops->xfer_put(ph, t);134135return ret;136}137138static int scmi_imx_cpu_started(const struct scmi_protocol_handle *ph, u32 cpuid,139bool *started)140{141struct scmi_imx_cpu_info_get_out *out;142struct scmi_xfer *t;143u32 mode;144int ret;145146if (!started)147return -EINVAL;148149*started = false;150ret = scmi_imx_cpu_validate_cpuid(ph, cpuid);151if (ret)152return ret;153154ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_INFO_GET, sizeof(u32),1550, &t);156if (ret)157return ret;158159put_unaligned_le32(cpuid, t->tx.buf);160ret = ph->xops->do_xfer(ph, t);161if (!ret) {162out = t->rx.buf;163mode = le32_to_cpu(out->runmode);164if (mode == CPU_RUN_MODE_START || mode == CPU_RUN_MODE_SLEEP)165*started = true;166}167168ph->xops->xfer_put(ph, t);169170return ret;171}172173static const struct scmi_imx_cpu_proto_ops scmi_imx_cpu_proto_ops = {174.cpu_reset_vector_set = scmi_imx_cpu_reset_vector_set,175.cpu_start = scmi_imx_cpu_start,176.cpu_started = scmi_imx_cpu_started,177};178179static int scmi_imx_cpu_protocol_attributes_get(const struct scmi_protocol_handle *ph,180struct scmi_imx_cpu_info *info)181{182struct scmi_msg_imx_cpu_protocol_attributes *attr;183struct scmi_xfer *t;184int ret;185186ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,187sizeof(*attr), &t);188if (ret)189return ret;190191attr = t->rx.buf;192193ret = ph->xops->do_xfer(ph, t);194if (!ret) {195info->nr_cpu = le32_get_bits(attr->attributes, SCMI_IMX_CPU_NR_CPU_MASK);196dev_info(ph->dev, "i.MX SM CPU: %d cpus\n",197info->nr_cpu);198}199200ph->xops->xfer_put(ph, t);201202return ret;203}204205static int scmi_imx_cpu_attributes_get(const struct scmi_protocol_handle *ph,206u32 cpuid)207{208struct scmi_msg_imx_cpu_attributes_out *out;209char name[SCMI_SHORT_NAME_MAX_SIZE] = {'\0'};210struct scmi_xfer *t;211int ret;212213ret = ph->xops->xfer_get_init(ph, SCMI_IMX_CPU_ATTRIBUTES, sizeof(u32), 0, &t);214if (ret)215return ret;216217put_unaligned_le32(cpuid, t->tx.buf);218ret = ph->xops->do_xfer(ph, t);219if (!ret) {220out = t->rx.buf;221strscpy(name, out->name, SCMI_SHORT_NAME_MAX_SIZE);222dev_info(ph->dev, "i.MX CPU: name: %s\n", name);223} else {224dev_err(ph->dev, "i.MX cpu: Failed to get info of cpu(%u)\n", cpuid);225}226227ph->xops->xfer_put(ph, t);228229return ret;230}231232static int scmi_imx_cpu_protocol_init(const struct scmi_protocol_handle *ph)233{234struct scmi_imx_cpu_info *info;235u32 version;236int ret, i;237238ret = ph->xops->version_get(ph, &version);239if (ret)240return ret;241242dev_info(ph->dev, "NXP SM CPU Protocol Version %d.%d\n",243PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));244245info = devm_kzalloc(ph->dev, sizeof(*info), GFP_KERNEL);246if (!info)247return -ENOMEM;248249ret = scmi_imx_cpu_protocol_attributes_get(ph, info);250if (ret)251return ret;252253for (i = 0; i < info->nr_cpu; i++) {254ret = scmi_imx_cpu_attributes_get(ph, i);255if (ret)256return ret;257}258259return ph->set_priv(ph, info, version);260}261262static const struct scmi_protocol scmi_imx_cpu = {263.id = SCMI_PROTOCOL_IMX_CPU,264.owner = THIS_MODULE,265.instance_init = &scmi_imx_cpu_protocol_init,266.ops = &scmi_imx_cpu_proto_ops,267.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,268.vendor_id = SCMI_IMX_VENDOR,269.sub_vendor_id = SCMI_IMX_SUBVENDOR,270};271module_scmi_protocol(scmi_imx_cpu);272273MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_CPU) "-" SCMI_IMX_VENDOR);274MODULE_DESCRIPTION("i.MX SCMI CPU driver");275MODULE_LICENSE("GPL");276277278