Path: blob/master/drivers/firmware/arm_scmi/vendors/imx/imx-sm-misc.c
54308 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_SYSLOG_GET = 0xD,31SCMI_IMX_MISC_BOARD_INFO = 0xE,32};3334struct scmi_imx_misc_info {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};9091struct scmi_imx_misc_syslog_in {92__le32 flags;93__le32 index;94};9596#define REMAINING(x) le32_get_bits((x), GENMASK(31, 20))97#define RETURNED(x) le32_get_bits((x), GENMASK(11, 0))9899struct scmi_imx_misc_syslog_out {100__le32 numlogflags;101__le32 syslog[];102};103104static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,105struct scmi_imx_misc_info *mi)106{107int ret;108struct scmi_xfer *t;109struct scmi_msg_imx_misc_protocol_attributes *attr;110111ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,112sizeof(*attr), &t);113if (ret)114return ret;115116attr = t->rx.buf;117118ret = ph->xops->do_xfer(ph, t);119if (!ret) {120mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);121mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);122mi->nr_reason = GET_REASONS_NR(attr->attributes);123dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",124mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);125}126127ph->xops->xfer_put(ph, t);128129return ret;130}131132static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,133u32 ctrl_id)134{135struct scmi_imx_misc_info *mi = ph->get_priv(ph);136137/*138* [0, BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related139* [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related140*/141if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)142return -EINVAL;143if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)144return -EINVAL;145146return 0;147}148149static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,150u32 ctrl_id, u32 evt_id, u32 flags)151{152struct scmi_imx_misc_ctrl_notify_in *in;153struct scmi_xfer *t;154int ret;155156ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);157if (ret)158return ret;159160ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,161sizeof(*in), 0, &t);162if (ret)163return ret;164165in = t->tx.buf;166in->ctrl_id = cpu_to_le32(ctrl_id);167in->flags = cpu_to_le32(flags);168169ret = ph->xops->do_xfer(ph, t);170171ph->xops->xfer_put(ph, t);172173return ret;174}175176static int177scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,178u8 evt_id, u32 src_id, bool enable)179{180int ret;181182/* misc_ctrl_req_notify is for enablement */183if (enable)184return 0;185186ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);187if (ret)188dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",189evt_id, src_id, ret);190191return ret;192}193194static void *195scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,196u8 evt_id, ktime_t timestamp,197const void *payld, size_t payld_sz,198void *report, u32 *src_id)199{200const struct scmi_imx_misc_ctrl_notify_payld *p = payld;201struct scmi_imx_misc_ctrl_notify_report *r = report;202203if (sizeof(*p) != payld_sz)204return NULL;205206r->timestamp = timestamp;207r->ctrl_id = le32_to_cpu(p->ctrl_id);208r->flags = le32_to_cpu(p->flags);209if (src_id)210*src_id = r->ctrl_id;211dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,212r->ctrl_id, r->flags);213214return r;215}216217static const struct scmi_event_ops scmi_imx_misc_event_ops = {218.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,219.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,220};221222static const struct scmi_event scmi_imx_misc_events[] = {223{224.id = SCMI_EVENT_IMX_MISC_CONTROL,225.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),226.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),227},228};229230static struct scmi_protocol_events scmi_imx_misc_protocol_events = {231.queue_sz = SCMI_PROTO_QUEUE_SZ,232.ops = &scmi_imx_misc_event_ops,233.evts = scmi_imx_misc_events,234.num_events = ARRAY_SIZE(scmi_imx_misc_events),235.num_sources = MAX_MISC_CTRL_SOURCES,236};237238static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,239u32 ctrl_id, u32 *num, u32 *val)240{241struct scmi_imx_misc_ctrl_get_out *out;242struct scmi_xfer *t;243int ret, i;244int max_msg_size = ph->hops->get_max_msg_size(ph);245int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);246247ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);248if (ret)249return ret;250251ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),2520, &t);253if (ret)254return ret;255256put_unaligned_le32(ctrl_id, t->tx.buf);257ret = ph->xops->do_xfer(ph, t);258if (!ret) {259out = t->rx.buf;260*num = le32_to_cpu(out->num);261262if (*num >= max_num ||263*num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {264ph->xops->xfer_put(ph, t);265return -EINVAL;266}267268for (i = 0; i < *num; i++)269val[i] = le32_to_cpu(out->val[i]);270}271272ph->xops->xfer_put(ph, t);273274return ret;275}276277static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,278u32 ctrl_id, u32 num, u32 *val)279{280struct scmi_imx_misc_ctrl_set_in *in;281struct scmi_xfer *t;282int ret, i;283int max_msg_size = ph->hops->get_max_msg_size(ph);284int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);285286ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);287if (ret)288return ret;289290if (num > max_num)291return -EINVAL;292293ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET,294sizeof(*in) + num * sizeof(__le32), 0, &t);295if (ret)296return ret;297298in = t->tx.buf;299in->id = cpu_to_le32(ctrl_id);300in->num = cpu_to_le32(num);301for (i = 0; i < num; i++)302in->value[i] = cpu_to_le32(val[i]);303304ret = ph->xops->do_xfer(ph, t);305306ph->xops->xfer_put(ph, t);307308return ret;309}310311static int scmi_imx_misc_build_info_discover(const struct scmi_protocol_handle *ph)312{313char date[MISC_MAX_BUILDDATE], time[MISC_MAX_BUILDTIME];314struct scmi_imx_misc_buildinfo_out *out;315struct scmi_xfer *t;316int ret;317318ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_DISCOVER_BUILD_INFO, 0,319sizeof(*out), &t);320if (ret)321return ret;322323ret = ph->xops->do_xfer(ph, t);324if (!ret) {325out = t->rx.buf;326strscpy(date, out->builddate, MISC_MAX_BUILDDATE);327strscpy(time, out->buildtime, MISC_MAX_BUILDTIME);328dev_info(ph->dev, "SM Version\t= Build %u, Commit %08x %s %s\n",329le32_to_cpu(out->buildnum), le32_to_cpu(out->buildcommit),330date, time);331}332333ph->xops->xfer_put(ph, t);334335return ret;336}337338static int scmi_imx_misc_board_info(const struct scmi_protocol_handle *ph)339{340struct scmi_imx_misc_board_info_out *out;341char name[MISC_MAX_BRDNAME];342struct scmi_xfer *t;343int ret;344345ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_BOARD_INFO, 0, sizeof(*out), &t);346if (ret)347return ret;348349ret = ph->xops->do_xfer(ph, t);350if (!ret) {351out = t->rx.buf;352strscpy(name, out->brdname, MISC_MAX_BRDNAME);353dev_info(ph->dev, "Board\t\t= %s, attr=0x%08x\n",354name, le32_to_cpu(out->attributes));355}356357ph->xops->xfer_put(ph, t);358359return ret;360}361362static int scmi_imx_misc_cfg_info_get(const struct scmi_protocol_handle *ph)363{364struct scmi_imx_misc_cfg_info_out *out;365char name[MISC_MAX_CFGNAME];366struct scmi_xfer *t;367int ret;368369ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CFG_INFO_GET, 0, sizeof(*out), &t);370if (ret)371return ret;372373ret = ph->xops->do_xfer(ph, t);374if (!ret) {375out = t->rx.buf;376strscpy(name, out->cfgname, MISC_MAX_CFGNAME);377dev_info(ph->dev, "SM Config\t= %s, mSel = %u\n",378name, le32_to_cpu(out->msel));379}380381ph->xops->xfer_put(ph, t);382383return ret;384}385386struct scmi_imx_misc_syslog_ipriv {387u32 *array;388u16 *size;389};390391static void iter_misc_syslog_prepare_message(void *message, u32 desc_index,392const void *priv)393{394struct scmi_imx_misc_syslog_in *msg = message;395396msg->flags = cpu_to_le32(0);397msg->index = cpu_to_le32(desc_index);398}399400static int iter_misc_syslog_update_state(struct scmi_iterator_state *st,401const void *response, void *priv)402{403const struct scmi_imx_misc_syslog_out *r = response;404struct scmi_imx_misc_syslog_ipriv *p = priv;405406st->num_returned = RETURNED(r->numlogflags);407st->num_remaining = REMAINING(r->numlogflags);408*p->size = st->num_returned + st->num_remaining;409410return 0;411}412413static int414iter_misc_syslog_process_response(const struct scmi_protocol_handle *ph,415const void *response,416struct scmi_iterator_state *st, void *priv)417{418const struct scmi_imx_misc_syslog_out *r = response;419struct scmi_imx_misc_syslog_ipriv *p = priv;420421p->array[st->desc_index + st->loop_idx] =422le32_to_cpu(r->syslog[st->loop_idx]);423424return 0;425}426427static int scmi_imx_misc_syslog_get(const struct scmi_protocol_handle *ph, u16 *size,428void *array)429{430struct scmi_iterator_ops ops = {431.prepare_message = iter_misc_syslog_prepare_message,432.update_state = iter_misc_syslog_update_state,433.process_response = iter_misc_syslog_process_response,434};435struct scmi_imx_misc_syslog_ipriv ipriv = {436.array = array,437.size = size,438};439void *iter;440441if (!array || !size || !*size)442return -EINVAL;443444iter = ph->hops->iter_response_init(ph, &ops, *size, SCMI_IMX_MISC_SYSLOG_GET,445sizeof(struct scmi_imx_misc_syslog_in),446&ipriv);447if (IS_ERR(iter))448return PTR_ERR(iter);449450/* If firmware return NOT SUPPORTED, propagate value to caller */451return ph->hops->iter_response_run(iter);452}453454static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {455.misc_ctrl_set = scmi_imx_misc_ctrl_set,456.misc_ctrl_get = scmi_imx_misc_ctrl_get,457.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,458.misc_syslog = scmi_imx_misc_syslog_get,459};460461static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)462{463struct scmi_imx_misc_info *minfo;464int ret;465466dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",467PROTOCOL_REV_MAJOR(ph->version), PROTOCOL_REV_MINOR(ph->version));468469minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);470if (!minfo)471return -ENOMEM;472473ret = scmi_imx_misc_attributes_get(ph, minfo);474if (ret)475return ret;476477ret = scmi_imx_misc_build_info_discover(ph);478if (ret && ret != -EOPNOTSUPP)479return ret;480481ret = scmi_imx_misc_board_info(ph);482if (ret && ret != -EOPNOTSUPP)483return ret;484485ret = scmi_imx_misc_cfg_info_get(ph);486if (ret && ret != -EOPNOTSUPP)487return ret;488489return ph->set_priv(ph, minfo);490}491492static const struct scmi_protocol scmi_imx_misc = {493.id = SCMI_PROTOCOL_IMX_MISC,494.owner = THIS_MODULE,495.instance_init = &scmi_imx_misc_protocol_init,496.ops = &scmi_imx_misc_proto_ops,497.events = &scmi_imx_misc_protocol_events,498.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,499.vendor_id = SCMI_IMX_VENDOR,500.sub_vendor_id = SCMI_IMX_SUBVENDOR,501};502module_scmi_protocol(scmi_imx_misc);503504MODULE_ALIAS("scmi-protocol-" __stringify(SCMI_PROTOCOL_IMX_MISC) "-" SCMI_IMX_VENDOR);505MODULE_DESCRIPTION("i.MX SCMI MISC driver");506MODULE_LICENSE("GPL");507508509