Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
29286 views
// SPDX-License-Identifier: GPL-2.01/*2* System control and Management Interface (SCMI) NXP MISC Protocol3*4* Copyright 2024 NXP5*/67#define pr_fmt(fmt) "SCMI Notifications MISC - " fmt89#include <linux/bits.h>10#include <linux/io.h>11#include <linux/module.h>12#include <linux/of.h>13#include <linux/platform_device.h>14#include <linux/scmi_protocol.h>15#include <linux/scmi_imx_protocol.h>1617#include "../../protocols.h"18#include "../../notify.h"1920#define SCMI_PROTOCOL_SUPPORTED_VERSION 0x100002122#define MAX_MISC_CTRL_SOURCES GENMASK(15, 0)2324enum scmi_imx_misc_protocol_cmd {25SCMI_IMX_MISC_CTRL_SET = 0x3,26SCMI_IMX_MISC_CTRL_GET = 0x4,27SCMI_IMX_MISC_DISCOVER_BUILD_INFO = 0x6,28SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,29SCMI_IMX_MISC_CFG_INFO_GET = 0xC,30SCMI_IMX_MISC_BOARD_INFO = 0xE,31};3233struct scmi_imx_misc_info {34u32 version;35u32 nr_dev_ctrl;36u32 nr_brd_ctrl;37u32 nr_reason;38};3940struct scmi_msg_imx_misc_protocol_attributes {41__le32 attributes;42};4344#define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24))45#define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16))46#define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0))47#define BRD_CTRL_START_ID BIT(15)4849struct scmi_imx_misc_ctrl_set_in {50__le32 id;51__le32 num;52__le32 value[];53};5455struct scmi_imx_misc_ctrl_notify_in {56__le32 ctrl_id;57__le32 flags;58};5960struct scmi_imx_misc_ctrl_notify_payld {61__le32 ctrl_id;62__le32 flags;63};6465struct scmi_imx_misc_ctrl_get_out {66__le32 num;67__le32 val[];68};6970struct scmi_imx_misc_buildinfo_out {71__le32 buildnum;72__le32 buildcommit;73#define MISC_MAX_BUILDDATE 1674u8 builddate[MISC_MAX_BUILDDATE];75#define MISC_MAX_BUILDTIME 1676u8 buildtime[MISC_MAX_BUILDTIME];77};7879struct scmi_imx_misc_board_info_out {80__le32 attributes;81#define MISC_MAX_BRDNAME 1682u8 brdname[MISC_MAX_BRDNAME];83};8485struct scmi_imx_misc_cfg_info_out {86__le32 msel;87#define MISC_MAX_CFGNAME 1688u8 cfgname[MISC_MAX_CFGNAME];89};9091static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,92struct scmi_imx_misc_info *mi)93{94int ret;95struct scmi_xfer *t;96struct scmi_msg_imx_misc_protocol_attributes *attr;9798ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,99sizeof(*attr), &t);100if (ret)101return ret;102103attr = t->rx.buf;104105ret = ph->xops->do_xfer(ph, t);106if (!ret) {107mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);108mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);109mi->nr_reason = GET_REASONS_NR(attr->attributes);110dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",111mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);112}113114ph->xops->xfer_put(ph, t);115116return ret;117}118119static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,120u32 ctrl_id)121{122struct scmi_imx_misc_info *mi = ph->get_priv(ph);123124/*125* [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related126* [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related127*/128if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)129return -EINVAL;130if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)131return -EINVAL;132133return 0;134}135136static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,137u32 ctrl_id, u32 evt_id, u32 flags)138{139struct scmi_imx_misc_ctrl_notify_in *in;140struct scmi_xfer *t;141int ret;142143ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);144if (ret)145return ret;146147ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,148sizeof(*in), 0, &t);149if (ret)150return ret;151152in = t->tx.buf;153in->ctrl_id = cpu_to_le32(ctrl_id);154in->flags = cpu_to_le32(flags);155156ret = ph->xops->do_xfer(ph, t);157158ph->xops->xfer_put(ph, t);159160return ret;161}162163static int164scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,165u8 evt_id, u32 src_id, bool enable)166{167int ret;168169/* misc_ctrl_req_notify is for enablement */170if (enable)171return 0;172173ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);174if (ret)175dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",176evt_id, src_id, ret);177178return ret;179}180181static void *182scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,183u8 evt_id, ktime_t timestamp,184const void *payld, size_t payld_sz,185void *report, u32 *src_id)186{187const struct scmi_imx_misc_ctrl_notify_payld *p = payld;188struct scmi_imx_misc_ctrl_notify_report *r = report;189190if (sizeof(*p) != payld_sz)191return NULL;192193r->timestamp = timestamp;194r->ctrl_id = le32_to_cpu(p->ctrl_id);195r->flags = le32_to_cpu(p->flags);196if (src_id)197*src_id = r->ctrl_id;198dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,199r->ctrl_id, r->flags);200201return r;202}203204static const struct scmi_event_ops scmi_imx_misc_event_ops = {205.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,206.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,207};208209static const struct scmi_event scmi_imx_misc_events[] = {210{211.id = SCMI_EVENT_IMX_MISC_CONTROL,212.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),213.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),214},215};216217static struct scmi_protocol_events scmi_imx_misc_protocol_events = {218.queue_sz = SCMI_PROTO_QUEUE_SZ,219.ops = &scmi_imx_misc_event_ops,220.evts = scmi_imx_misc_events,221.num_events = ARRAY_SIZE(scmi_imx_misc_events),222.num_sources = MAX_MISC_CTRL_SOURCES,223};224225static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,226u32 ctrl_id, u32 *num, u32 *val)227{228struct scmi_imx_misc_ctrl_get_out *out;229struct scmi_xfer *t;230int ret, i;231int max_msg_size = ph->hops->get_max_msg_size(ph);232int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);233234ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);235if (ret)236return ret;237238ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),2390, &t);240if (ret)241return ret;242243put_unaligned_le32(ctrl_id, t->tx.buf);244ret = ph->xops->do_xfer(ph, t);245if (!ret) {246out = t->rx.buf;247*num = le32_to_cpu(out->num);248249if (*num >= max_num ||250*num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {251ph->xops->xfer_put(ph, t);252return -EINVAL;253}254255for (i = 0; i < *num; i++)256val[i] = le32_to_cpu(out->val[i]);257}258259ph->xops->xfer_put(ph, t);260261return ret;262}263264static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,265u32 ctrl_id, u32 num, u32 *val)266{267struct scmi_imx_misc_ctrl_set_in *in;268struct scmi_xfer *t;269int ret, i;270int max_msg_size = ph->hops->get_max_msg_size(ph);271int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);272273ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);274if (ret)275return ret;276277if (num > max_num)278return -EINVAL;279280ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET,281sizeof(*in) + num * sizeof(__le32), 0, &t);282if (ret)283return ret;284285in = t->tx.buf;286in->id = cpu_to_le32(ctrl_id);287in->num = cpu_to_le32(num);288for (i = 0; i < num; i++)289in->value[i] = cpu_to_le32(val[i]);290291ret = ph->xops->do_xfer(ph, t);292293ph->xops->xfer_put(ph, t);294295return ret;296}297298static int scmi_imx_misc_build_info_discover(const struct scmi_protocol_handle *ph)299{300char date[MISC_MAX_BUILDDATE], time[MISC_MAX_BUILDTIME];301struct scmi_imx_misc_buildinfo_out *out;302struct scmi_xfer *t;303int ret;304305ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_DISCOVER_BUILD_INFO, 0,306sizeof(*out), &t);307if (ret)308return ret;309310ret = ph->xops->do_xfer(ph, t);311if (!ret) {312out = t->rx.buf;313strscpy(date, out->builddate, MISC_MAX_BUILDDATE);314strscpy(time, out->buildtime, MISC_MAX_BUILDTIME);315dev_info(ph->dev, "SM Version\t= Build %u, Commit %08x %s %s\n",316le32_to_cpu(out->buildnum), le32_to_cpu(out->buildcommit),317date, time);318}319320ph->xops->xfer_put(ph, t);321322return ret;323}324325static int scmi_imx_misc_board_info(const struct scmi_protocol_handle *ph)326{327struct scmi_imx_misc_board_info_out *out;328char name[MISC_MAX_BRDNAME];329struct scmi_xfer *t;330int ret;331332ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_BOARD_INFO, 0, sizeof(*out), &t);333if (ret)334return ret;335336ret = ph->xops->do_xfer(ph, t);337if (!ret) {338out = t->rx.buf;339strscpy(name, out->brdname, MISC_MAX_BRDNAME);340dev_info(ph->dev, "Board\t\t= %s, attr=0x%08x\n",341name, le32_to_cpu(out->attributes));342}343344ph->xops->xfer_put(ph, t);345346return ret;347}348349static int scmi_imx_misc_cfg_info_get(const struct scmi_protocol_handle *ph)350{351struct scmi_imx_misc_cfg_info_out *out;352char name[MISC_MAX_CFGNAME];353struct scmi_xfer *t;354int ret;355356ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CFG_INFO_GET, 0, sizeof(*out), &t);357if (ret)358return ret;359360ret = ph->xops->do_xfer(ph, t);361if (!ret) {362out = t->rx.buf;363strscpy(name, out->cfgname, MISC_MAX_CFGNAME);364dev_info(ph->dev, "SM Config\t= %s, mSel = %u\n",365name, le32_to_cpu(out->msel));366}367368ph->xops->xfer_put(ph, t);369370return ret;371}372373static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {374.misc_ctrl_set = scmi_imx_misc_ctrl_set,375.misc_ctrl_get = scmi_imx_misc_ctrl_get,376.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,377};378379static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)380{381struct scmi_imx_misc_info *minfo;382u32 version;383int ret;384385ret = ph->xops->version_get(ph, &version);386if (ret)387return ret;388389dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",390PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));391392minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);393if (!minfo)394return -ENOMEM;395396ret = scmi_imx_misc_attributes_get(ph, minfo);397if (ret)398return ret;399400ret = scmi_imx_misc_build_info_discover(ph);401if (ret && ret != -EOPNOTSUPP)402return ret;403404ret = scmi_imx_misc_board_info(ph);405if (ret && ret != -EOPNOTSUPP)406return ret;407408ret = scmi_imx_misc_cfg_info_get(ph);409if (ret && ret != -EOPNOTSUPP)410return ret;411412return ph->set_priv(ph, minfo, version);413}414415static const struct scmi_protocol scmi_imx_misc = {416.id = SCMI_PROTOCOL_IMX_MISC,417.owner = THIS_MODULE,418.instance_init = &scmi_imx_misc_protocol_init,419.ops = &scmi_imx_misc_proto_ops,420.events = &scmi_imx_misc_protocol_events,421.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,422.vendor_id = SCMI_IMX_VENDOR,423.sub_vendor_id = SCMI_IMX_SUBVENDOR,424};425module_scmi_protocol(scmi_imx_misc);426427MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_MISC) "-" SCMI_IMX_VENDOR);428MODULE_DESCRIPTION("i.MX SCMI MISC driver");429MODULE_LICENSE("GPL");430431432