brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · 17799ea Raw
384 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System Control and Management Interface (SCMI) NXP BBM Protocol4 *5 * Copyright 2024 NXP6 */7 8#define pr_fmt(fmt) "SCMI Notifications BBM - " 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 23enum scmi_imx_bbm_protocol_cmd {24	IMX_BBM_GPR_SET = 0x3,25	IMX_BBM_GPR_GET = 0x4,26	IMX_BBM_RTC_ATTRIBUTES = 0x5,27	IMX_BBM_RTC_TIME_SET = 0x6,28	IMX_BBM_RTC_TIME_GET = 0x7,29	IMX_BBM_RTC_ALARM_SET = 0x8,30	IMX_BBM_BUTTON_GET = 0x9,31	IMX_BBM_RTC_NOTIFY = 0xA,32	IMX_BBM_BUTTON_NOTIFY = 0xB,33};34 35#define GET_RTCS_NR(x)	le32_get_bits((x), GENMASK(23, 16))36#define GET_GPRS_NR(x)	le32_get_bits((x), GENMASK(15, 0))37 38#define SCMI_IMX_BBM_NOTIFY_RTC_UPDATED		BIT(2)39#define SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER	BIT(1)40#define SCMI_IMX_BBM_NOTIFY_RTC_ALARM		BIT(0)41 42#define SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG	BIT(0)43 44#define SCMI_IMX_BBM_NOTIFY_RTC_FLAG	\45	(SCMI_IMX_BBM_NOTIFY_RTC_UPDATED | SCMI_IMX_BBM_NOTIFY_RTC_ROLLOVER | \46	 SCMI_IMX_BBM_NOTIFY_RTC_ALARM)47 48#define SCMI_IMX_BBM_EVENT_RTC_MASK		GENMASK(31, 24)49 50struct scmi_imx_bbm_info {51	u32 version;52	int nr_rtc;53	int nr_gpr;54};55 56struct scmi_msg_imx_bbm_protocol_attributes {57	__le32 attributes;58};59 60struct scmi_imx_bbm_set_time {61	__le32 id;62	__le32 flags;63	__le32 value_low;64	__le32 value_high;65};66 67struct scmi_imx_bbm_get_time {68	__le32 id;69	__le32 flags;70};71 72struct scmi_imx_bbm_alarm_time {73	__le32 id;74	__le32 flags;75	__le32 value_low;76	__le32 value_high;77};78 79struct scmi_msg_imx_bbm_rtc_notify {80	__le32 rtc_id;81	__le32 flags;82};83 84struct scmi_msg_imx_bbm_button_notify {85	__le32 flags;86};87 88struct scmi_imx_bbm_notify_payld {89	__le32 flags;90};91 92static int scmi_imx_bbm_attributes_get(const struct scmi_protocol_handle *ph,93				       struct scmi_imx_bbm_info *pi)94{95	int ret;96	struct scmi_xfer *t;97	struct scmi_msg_imx_bbm_protocol_attributes *attr;98 99	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0, sizeof(*attr), &t);100	if (ret)101		return ret;102 103	attr = t->rx.buf;104 105	ret = ph->xops->do_xfer(ph, t);106	if (!ret) {107		pi->nr_rtc = GET_RTCS_NR(attr->attributes);108		pi->nr_gpr = GET_GPRS_NR(attr->attributes);109	}110 111	ph->xops->xfer_put(ph, t);112 113	return ret;114}115 116static int scmi_imx_bbm_notify(const struct scmi_protocol_handle *ph,117			       u32 src_id, int message_id, bool enable)118{119	int ret;120	struct scmi_xfer *t;121 122	if (message_id == IMX_BBM_RTC_NOTIFY) {123		struct scmi_msg_imx_bbm_rtc_notify *rtc_notify;124 125		ret = ph->xops->xfer_get_init(ph, message_id,126					      sizeof(*rtc_notify), 0, &t);127		if (ret)128			return ret;129 130		rtc_notify = t->tx.buf;131		rtc_notify->rtc_id = cpu_to_le32(0);132		rtc_notify->flags =133			cpu_to_le32(enable ? SCMI_IMX_BBM_NOTIFY_RTC_FLAG : 0);134	} else if (message_id == IMX_BBM_BUTTON_NOTIFY) {135		struct scmi_msg_imx_bbm_button_notify *button_notify;136 137		ret = ph->xops->xfer_get_init(ph, message_id,138					      sizeof(*button_notify), 0, &t);139		if (ret)140			return ret;141 142		button_notify = t->tx.buf;143		button_notify->flags = cpu_to_le32(enable ? 1 : 0);144	} else {145		return -EINVAL;146	}147 148	ret = ph->xops->do_xfer(ph, t);149 150	ph->xops->xfer_put(ph, t);151	return ret;152}153 154static enum scmi_imx_bbm_protocol_cmd evt_2_cmd[] = {155	IMX_BBM_RTC_NOTIFY,156	IMX_BBM_BUTTON_NOTIFY157};158 159static int scmi_imx_bbm_set_notify_enabled(const struct scmi_protocol_handle *ph,160					   u8 evt_id, u32 src_id, bool enable)161{162	int ret, cmd_id;163 164	if (evt_id >= ARRAY_SIZE(evt_2_cmd))165		return -EINVAL;166 167	cmd_id = evt_2_cmd[evt_id];168	ret = scmi_imx_bbm_notify(ph, src_id, cmd_id, enable);169	if (ret)170		pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",171			 evt_id, src_id, ret);172 173	return ret;174}175 176static void *scmi_imx_bbm_fill_custom_report(const struct scmi_protocol_handle *ph,177					     u8 evt_id, ktime_t timestamp,178					     const void *payld, size_t payld_sz,179					     void *report, u32 *src_id)180{181	const struct scmi_imx_bbm_notify_payld *p = payld;182	struct scmi_imx_bbm_notif_report *r = report;183 184	if (sizeof(*p) != payld_sz)185		return NULL;186 187	if (evt_id == SCMI_EVENT_IMX_BBM_RTC) {188		r->is_rtc = true;189		r->is_button = false;190		r->timestamp = timestamp;191		r->rtc_id = le32_get_bits(p->flags, SCMI_IMX_BBM_EVENT_RTC_MASK);192		r->rtc_evt = le32_get_bits(p->flags, SCMI_IMX_BBM_NOTIFY_RTC_FLAG);193		dev_dbg(ph->dev, "RTC: %d evt: %x\n", r->rtc_id, r->rtc_evt);194		*src_id = r->rtc_evt;195	} else if (evt_id == SCMI_EVENT_IMX_BBM_BUTTON) {196		r->is_rtc = false;197		r->is_button = true;198		r->timestamp = timestamp;199		dev_dbg(ph->dev, "BBM Button\n");200		*src_id = 0;201	} else {202		WARN_ON_ONCE(1);203		return NULL;204	}205 206	return r;207}208 209static const struct scmi_event scmi_imx_bbm_events[] = {210	{211		.id = SCMI_EVENT_IMX_BBM_RTC,212		.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),213		.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),214	},215	{216		.id = SCMI_EVENT_IMX_BBM_BUTTON,217		.max_payld_sz = sizeof(struct scmi_imx_bbm_notify_payld),218		.max_report_sz = sizeof(struct scmi_imx_bbm_notif_report),219	},220};221 222static const struct scmi_event_ops scmi_imx_bbm_event_ops = {223	.set_notify_enabled = scmi_imx_bbm_set_notify_enabled,224	.fill_custom_report = scmi_imx_bbm_fill_custom_report,225};226 227static const struct scmi_protocol_events scmi_imx_bbm_protocol_events = {228	.queue_sz = SCMI_PROTO_QUEUE_SZ,229	.ops = &scmi_imx_bbm_event_ops,230	.evts = scmi_imx_bbm_events,231	.num_events = ARRAY_SIZE(scmi_imx_bbm_events),232	.num_sources = 1,233};234 235static int scmi_imx_bbm_rtc_time_set(const struct scmi_protocol_handle *ph,236				     u32 rtc_id, u64 sec)237{238	struct scmi_imx_bbm_info *pi = ph->get_priv(ph);239	struct scmi_imx_bbm_set_time *cfg;240	struct scmi_xfer *t;241	int ret;242 243	if (rtc_id >= pi->nr_rtc)244		return -EINVAL;245 246	ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_SET, sizeof(*cfg), 0, &t);247	if (ret)248		return ret;249 250	cfg = t->tx.buf;251	cfg->id = cpu_to_le32(rtc_id);252	cfg->flags = 0;253	cfg->value_low = cpu_to_le32(lower_32_bits(sec));254	cfg->value_high = cpu_to_le32(upper_32_bits(sec));255 256	ret = ph->xops->do_xfer(ph, t);257 258	ph->xops->xfer_put(ph, t);259 260	return ret;261}262 263static int scmi_imx_bbm_rtc_time_get(const struct scmi_protocol_handle *ph,264				     u32 rtc_id, u64 *value)265{266	struct scmi_imx_bbm_info *pi = ph->get_priv(ph);267	struct scmi_imx_bbm_get_time *cfg;268	struct scmi_xfer *t;269	int ret;270 271	if (rtc_id >= pi->nr_rtc)272		return -EINVAL;273 274	ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_TIME_GET, sizeof(*cfg),275				      sizeof(u64), &t);276	if (ret)277		return ret;278 279	cfg = t->tx.buf;280	cfg->id = cpu_to_le32(rtc_id);281	cfg->flags = 0;282 283	ret = ph->xops->do_xfer(ph, t);284	if (!ret)285		*value = get_unaligned_le64(t->rx.buf);286 287	ph->xops->xfer_put(ph, t);288 289	return ret;290}291 292static int scmi_imx_bbm_rtc_alarm_set(const struct scmi_protocol_handle *ph,293				      u32 rtc_id, bool enable, u64 sec)294{295	struct scmi_imx_bbm_info *pi = ph->get_priv(ph);296	struct scmi_imx_bbm_alarm_time *cfg;297	struct scmi_xfer *t;298	int ret;299 300	if (rtc_id >= pi->nr_rtc)301		return -EINVAL;302 303	ret = ph->xops->xfer_get_init(ph, IMX_BBM_RTC_ALARM_SET, sizeof(*cfg), 0, &t);304	if (ret)305		return ret;306 307	cfg = t->tx.buf;308	cfg->id = cpu_to_le32(rtc_id);309	cfg->flags = enable ?310		     cpu_to_le32(SCMI_IMX_BBM_RTC_ALARM_ENABLE_FLAG) : 0;311	cfg->value_low = cpu_to_le32(lower_32_bits(sec));312	cfg->value_high = cpu_to_le32(upper_32_bits(sec));313 314	ret = ph->xops->do_xfer(ph, t);315 316	ph->xops->xfer_put(ph, t);317 318	return ret;319}320 321static int scmi_imx_bbm_button_get(const struct scmi_protocol_handle *ph, u32 *state)322{323	struct scmi_xfer *t;324	int ret;325 326	ret = ph->xops->xfer_get_init(ph, IMX_BBM_BUTTON_GET, 0, sizeof(u32), &t);327	if (ret)328		return ret;329 330	ret = ph->xops->do_xfer(ph, t);331	if (!ret)332		*state = get_unaligned_le32(t->rx.buf);333 334	ph->xops->xfer_put(ph, t);335 336	return ret;337}338 339static const struct scmi_imx_bbm_proto_ops scmi_imx_bbm_proto_ops = {340	.rtc_time_get = scmi_imx_bbm_rtc_time_get,341	.rtc_time_set = scmi_imx_bbm_rtc_time_set,342	.rtc_alarm_set = scmi_imx_bbm_rtc_alarm_set,343	.button_get = scmi_imx_bbm_button_get,344};345 346static int scmi_imx_bbm_protocol_init(const struct scmi_protocol_handle *ph)347{348	u32 version;349	int ret;350	struct scmi_imx_bbm_info *binfo;351 352	ret = ph->xops->version_get(ph, &version);353	if (ret)354		return ret;355 356	dev_info(ph->dev, "NXP SM BBM Version %d.%d\n",357		 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));358 359	binfo = devm_kzalloc(ph->dev, sizeof(*binfo), GFP_KERNEL);360	if (!binfo)361		return -ENOMEM;362 363	ret = scmi_imx_bbm_attributes_get(ph, binfo);364	if (ret)365		return ret;366 367	return ph->set_priv(ph, binfo, version);368}369 370static const struct scmi_protocol scmi_imx_bbm = {371	.id = SCMI_PROTOCOL_IMX_BBM,372	.owner = THIS_MODULE,373	.instance_init = &scmi_imx_bbm_protocol_init,374	.ops = &scmi_imx_bbm_proto_ops,375	.events = &scmi_imx_bbm_protocol_events,376	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,377	.vendor_id = "NXP",378	.sub_vendor_id = "IMX",379};380module_scmi_protocol(scmi_imx_bbm);381 382MODULE_DESCRIPTION("i.MX SCMI BBM driver");383MODULE_LICENSE("GPL");384