Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / firmware / arm_scmi / sensors.c
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 #include "common.h"
9
10 enum scmi_sensor_protocol_cmd {
11         SENSOR_DESCRIPTION_GET = 0x3,
12         SENSOR_TRIP_POINT_NOTIFY = 0x4,
13         SENSOR_TRIP_POINT_CONFIG = 0x5,
14         SENSOR_READING_GET = 0x6,
15 };
16
17 struct scmi_msg_resp_sensor_attributes {
18         __le16 num_sensors;
19         u8 max_requests;
20         u8 reserved;
21         __le32 reg_addr_low;
22         __le32 reg_addr_high;
23         __le32 reg_size;
24 };
25
26 struct scmi_msg_resp_sensor_description {
27         __le16 num_returned;
28         __le16 num_remaining;
29         struct {
30                 __le32 id;
31                 __le32 attributes_low;
32 #define SUPPORTS_ASYNC_READ(x)  ((x) & BIT(31))
33 #define NUM_TRIP_POINTS(x)      ((x) & 0xff)
34                 __le32 attributes_high;
35 #define SENSOR_TYPE(x)          ((x) & 0xff)
36 #define SENSOR_SCALE(x)         (((x) >> 11) & 0x1f)
37 #define SENSOR_SCALE_SIGN       BIT(4)
38 #define SENSOR_SCALE_EXTEND     GENMASK(7, 5)
39 #define SENSOR_UPDATE_SCALE(x)  (((x) >> 22) & 0x1f)
40 #define SENSOR_UPDATE_BASE(x)   (((x) >> 27) & 0x1f)
41                     u8 name[SCMI_MAX_STR_SIZE];
42         } desc[0];
43 };
44
45 struct scmi_msg_sensor_trip_point_notify {
46         __le32 id;
47         __le32 event_control;
48 #define SENSOR_TP_NOTIFY_ALL    BIT(0)
49 };
50
51 struct scmi_msg_set_sensor_trip_point {
52         __le32 id;
53         __le32 event_control;
54 #define SENSOR_TP_EVENT_MASK    (0x3)
55 #define SENSOR_TP_DISABLED      0x0
56 #define SENSOR_TP_POSITIVE      0x1
57 #define SENSOR_TP_NEGATIVE      0x2
58 #define SENSOR_TP_BOTH          0x3
59 #define SENSOR_TP_ID(x)         (((x) & 0xff) << 4)
60         __le32 value_low;
61         __le32 value_high;
62 };
63
64 struct scmi_msg_sensor_reading_get {
65         __le32 id;
66         __le32 flags;
67 #define SENSOR_READ_ASYNC       BIT(0)
68 };
69
70 struct sensors_info {
71         int num_sensors;
72         int max_requests;
73         u64 reg_addr;
74         u32 reg_size;
75         struct scmi_sensor_info *sensors;
76 };
77
78 static int scmi_sensor_attributes_get(const struct scmi_handle *handle,
79                                       struct sensors_info *si)
80 {
81         int ret;
82         struct scmi_xfer *t;
83         struct scmi_msg_resp_sensor_attributes *attr;
84
85         ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
86                                  SCMI_PROTOCOL_SENSOR, 0, sizeof(*attr), &t);
87         if (ret)
88                 return ret;
89
90         attr = t->rx.buf;
91
92         ret = scmi_do_xfer(handle, t);
93         if (!ret) {
94                 si->num_sensors = le16_to_cpu(attr->num_sensors);
95                 si->max_requests = attr->max_requests;
96                 si->reg_addr = le32_to_cpu(attr->reg_addr_low) |
97                                 (u64)le32_to_cpu(attr->reg_addr_high) << 32;
98                 si->reg_size = le32_to_cpu(attr->reg_size);
99         }
100
101         scmi_xfer_put(handle, t);
102         return ret;
103 }
104
105 static int scmi_sensor_description_get(const struct scmi_handle *handle,
106                                        struct sensors_info *si)
107 {
108         int ret, cnt;
109         u32 desc_index = 0;
110         u16 num_returned, num_remaining;
111         struct scmi_xfer *t;
112         struct scmi_msg_resp_sensor_description *buf;
113
114         ret = scmi_xfer_get_init(handle, SENSOR_DESCRIPTION_GET,
115                                  SCMI_PROTOCOL_SENSOR, sizeof(__le32), 0, &t);
116         if (ret)
117                 return ret;
118
119         buf = t->rx.buf;
120
121         do {
122                 /* Set the number of sensors to be skipped/already read */
123                 put_unaligned_le32(desc_index, t->tx.buf);
124
125                 ret = scmi_do_xfer(handle, t);
126                 if (ret)
127                         break;
128
129                 num_returned = le16_to_cpu(buf->num_returned);
130                 num_remaining = le16_to_cpu(buf->num_remaining);
131
132                 if (desc_index + num_returned > si->num_sensors) {
133                         dev_err(handle->dev, "No. of sensors can't exceed %d",
134                                 si->num_sensors);
135                         break;
136                 }
137
138                 for (cnt = 0; cnt < num_returned; cnt++) {
139                         u32 attrh, attrl;
140                         struct scmi_sensor_info *s;
141
142                         attrl = le32_to_cpu(buf->desc[cnt].attributes_low);
143                         attrh = le32_to_cpu(buf->desc[cnt].attributes_high);
144                         s = &si->sensors[desc_index + cnt];
145                         s->id = le32_to_cpu(buf->desc[cnt].id);
146                         s->type = SENSOR_TYPE(attrh);
147                         s->scale = SENSOR_SCALE(attrh);
148                         /* Sign extend to a full s8 */
149                         if (s->scale & SENSOR_SCALE_SIGN)
150                                 s->scale |= SENSOR_SCALE_EXTEND;
151                         s->async = SUPPORTS_ASYNC_READ(attrl);
152                         s->num_trip_points = NUM_TRIP_POINTS(attrl);
153                         strlcpy(s->name, buf->desc[cnt].name, SCMI_MAX_STR_SIZE);
154                 }
155
156                 desc_index += num_returned;
157                 /*
158                  * check for both returned and remaining to avoid infinite
159                  * loop due to buggy firmware
160                  */
161         } while (num_returned && num_remaining);
162
163         scmi_xfer_put(handle, t);
164         return ret;
165 }
166
167 static int scmi_sensor_trip_point_notify(const struct scmi_handle *handle,
168                                          u32 sensor_id, bool enable)
169 {
170         int ret;
171         u32 evt_cntl = enable ? SENSOR_TP_NOTIFY_ALL : 0;
172         struct scmi_xfer *t;
173         struct scmi_msg_sensor_trip_point_notify *cfg;
174
175         ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_NOTIFY,
176                                  SCMI_PROTOCOL_SENSOR, sizeof(*cfg), 0, &t);
177         if (ret)
178                 return ret;
179
180         cfg = t->tx.buf;
181         cfg->id = cpu_to_le32(sensor_id);
182         cfg->event_control = cpu_to_le32(evt_cntl);
183
184         ret = scmi_do_xfer(handle, t);
185
186         scmi_xfer_put(handle, t);
187         return ret;
188 }
189
190 static int
191 scmi_sensor_trip_point_config(const struct scmi_handle *handle, u32 sensor_id,
192                               u8 trip_id, u64 trip_value)
193 {
194         int ret;
195         u32 evt_cntl = SENSOR_TP_BOTH;
196         struct scmi_xfer *t;
197         struct scmi_msg_set_sensor_trip_point *trip;
198
199         ret = scmi_xfer_get_init(handle, SENSOR_TRIP_POINT_CONFIG,
200                                  SCMI_PROTOCOL_SENSOR, sizeof(*trip), 0, &t);
201         if (ret)
202                 return ret;
203
204         trip = t->tx.buf;
205         trip->id = cpu_to_le32(sensor_id);
206         trip->event_control = cpu_to_le32(evt_cntl | SENSOR_TP_ID(trip_id));
207         trip->value_low = cpu_to_le32(trip_value & 0xffffffff);
208         trip->value_high = cpu_to_le32(trip_value >> 32);
209
210         ret = scmi_do_xfer(handle, t);
211
212         scmi_xfer_put(handle, t);
213         return ret;
214 }
215
216 static int scmi_sensor_reading_get(const struct scmi_handle *handle,
217                                    u32 sensor_id, u64 *value)
218 {
219         int ret;
220         struct scmi_xfer *t;
221         struct scmi_msg_sensor_reading_get *sensor;
222         struct sensors_info *si = handle->sensor_priv;
223         struct scmi_sensor_info *s = si->sensors + sensor_id;
224
225         ret = scmi_xfer_get_init(handle, SENSOR_READING_GET,
226                                  SCMI_PROTOCOL_SENSOR, sizeof(*sensor),
227                                  sizeof(u64), &t);
228         if (ret)
229                 return ret;
230
231         sensor = t->tx.buf;
232         sensor->id = cpu_to_le32(sensor_id);
233
234         if (s->async) {
235                 sensor->flags = cpu_to_le32(SENSOR_READ_ASYNC);
236                 ret = scmi_do_xfer_with_response(handle, t);
237                 if (!ret)
238                         *value = get_unaligned_le64((void *)
239                                                     ((__le32 *)t->rx.buf + 1));
240         } else {
241                 sensor->flags = cpu_to_le32(0);
242                 ret = scmi_do_xfer(handle, t);
243                 if (!ret)
244                         *value = get_unaligned_le64(t->rx.buf);
245         }
246
247         scmi_xfer_put(handle, t);
248         return ret;
249 }
250
251 static const struct scmi_sensor_info *
252 scmi_sensor_info_get(const struct scmi_handle *handle, u32 sensor_id)
253 {
254         struct sensors_info *si = handle->sensor_priv;
255
256         return si->sensors + sensor_id;
257 }
258
259 static int scmi_sensor_count_get(const struct scmi_handle *handle)
260 {
261         struct sensors_info *si = handle->sensor_priv;
262
263         return si->num_sensors;
264 }
265
266 static struct scmi_sensor_ops sensor_ops = {
267         .count_get = scmi_sensor_count_get,
268         .info_get = scmi_sensor_info_get,
269         .trip_point_notify = scmi_sensor_trip_point_notify,
270         .trip_point_config = scmi_sensor_trip_point_config,
271         .reading_get = scmi_sensor_reading_get,
272 };
273
274 static int scmi_sensors_protocol_init(struct scmi_handle *handle)
275 {
276         u32 version;
277         struct sensors_info *sinfo;
278
279         scmi_version_get(handle, SCMI_PROTOCOL_SENSOR, &version);
280
281         dev_dbg(handle->dev, "Sensor Version %d.%d\n",
282                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
283
284         sinfo = devm_kzalloc(handle->dev, sizeof(*sinfo), GFP_KERNEL);
285         if (!sinfo)
286                 return -ENOMEM;
287
288         scmi_sensor_attributes_get(handle, sinfo);
289
290         sinfo->sensors = devm_kcalloc(handle->dev, sinfo->num_sensors,
291                                       sizeof(*sinfo->sensors), GFP_KERNEL);
292         if (!sinfo->sensors)
293                 return -ENOMEM;
294
295         scmi_sensor_description_get(handle, sinfo);
296
297         handle->sensor_ops = &sensor_ops;
298         handle->sensor_priv = sinfo;
299
300         return 0;
301 }
302
303 static int __init scmi_sensors_init(void)
304 {
305         return scmi_protocol_register(SCMI_PROTOCOL_SENSOR,
306                                       &scmi_sensors_protocol_init);
307 }
308 subsys_initcall(scmi_sensors_init);