1// SPDX-License-Identifier: GPL-2.0
2/*
3 * System Control and Management Interface (SCMI) Sensor Protocol
4 *
5 * Copyright (C) 2018 ARM Ltd.
6 */
7
8#define pr_fmt(fmt) "SCMI Notifications SENSOR - " fmt
9
10#include <linux/scmi_protocol.h>
11
12#include "common.h"
13#include "notify.h"
14
15enum scmi_sensor_protocol_cmd {
16	SENSOR_DESCRIPTION_GET = 0x3,
17	SENSOR_TRIP_POINT_NOTIFY = 0x4,
18	SENSOR_TRIP_POINT_CONFIG = 0x5,
19	SENSOR_READING_GET = 0x6,
20};
21
22struct scmi_msg_resp_sensor_attributes {
23	__le16 num_sensors;
24	u8 max_requests;
25	u8 reserved;
26	__le32 reg_addr_low;
27	__le32 reg_addr_high;
28	__le32 reg_size;
29};
30
31struct scmi_msg_resp_sensor_description {
32	__le16 num_returned;
33	__le16 num_remaining;
34	struct {
35		__le32 id;
36		__le32 attributes_low;
37#define SUPPORTS_ASYNC_READ(x)	((x) & BIT(31))
38#define NUM_TRIP_POINTS(x)	((x) & 0xff)
39		__le32 attributes_high;
40#define SENSOR_TYPE(x)		((x) & 0xff)
41#define SENSOR_SCALE(x)		(((x) >> 11) & 0x1f)
42#define SENSOR_SCALE_SIGN	BIT(4)
43#define SENSOR_SCALE_EXTEND	GENMASK(7, 5)
44#define SENSOR_UPDATE_SCALE(x)	(((x) >> 22) & 0x1f)
45#define SENSOR_UPDATE_BASE(x)	(((x) >> 27) & 0x1f)
46		    u8 name[SCMI_MAX_STR_SIZE];
47	} desc[0];
48};
49
50struct scmi_msg_sensor_trip_point_notify {
51	__le32 id;
52	__le32 event_control;
53#define SENSOR_TP_NOTIFY_ALL	BIT(0)
54};
55
56struct scmi_msg_set_sensor_trip_point {
57	__le32 id;
58	__le32 event_control;
59#define SENSOR_TP_EVENT_MASK	(0x3)
60#define SENSOR_TP_DISABLED	0x0
61#define SENSOR_TP_POSITIVE	0x1
62#define SENSOR_TP_NEGATIVE	0x2
63#define SENSOR_TP_BOTH		0x3
64#define SENSOR_TP_ID(x)		(((x) & 0xff) << 4)
65	__le32 value_low;
66	__le32 value_high;
67};
68
69struct scmi_msg_sensor_reading_get {
70	__le32 id;
71	__le32 flags;
72#define SENSOR_READ_ASYNC	BIT(0)
73};
74
75struct scmi_sensor_trip_notify_payld {
76	__le32 agent_id;
77	__le32 sensor_id;
78	__le32 trip_point_desc;
79};
80
81struct sensors_info {
82	u32 version;
83	int num_sensors;
84	int max_requests;
85	u64 reg_addr;
86	u32 reg_size;
87	struct scmi_sensor_info *sensors;
88};
89
90static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
91				      struct sensors_info *si)
92{
93	int ret;
94	struct scmi_xfer *t;
95	struct scmi_msg_resp_sensor_attributes *attr;
96
97	ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
98				 SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t);
99	if (ret)
100		return ret;
101
102	attr = t->rx.buf;
103
104	ret = scmi_do_xfer(handle, t);
105	if (!ret) {
106		si->num_sensors = le16_to_cpu(attr->num_sensors);
107		si->max_requests = attr->max_requests;
108		si->reg_addr = le32_to_cpu(attr->reg_addr_low) |
109				(u64)le32_to_cpu(attr->reg_addr_high) << 32;
110		si->reg_size = le32_to_cpu(attr->reg_size);
111	}
112
113	scmi_xfer_put(handle, t);
114	return ret;
115}
116
117static int scmi_sensor_description_get(const struct scmi_handle *handle,
118				       struct sensors_info *si)
119{
120	int ret, cnt;
121	u32 desc_index = 0;
122	u16 num_returned, num_remaining;
123	struct scmi_xfer *t;
124	struct scmi_msg_resp_sensor_description *buf;
125
126	ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET,
127				 SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t);
128	if (ret)
129		return ret;
130
131	buf = t->rx.buf;
132
133	do {
134		/* Set the number of sensors to be skipped/already read */
135		put_unaligned_le32(desc_index, t->tx.buf);
136
137		ret = scmi_do_xfer(handle, t);
138		if (ret)
139			break;
140
141		num_returned = le16_to_cpu(buf->num_returned);
142		num_remaining = le16_to_cpu(buf->num_remaining);
143
144		if (desc_index + num_returned > si->num_sensors) {
145			dev_err(handle->dev, "No. of sensors can't exceed %d",
146				si->num_sensors);
147			break;
148		}
149
150		for (cnt = 0; cnt < num_returned; cnt++) {
151			u32 attrh, attrl;
152			struct scmi_sensor_info *s;
153
154			attrl = le32_to_cpu(buf->desc[cnt].attributes_low);
155			attrh = le32_to_cpu(buf->desc[cnt].attributes_high);
156			s = &si->sensors[desc_index + cnt];
157			s->id = le32_to_cpu(buf->desc[cnt].id);
158			s->type = SENSOR_TYPE(attrh);
159			s->scale = SENSOR_SCALE(attrh);
160			/* Sign extend to a full s8 */
161			if (s->scale & SENSOR_SCALE_SIGN)
162				s->scale |= SENSOR_SCALE_EXTEND;
163			s->async = SUPPORTS_ASYNC_READ(attrl);
164			s->num_trip_points = NUM_TRIP_POINTS(attrl);
165			strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
166		}
167
168		desc_index += num_returned;
169
170		scmi_reset_rx_to_maxsz(handle, t);
171		/*
172		 * check for both returned and remaining to avoid infinite
173		 * loop due to buggy firmware
174		 */
175	} while (num_returned && num_remaining);
176
177	scmi_xfer_put(handle, t);
178	return ret;
179}
180
181static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
182					 u32 sensor_id, bool enable)
183{
184	int ret;
185	u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0;
186	struct scmi_xfer *t;
187	struct scmi_msg_sensor_trip_point_notify *cfg;
188
189	ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY,
190				 SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
191	if (ret)
192		return ret;
193
194	cfg = t->tx.buf;
195	cfg->id = cpu_to_le32(sensor_id);
196	cfg->event_control = cpu_to_le32(evt_cntl);
197
198	ret = scmi_do_xfer(handle, t);
199
200	scmi_xfer_put(handle, t);
201	return ret;
202}
203
204static int
205scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
206			      u8 trip_id, u64 trip_value)
207{
208	int ret;
209	u32 evt_cntl = SENSOR_TP_BOTH;
210	struct scmi_xfer *t;
211	struct scmi_msg_set_sensor_trip_point *trip;
212
213	ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG,
214				 SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t);
215	if (ret)
216		return ret;
217
218	trip = t->tx.buf;
219	trip->id = cpu_to_le32(sensor_id);
220	trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id));
221	trip->value_low = cpu_to_le32(trip_value & 0xffffffff);
222	trip->value_high = cpu_to_le32(trip_value >> 32);
223
224	ret = scmi_do_xfer(handle, t);
225
226	scmi_xfer_put(handle, t);
227	return ret;
228}
229
230static int scmi_sensor_reading_get(const struct scmi_handle *handle,
231				   u32 sensor_id, u64 *value)
232{
233	int ret;
234	struct scmi_xfer *t;
235	struct scmi_msg_sensor_reading_get *sensor;
236	struct sensors_info *si = handle->sensor_priv;
237	struct scmi_sensor_info *s = si->sensors + sensor_id;
238
239	ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
240				 SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
241				 sizeof(u64), &t);
242	if (ret)
243		return ret;
244
245	sensor = t->tx.buf;
246	sensor->id = cpu_to_le32(sensor_id);
247
248	if (s->async) {
249		sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
250		ret = scmi_do_xfer_with_response(handle, t);
251		if (!ret)
252			*value = get_unaligned_le64((void *)
253						    ((__le32 *)t->rx.buf + 1));
254	} else {
255		sensor->flags = cpu_to_le32(0);
256		ret = scmi_do_xfer(handle, t);
257		if (!ret)
258			*value = get_unaligned_le64(t->rx.buf);
259	}
260
261	scmi_xfer_put(handle, t);
262	return ret;
263}
264
265static const struct scmi_sensor_info *
266scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
267{
268	struct sensors_info *si = handle->sensor_priv;
269
270	return si->sensors + sensor_id;
271}
272
273static int scmi_sensor_count_get(const struct scmi_handle *handle)
274{
275	struct sensors_info *si = handle->sensor_priv;
276
277	return si->num_sensors;
278}
279
280static const struct scmi_sensor_ops sensor_ops = {
281	.count_get = scmi_sensor_count_get,
282	.info_get = scmi_sensor_info_get,
283	.trip_point_config = scmi_sensor_trip_point_config,
284	.reading_get = scmi_sensor_reading_get,
285};
286
287static int scmi_sensor_set_notify_enabled(const struct scmi_handle *handle,
288					  u8 evt_id, u32 src_id, bool enable)
289{
290	int ret;
291
292	ret = scmi_sensor_trip_point_notify(handle, src_id, enable);
293	if (ret)
294		pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
295			 evt_id, src_id, ret);
296
297	return ret;
298}
299
300static void *scmi_sensor_fill_custom_report(const struct scmi_handle *handle,
301					    u8 evt_id, ktime_t timestamp,
302					    const void *payld, size_t payld_sz,
303					    void *report, u32 *src_id)
304{
305	const struct scmi_sensor_trip_notify_payld *p = payld;
306	struct scmi_sensor_trip_point_report *r = report;
307
308	if (evt_id != SCMI_EVENT_SENSOR_TRIP_POINT_EVENT ||
309	    sizeof(*p) != payld_sz)
310		return NULL;
311
312	r->timestamp = timestamp;
313	r->agent_id = le32_to_cpu(p->agent_id);
314	r->sensor_id = le32_to_cpu(p->sensor_id);
315	r->trip_point_desc = le32_to_cpu(p->trip_point_desc);
316	*src_id = r->sensor_id;
317
318	return r;
319}
320
321static const struct scmi_event sensor_events[] = {
322	{
323		.id = SCMI_EVENT_SENSOR_TRIP_POINT_EVENT,
324		.max_payld_sz = sizeof(struct scmi_sensor_trip_notify_payld),
325		.max_report_sz = sizeof(struct scmi_sensor_trip_point_report),
326	},
327};
328
329static const struct scmi_event_ops sensor_event_ops = {
330	.set_notify_enabled = scmi_sensor_set_notify_enabled,
331	.fill_custom_report = scmi_sensor_fill_custom_report,
332};
333
334static int scmi_sensors_protocol_init(struct scmi_handle *handle)
335{
336	u32 version;
337	struct sensors_info *sinfo;
338
339	scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version);
340
341	dev_dbg(handle->dev, "Sensor Version %d.%d\n",
342		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
343
344	sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL);
345	if (!sinfo)
346		return -ENOMEM;
347
348	scmi_sensor_attributes_get(handle, sinfo);
349
350	sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors,
351				      sizeof(*sinfo->sensors), GFP_KERNEL);
352	if (!sinfo->sensors)
353		return -ENOMEM;
354
355	scmi_sensor_description_get(handle, sinfo);
356
357	scmi_register_protocol_events(handle,
358				      SCMI_PROTOCOL_SENSOR, SCMI_PROTO_QUEUE_SZ,
359				      &sensor_event_ops, sensor_events,
360				      ARRAY_SIZE(sensor_events),
361				      sinfo->num_sensors);
362
363	sinfo->version = version;
364	handle->sensor_ops = &sensor_ops;
365	handle->sensor_priv = sinfo;
366
367	return 0;
368}
369
370DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(SCMI_PROTOCOL_SENSOR, sensors)
371