brintos

brintos / linux-shallow public Read only

0
0
Text · 7.5 KiB · a86ab9b Raw
319 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System control and Management Interface (SCMI) NXP MISC Protocol4 *5 * Copyright 2024 NXP6 */7 8#define pr_fmt(fmt) "SCMI Notifications MISC - " fmt9 10#include <linux/bits.h>11#include <linux/io.h>12#include <linux/module.h>13#include <linux/of.h>14#include <linux/platform_device.h>15#include <linux/scmi_protocol.h>16#include <linux/scmi_imx_protocol.h>17 18#include "../../protocols.h"19#include "../../notify.h"20 21#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x1000022 23#define MAX_MISC_CTRL_SOURCES			GENMASK(15, 0)24 25enum scmi_imx_misc_protocol_cmd {26	SCMI_IMX_MISC_CTRL_SET	= 0x3,27	SCMI_IMX_MISC_CTRL_GET	= 0x4,28	SCMI_IMX_MISC_CTRL_NOTIFY = 0x8,29};30 31struct scmi_imx_misc_info {32	u32 version;33	u32 nr_dev_ctrl;34	u32 nr_brd_ctrl;35	u32 nr_reason;36};37 38struct scmi_msg_imx_misc_protocol_attributes {39	__le32 attributes;40};41 42#define GET_BRD_CTRLS_NR(x)	le32_get_bits((x), GENMASK(31, 24))43#define GET_REASONS_NR(x)	le32_get_bits((x), GENMASK(23, 16))44#define GET_DEV_CTRLS_NR(x)	le32_get_bits((x), GENMASK(15, 0))45#define BRD_CTRL_START_ID	BIT(15)46 47struct scmi_imx_misc_ctrl_set_in {48	__le32 id;49	__le32 num;50	__le32 value[];51};52 53struct scmi_imx_misc_ctrl_notify_in {54	__le32 ctrl_id;55	__le32 flags;56};57 58struct scmi_imx_misc_ctrl_notify_payld {59	__le32 ctrl_id;60	__le32 flags;61};62 63struct scmi_imx_misc_ctrl_get_out {64	__le32 num;65	__le32 val[];66};67 68static int scmi_imx_misc_attributes_get(const struct scmi_protocol_handle *ph,69					struct scmi_imx_misc_info *mi)70{71	int ret;72	struct scmi_xfer *t;73	struct scmi_msg_imx_misc_protocol_attributes *attr;74 75	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,76				      sizeof(*attr), &t);77	if (ret)78		return ret;79 80	attr = t->rx.buf;81 82	ret = ph->xops->do_xfer(ph, t);83	if (!ret) {84		mi->nr_dev_ctrl = GET_DEV_CTRLS_NR(attr->attributes);85		mi->nr_brd_ctrl = GET_BRD_CTRLS_NR(attr->attributes);86		mi->nr_reason = GET_REASONS_NR(attr->attributes);87		dev_info(ph->dev, "i.MX MISC NUM DEV CTRL: %d, NUM BRD CTRL: %d,NUM Reason: %d\n",88			 mi->nr_dev_ctrl, mi->nr_brd_ctrl, mi->nr_reason);89	}90 91	ph->xops->xfer_put(ph, t);92 93	return ret;94}95 96static int scmi_imx_misc_ctrl_validate_id(const struct scmi_protocol_handle *ph,97					  u32 ctrl_id)98{99	struct scmi_imx_misc_info *mi = ph->get_priv(ph);100 101	/*102	 * [0,      BRD_CTRL_START_ID) is for Dev Ctrl which is SOC related103	 * [BRD_CTRL_START_ID, 0xffff) is for Board Ctrl which is board related104	 */105	if (ctrl_id < BRD_CTRL_START_ID && ctrl_id > mi->nr_dev_ctrl)106		return -EINVAL;107	if (ctrl_id >= BRD_CTRL_START_ID + mi->nr_brd_ctrl)108		return -EINVAL;109 110	return 0;111}112 113static int scmi_imx_misc_ctrl_notify(const struct scmi_protocol_handle *ph,114				     u32 ctrl_id, u32 evt_id, u32 flags)115{116	struct scmi_imx_misc_ctrl_notify_in *in;117	struct scmi_xfer *t;118	int ret;119 120	ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);121	if (ret)122		return ret;123 124	ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_NOTIFY,125				      sizeof(*in), 0, &t);126	if (ret)127		return ret;128 129	in = t->tx.buf;130	in->ctrl_id = cpu_to_le32(ctrl_id);131	in->flags = cpu_to_le32(flags);132 133	ret = ph->xops->do_xfer(ph, t);134 135	ph->xops->xfer_put(ph, t);136 137	return ret;138}139 140static int141scmi_imx_misc_ctrl_set_notify_enabled(const struct scmi_protocol_handle *ph,142				      u8 evt_id, u32 src_id, bool enable)143{144	int ret;145 146	/* misc_ctrl_req_notify is for enablement */147	if (enable)148		return 0;149 150	ret = scmi_imx_misc_ctrl_notify(ph, src_id, evt_id, 0);151	if (ret)152		dev_err(ph->dev, "FAIL_ENABLED - evt[%X] src[%d] - ret:%d\n",153			evt_id, src_id, ret);154 155	return ret;156}157 158static void *159scmi_imx_misc_ctrl_fill_custom_report(const struct scmi_protocol_handle *ph,160				      u8 evt_id, ktime_t timestamp,161				      const void *payld, size_t payld_sz,162				      void *report, u32 *src_id)163{164	const struct scmi_imx_misc_ctrl_notify_payld *p = payld;165	struct scmi_imx_misc_ctrl_notify_report *r = report;166 167	if (sizeof(*p) != payld_sz)168		return NULL;169 170	r->timestamp = timestamp;171	r->ctrl_id = le32_to_cpu(p->ctrl_id);172	r->flags = le32_to_cpu(p->flags);173	if (src_id)174		*src_id = r->ctrl_id;175	dev_dbg(ph->dev, "%s: ctrl_id: %d flags: %d\n", __func__,176		r->ctrl_id, r->flags);177 178	return r;179}180 181static const struct scmi_event_ops scmi_imx_misc_event_ops = {182	.set_notify_enabled = scmi_imx_misc_ctrl_set_notify_enabled,183	.fill_custom_report = scmi_imx_misc_ctrl_fill_custom_report,184};185 186static const struct scmi_event scmi_imx_misc_events[] = {187	{188		.id = SCMI_EVENT_IMX_MISC_CONTROL,189		.max_payld_sz = sizeof(struct scmi_imx_misc_ctrl_notify_payld),190		.max_report_sz = sizeof(struct scmi_imx_misc_ctrl_notify_report),191	},192};193 194static struct scmi_protocol_events scmi_imx_misc_protocol_events = {195	.queue_sz = SCMI_PROTO_QUEUE_SZ,196	.ops = &scmi_imx_misc_event_ops,197	.evts = scmi_imx_misc_events,198	.num_events = ARRAY_SIZE(scmi_imx_misc_events),199	.num_sources = MAX_MISC_CTRL_SOURCES,200};201 202static int scmi_imx_misc_ctrl_get(const struct scmi_protocol_handle *ph,203				  u32 ctrl_id, u32 *num, u32 *val)204{205	struct scmi_imx_misc_ctrl_get_out *out;206	struct scmi_xfer *t;207	int ret, i;208	int max_msg_size = ph->hops->get_max_msg_size(ph);209	int max_num = (max_msg_size - sizeof(*out)) / sizeof(__le32);210 211	ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);212	if (ret)213		return ret;214 215	ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_GET, sizeof(u32),216				      0, &t);217	if (ret)218		return ret;219 220	put_unaligned_le32(ctrl_id, t->tx.buf);221	ret = ph->xops->do_xfer(ph, t);222	if (!ret) {223		out = t->rx.buf;224		*num = le32_to_cpu(out->num);225 226		if (*num >= max_num ||227		    *num * sizeof(__le32) > t->rx.len - sizeof(__le32)) {228			ph->xops->xfer_put(ph, t);229			return -EINVAL;230		}231 232		for (i = 0; i < *num; i++)233			val[i] = le32_to_cpu(out->val[i]);234	}235 236	ph->xops->xfer_put(ph, t);237 238	return ret;239}240 241static int scmi_imx_misc_ctrl_set(const struct scmi_protocol_handle *ph,242				  u32 ctrl_id, u32 num, u32 *val)243{244	struct scmi_imx_misc_ctrl_set_in *in;245	struct scmi_xfer *t;246	int ret, i;247	int max_msg_size = ph->hops->get_max_msg_size(ph);248	int max_num = (max_msg_size - sizeof(*in)) / sizeof(__le32);249 250	ret = scmi_imx_misc_ctrl_validate_id(ph, ctrl_id);251	if (ret)252		return ret;253 254	if (num > max_num)255		return -EINVAL;256 257	ret = ph->xops->xfer_get_init(ph, SCMI_IMX_MISC_CTRL_SET, sizeof(*in),258				      0, &t);259	if (ret)260		return ret;261 262	in = t->tx.buf;263	in->id = cpu_to_le32(ctrl_id);264	in->num = cpu_to_le32(num);265	for (i = 0; i < num; i++)266		in->value[i] = cpu_to_le32(val[i]);267 268	ret = ph->xops->do_xfer(ph, t);269 270	ph->xops->xfer_put(ph, t);271 272	return ret;273}274 275static const struct scmi_imx_misc_proto_ops scmi_imx_misc_proto_ops = {276	.misc_ctrl_set = scmi_imx_misc_ctrl_set,277	.misc_ctrl_get = scmi_imx_misc_ctrl_get,278	.misc_ctrl_req_notify = scmi_imx_misc_ctrl_notify,279};280 281static int scmi_imx_misc_protocol_init(const struct scmi_protocol_handle *ph)282{283	struct scmi_imx_misc_info *minfo;284	u32 version;285	int ret;286 287	ret = ph->xops->version_get(ph, &version);288	if (ret)289		return ret;290 291	dev_info(ph->dev, "NXP SM MISC Version %d.%d\n",292		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));293 294	minfo = devm_kzalloc(ph->dev, sizeof(*minfo), GFP_KERNEL);295	if (!minfo)296		return -ENOMEM;297 298	ret = scmi_imx_misc_attributes_get(ph, minfo);299	if (ret)300		return ret;301 302	return ph->set_priv(ph, minfo, version);303}304 305static const struct scmi_protocol scmi_imx_misc = {306	.id = SCMI_PROTOCOL_IMX_MISC,307	.owner = THIS_MODULE,308	.instance_init = &scmi_imx_misc_protocol_init,309	.ops = &scmi_imx_misc_proto_ops,310	.events = &scmi_imx_misc_protocol_events,311	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,312	.vendor_id = "NXP",313	.sub_vendor_id = "IMX",314};315module_scmi_protocol(scmi_imx_misc);316 317MODULE_DESCRIPTION("i.MX SCMI MISC driver");318MODULE_LICENSE("GPL");319