1
2
3
4
5
6
7
8#include <linux/module.h>
9#include <linux/scmi_protocol.h>
10
11#include "protocols.h"
12
13#define VOLTAGE_DOMS_NUM_MASK GENMASK(15, 0)
14#define REMAINING_LEVELS_MASK GENMASK(31, 16)
15#define RETURNED_LEVELS_MASK GENMASK(11, 0)
16
17enum scmi_voltage_protocol_cmd {
18 VOLTAGE_DOMAIN_ATTRIBUTES = 0x3,
19 VOLTAGE_DESCRIBE_LEVELS = 0x4,
20 VOLTAGE_CONFIG_SET = 0x5,
21 VOLTAGE_CONFIG_GET = 0x6,
22 VOLTAGE_LEVEL_SET = 0x7,
23 VOLTAGE_LEVEL_GET = 0x8,
24 VOLTAGE_DOMAIN_NAME_GET = 0x09,
25};
26
27#define NUM_VOLTAGE_DOMAINS(x) ((u16)(FIELD_GET(VOLTAGE_DOMS_NUM_MASK, (x))))
28
29struct scmi_msg_resp_domain_attributes {
30 __le32 attr;
31#define SUPPORTS_ASYNC_LEVEL_SET(x) ((x) & BIT(31))
32#define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(30))
33 u8 name[SCMI_SHORT_NAME_MAX_SIZE];
34};
35
36struct scmi_msg_cmd_describe_levels {
37 __le32 domain_id;
38 __le32 level_index;
39};
40
41struct scmi_msg_resp_describe_levels {
42 __le32 flags;
43#define NUM_REMAINING_LEVELS(f) ((u16)(FIELD_GET(REMAINING_LEVELS_MASK, (f))))
44#define NUM_RETURNED_LEVELS(f) ((u16)(FIELD_GET(RETURNED_LEVELS_MASK, (f))))
45#define SUPPORTS_SEGMENTED_LEVELS(f) ((f) & BIT(12))
46 __le32 voltage[];
47};
48
49struct scmi_msg_cmd_config_set {
50 __le32 domain_id;
51 __le32 config;
52};
53
54struct scmi_msg_cmd_level_set {
55 __le32 domain_id;
56 __le32 flags;
57 __le32 voltage_level;
58};
59
60struct scmi_resp_voltage_level_set_complete {
61 __le32 domain_id;
62 __le32 voltage_level;
63};
64
65struct voltage_info {
66 unsigned int version;
67 unsigned int num_domains;
68 struct scmi_voltage_info *domains;
69};
70
71static int scmi_protocol_attributes_get(const struct scmi_protocol_handle *ph,
72 struct voltage_info *vinfo)
73{
74 int ret;
75 struct scmi_xfer *t;
76
77 ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
78 sizeof(__le32), &t);
79 if (ret)
80 return ret;
81
82 ret = ph->xops->do_xfer(ph, t);
83 if (!ret)
84 vinfo->num_domains =
85 NUM_VOLTAGE_DOMAINS(get_unaligned_le32(t->rx.buf));
86
87 ph->xops->xfer_put(ph, t);
88 return ret;
89}
90
91static int scmi_init_voltage_levels(struct device *dev,
92 struct scmi_voltage_info *v,
93 u32 num_returned, u32 num_remaining,
94 bool segmented)
95{
96 u32 num_levels;
97
98 num_levels = num_returned + num_remaining;
99
100
101
102
103 if (!num_levels ||
104 (segmented && (num_remaining || num_returned != 3))) {
105 dev_err(dev,
106 "Invalid level descriptor(%d/%d/%d) for voltage dom %d\n",
107 num_levels, num_returned, num_remaining, v->id);
108 return -EINVAL;
109 }
110
111 v->levels_uv = devm_kcalloc(dev, num_levels, sizeof(u32), GFP_KERNEL);
112 if (!v->levels_uv)
113 return -ENOMEM;
114
115 v->num_levels = num_levels;
116 v->segmented = segmented;
117
118 return 0;
119}
120
121struct scmi_volt_ipriv {
122 struct device *dev;
123 struct scmi_voltage_info *v;
124};
125
126static void iter_volt_levels_prepare_message(void *message,
127 unsigned int desc_index,
128 const void *priv)
129{
130 struct scmi_msg_cmd_describe_levels *msg = message;
131 const struct scmi_volt_ipriv *p = priv;
132
133 msg->domain_id = cpu_to_le32(p->v->id);
134 msg->level_index = cpu_to_le32(desc_index);
135}
136
137static int iter_volt_levels_update_state(struct scmi_iterator_state *st,
138 const void *response, void *priv)
139{
140 int ret = 0;
141 u32 flags;
142 const struct scmi_msg_resp_describe_levels *r = response;
143 struct scmi_volt_ipriv *p = priv;
144
145 flags = le32_to_cpu(r->flags);
146 st->num_returned = NUM_RETURNED_LEVELS(flags);
147 st->num_remaining = NUM_REMAINING_LEVELS(flags);
148
149
150 if (!p->v->num_levels) {
151 ret = scmi_init_voltage_levels(p->dev, p->v, st->num_returned,
152 st->num_remaining,
153 SUPPORTS_SEGMENTED_LEVELS(flags));
154 if (!ret)
155 st->max_resources = p->v->num_levels;
156 }
157
158 return ret;
159}
160
161static int
162iter_volt_levels_process_response(const struct scmi_protocol_handle *ph,
163 const void *response,
164 struct scmi_iterator_state *st, void *priv)
165{
166 s32 val;
167 const struct scmi_msg_resp_describe_levels *r = response;
168 struct scmi_volt_ipriv *p = priv;
169
170 val = (s32)le32_to_cpu(r->voltage[st->loop_idx]);
171 p->v->levels_uv[st->desc_index + st->loop_idx] = val;
172 if (val < 0)
173 p->v->negative_volts_allowed = true;
174
175 return 0;
176}
177
178static int scmi_voltage_levels_get(const struct scmi_protocol_handle *ph,
179 struct scmi_voltage_info *v)
180{
181 int ret;
182 void *iter;
183 struct scmi_iterator_ops ops = {
184 .prepare_message = iter_volt_levels_prepare_message,
185 .update_state = iter_volt_levels_update_state,
186 .process_response = iter_volt_levels_process_response,
187 };
188 struct scmi_volt_ipriv vpriv = {
189 .dev = ph->dev,
190 .v = v,
191 };
192
193 iter = ph->hops->iter_response_init(ph, &ops, v->num_levels,
194 VOLTAGE_DESCRIBE_LEVELS,
195 sizeof(struct scmi_msg_cmd_describe_levels),
196 &vpriv);
197 if (IS_ERR(iter))
198 return PTR_ERR(iter);
199
200 ret = ph->hops->iter_response_run(iter);
201 if (ret) {
202 v->num_levels = 0;
203 devm_kfree(ph->dev, v->levels_uv);
204 }
205
206 return ret;
207}
208
209static int scmi_voltage_descriptors_get(const struct scmi_protocol_handle *ph,
210 struct voltage_info *vinfo)
211{
212 int ret, dom;
213 struct scmi_xfer *td;
214 struct scmi_msg_resp_domain_attributes *resp_dom;
215
216 ret = ph->xops->xfer_get_init(ph, VOLTAGE_DOMAIN_ATTRIBUTES,
217 sizeof(__le32), sizeof(*resp_dom), &td);
218 if (ret)
219 return ret;
220 resp_dom = td->rx.buf;
221
222 for (dom = 0; dom < vinfo->num_domains; dom++) {
223 u32 attributes;
224 struct scmi_voltage_info *v;
225
226
227 put_unaligned_le32(dom, td->tx.buf);
228
229 if (ph->xops->do_xfer(ph, td))
230 continue;
231
232 v = vinfo->domains + dom;
233 v->id = dom;
234 attributes = le32_to_cpu(resp_dom->attr);
235 strscpy(v->name, resp_dom->name, SCMI_SHORT_NAME_MAX_SIZE);
236
237
238
239
240
241 if (PROTOCOL_REV_MAJOR(vinfo->version) >= 0x2) {
242 if (SUPPORTS_EXTENDED_NAMES(attributes))
243 ph->hops->extended_name_get(ph,
244 VOLTAGE_DOMAIN_NAME_GET,
245 v->id, v->name,
246 SCMI_MAX_STR_SIZE);
247 if (SUPPORTS_ASYNC_LEVEL_SET(attributes))
248 v->async_level_set = true;
249 }
250
251
252 scmi_voltage_levels_get(ph, v);
253 }
254
255 ph->xops->xfer_put(ph, td);
256
257 return ret;
258}
259
260static int __scmi_voltage_get_u32(const struct scmi_protocol_handle *ph,
261 u8 cmd_id, u32 domain_id, u32 *value)
262{
263 int ret;
264 struct scmi_xfer *t;
265 struct voltage_info *vinfo = ph->get_priv(ph);
266
267 if (domain_id >= vinfo->num_domains)
268 return -EINVAL;
269
270 ret = ph->xops->xfer_get_init(ph, cmd_id, sizeof(__le32), 0, &t);
271 if (ret)
272 return ret;
273
274 put_unaligned_le32(domain_id, t->tx.buf);
275 ret = ph->xops->do_xfer(ph, t);
276 if (!ret)
277 *value = get_unaligned_le32(t->rx.buf);
278
279 ph->xops->xfer_put(ph, t);
280 return ret;
281}
282
283static int scmi_voltage_config_set(const struct scmi_protocol_handle *ph,
284 u32 domain_id, u32 config)
285{
286 int ret;
287 struct scmi_xfer *t;
288 struct voltage_info *vinfo = ph->get_priv(ph);
289 struct scmi_msg_cmd_config_set *cmd;
290
291 if (domain_id >= vinfo->num_domains)
292 return -EINVAL;
293
294 ret = ph->xops->xfer_get_init(ph, VOLTAGE_CONFIG_SET,
295 sizeof(*cmd), 0, &t);
296 if (ret)
297 return ret;
298
299 cmd = t->tx.buf;
300 cmd->domain_id = cpu_to_le32(domain_id);
301 cmd->config = cpu_to_le32(config & GENMASK(3, 0));
302
303 ret = ph->xops->do_xfer(ph, t);
304
305 ph->xops->xfer_put(ph, t);
306 return ret;
307}
308
309static int scmi_voltage_config_get(const struct scmi_protocol_handle *ph,
310 u32 domain_id, u32 *config)
311{
312 return __scmi_voltage_get_u32(ph, VOLTAGE_CONFIG_GET,
313 domain_id, config);
314}
315
316static int scmi_voltage_level_set(const struct scmi_protocol_handle *ph,
317 u32 domain_id,
318 enum scmi_voltage_level_mode mode,
319 s32 volt_uV)
320{
321 int ret;
322 struct scmi_xfer *t;
323 struct voltage_info *vinfo = ph->get_priv(ph);
324 struct scmi_msg_cmd_level_set *cmd;
325 struct scmi_voltage_info *v;
326
327 if (domain_id >= vinfo->num_domains)
328 return -EINVAL;
329
330 ret = ph->xops->xfer_get_init(ph, VOLTAGE_LEVEL_SET,
331 sizeof(*cmd), 0, &t);
332 if (ret)
333 return ret;
334
335 v = vinfo->domains + domain_id;
336
337 cmd = t->tx.buf;
338 cmd->domain_id = cpu_to_le32(domain_id);
339 cmd->voltage_level = cpu_to_le32(volt_uV);
340
341 if (!v->async_level_set || mode != SCMI_VOLTAGE_LEVEL_SET_AUTO) {
342 cmd->flags = cpu_to_le32(0x0);
343 ret = ph->xops->do_xfer(ph, t);
344 } else {
345 cmd->flags = cpu_to_le32(0x1);
346 ret = ph->xops->do_xfer_with_response(ph, t);
347 if (!ret) {
348 struct scmi_resp_voltage_level_set_complete *resp;
349
350 resp = t->rx.buf;
351 if (le32_to_cpu(resp->domain_id) == domain_id)
352 dev_dbg(ph->dev,
353 "Voltage domain %d set async to %d\n",
354 v->id,
355 le32_to_cpu(resp->voltage_level));
356 else
357 ret = -EPROTO;
358 }
359 }
360
361 ph->xops->xfer_put(ph, t);
362 return ret;
363}
364
365static int scmi_voltage_level_get(const struct scmi_protocol_handle *ph,
366 u32 domain_id, s32 *volt_uV)
367{
368 return __scmi_voltage_get_u32(ph, VOLTAGE_LEVEL_GET,
369 domain_id, (u32 *)volt_uV);
370}
371
372static const struct scmi_voltage_info * __must_check
373scmi_voltage_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
374{
375 struct voltage_info *vinfo = ph->get_priv(ph);
376
377 if (domain_id >= vinfo->num_domains ||
378 !vinfo->domains[domain_id].num_levels)
379 return NULL;
380
381 return vinfo->domains + domain_id;
382}
383
384static int scmi_voltage_domains_num_get(const struct scmi_protocol_handle *ph)
385{
386 struct voltage_info *vinfo = ph->get_priv(ph);
387
388 return vinfo->num_domains;
389}
390
391static struct scmi_voltage_proto_ops voltage_proto_ops = {
392 .num_domains_get = scmi_voltage_domains_num_get,
393 .info_get = scmi_voltage_info_get,
394 .config_set = scmi_voltage_config_set,
395 .config_get = scmi_voltage_config_get,
396 .level_set = scmi_voltage_level_set,
397 .level_get = scmi_voltage_level_get,
398};
399
400static int scmi_voltage_protocol_init(const struct scmi_protocol_handle *ph)
401{
402 int ret;
403 u32 version;
404 struct voltage_info *vinfo;
405
406 ret = ph->xops->version_get(ph, &version);
407 if (ret)
408 return ret;
409
410 dev_dbg(ph->dev, "Voltage Version %d.%d\n",
411 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
412
413 vinfo = devm_kzalloc(ph->dev, sizeof(*vinfo), GFP_KERNEL);
414 if (!vinfo)
415 return -ENOMEM;
416 vinfo->version = version;
417
418 ret = scmi_protocol_attributes_get(ph, vinfo);
419 if (ret)
420 return ret;
421
422 if (vinfo->num_domains) {
423 vinfo->domains = devm_kcalloc(ph->dev, vinfo->num_domains,
424 sizeof(*vinfo->domains),
425 GFP_KERNEL);
426 if (!vinfo->domains)
427 return -ENOMEM;
428 ret = scmi_voltage_descriptors_get(ph, vinfo);
429 if (ret)
430 return ret;
431 } else {
432 dev_warn(ph->dev, "No Voltage domains found.\n");
433 }
434
435 return ph->set_priv(ph, vinfo);
436}
437
438static const struct scmi_protocol scmi_voltage = {
439 .id = SCMI_PROTOCOL_VOLTAGE,
440 .owner = THIS_MODULE,
441 .instance_init = &scmi_voltage_protocol_init,
442 .ops = &voltage_proto_ops,
443};
444
445DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(voltage, scmi_voltage)
446