Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
26498 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_CTRL_NOTIFY = 0x8,28};2930struct scmi_imx_misc_info {31u32 version;32u32 nr_dev_ctrl;33u32 nr_brd_ctrl;34u32 nr_reason;35};3637struct scmi_msg_imx_misc_protocol_attributes {38__le32 attributes;39};4041#define GET_BRD_CTRLS_NR(x) le32_get_bits((x), GENMASK(31, 24))42#define GET_REASONS_NR(x) le32_get_bits((x), GENMASK(23, 16))43#define GET_DEV_CTRLS_NR(x) le32_get_bits((x), GENMASK(15, 0))44#define BRD_CTRL_START_ID BIT(15)4546struct scmi_imx_misc_ctrl_set_in {47__le32 id;48__le32 num;49__le32 value[];50};5152struct scmi_imx_misc_ctrl_notify_in {53__le32 ctrl_id;54__le32 flags;55};5657struct scmi_imx_misc_ctrl_notify_payld {58__le32 ctrl_id;59__le32 flags;60};6162struct scmi_imx_misc_ctrl_get_out {63__le32 num;64__le32 val[];65};6667static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,68struct scmi_imx_misc_info *mi)69{70int ret;71struct scmi_xfer *t;72struct scmi_msg_imx_misc_protocol_attributes *attr;7374ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,75sizeof(*attr), &t);76if (ret)77return ret;7879attr = t->rx.buf;8081ret = ph->xops->do_xfer(ph, t);82if (!ret) {83mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);84mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);85mi->nr_reason = GET_REASONS_NR(attr->attributes);86dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",87mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);88}8990ph->xops->xfer_put(ph, t);9192return ret;93}9495static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,96u32 ctrl_id)97{98struct scmi_imx_misc_info *mi = ph->get_priv(ph);99100/*101* [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related102* [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related103*/104if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)105return -EINVAL;106if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)107return -EINVAL;108109return 0;110}111112static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,113u32 ctrl_id, u32 evt_id, u32 flags)114{115struct scmi_imx_misc_ctrl_notify_in *in;116struct scmi_xfer *t;117int ret;118119ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);120if (ret)121return ret;122123ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,124sizeof(*in), 0, &t);125if (ret)126return ret;127128in = t->tx.buf;129in->ctrl_id = cpu_to_le32(ctrl_id);130in->flags = cpu_to_le32(flags);131132ret = ph->xops->do_xfer(ph, t);133134ph->xops->xfer_put(ph, t);135136return ret;137}138139static int140scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,141u8 evt_id, u32 src_id, bool enable)142{143int ret;144145/* misc_ctrl_req_notify is for enablement */146if (enable)147return 0;148149ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);150if (ret)151dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",152evt_id, src_id, ret);153154return ret;155}156157static void *158scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,159u8 evt_id, ktime_t timestamp,160const void *payld, size_t payld_sz,161void *report, u32 *src_id)162{163const struct scmi_imx_misc_ctrl_notify_payld *p = payld;164struct scmi_imx_misc_ctrl_notify_report *r = report;165166if (sizeof(*p) != payld_sz)167return NULL;168169r->timestamp = timestamp;170r->ctrl_id = le32_to_cpu(p->ctrl_id);171r->flags = le32_to_cpu(p->flags);172if (src_id)173*src_id = r->ctrl_id;174dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,175r->ctrl_id, r->flags);176177return r;178}179180static const struct scmi_event_ops scmi_imx_misc_event_ops = {181.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,182.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,183};184185static const struct scmi_event scmi_imx_misc_events[] = {186{187.id = SCMI_EVENT_IMX_MISC_CONTROL,188.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),189.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),190},191};192193static struct scmi_protocol_events scmi_imx_misc_protocol_events = {194.queue_sz = SCMI_PROTO_QUEUE_SZ,195.ops = &scmi_imx_misc_event_ops,196.evts = scmi_imx_misc_events,197.num_events = ARRAY_SIZE(scmi_imx_misc_events),198.num_sources = MAX_MISC_CTRL_SOURCES,199};200201static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,202u32 ctrl_id, u32 *num, u32 *val)203{204struct scmi_imx_misc_ctrl_get_out *out;205struct scmi_xfer *t;206int ret, i;207int max_msg_size = ph->hops->get_max_msg_size(ph);208int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);209210ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);211if (ret)212return ret;213214ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),2150, &t);216if (ret)217return ret;218219put_unaligned_le32(ctrl_id, t->tx.buf);220ret = ph->xops->do_xfer(ph, t);221if (!ret) {222out = t->rx.buf;223*num = le32_to_cpu(out->num);224225if (*num >= max_num ||226*num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {227ph->xops->xfer_put(ph, t);228return -EINVAL;229}230231for (i = 0; i < *num; i++)232val[i] = le32_to_cpu(out->val[i]);233}234235ph->xops->xfer_put(ph, t);236237return ret;238}239240static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,241u32 ctrl_id, u32 num, u32 *val)242{243struct scmi_imx_misc_ctrl_set_in *in;244struct scmi_xfer *t;245int ret, i;246int max_msg_size = ph->hops->get_max_msg_size(ph);247int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);248249ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);250if (ret)251return ret;252253if (num > max_num)254return -EINVAL;255256ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET,257sizeof(*in) + num * sizeof(__le32), 0, &t);258if (ret)259return ret;260261in = t->tx.buf;262in->id = cpu_to_le32(ctrl_id);263in->num = cpu_to_le32(num);264for (i = 0; i < num; i++)265in->value[i] = cpu_to_le32(val[i]);266267ret = ph->xops->do_xfer(ph, t);268269ph->xops->xfer_put(ph, t);270271return ret;272}273274static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {275.misc_ctrl_set = scmi_imx_misc_ctrl_set,276.misc_ctrl_get = scmi_imx_misc_ctrl_get,277.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,278};279280static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)281{282struct scmi_imx_misc_info *minfo;283u32 version;284int ret;285286ret = ph->xops->version_get(ph, &version);287if (ret)288return ret;289290dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",291PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));292293minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);294if (!minfo)295return -ENOMEM;296297ret = scmi_imx_misc_attributes_get(ph, minfo);298if (ret)299return ret;300301return ph->set_priv(ph, minfo, version);302}303304static const struct scmi_protocol scmi_imx_misc = {305.id = SCMI_PROTOCOL_IMX_MISC,306.owner = THIS_MODULE,307.instance_init = &scmi_imx_misc_protocol_init,308.ops = &scmi_imx_misc_proto_ops,309.events = &scmi_imx_misc_protocol_events,310.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,311.vendor_id = SCMI_IMX_VENDOR,312.sub_vendor_id = SCMI_IMX_SUBVENDOR,313};314module_scmi_protocol(scmi_imx_misc);315316MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_MISC) "-" SCMI_IMX_VENDOR);317MODULE_DESCRIPTION("i.MX SCMI MISC driver");318MODULE_LICENSE("GPL");319320321