Merge tag 'arm-late-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-block.git] / drivers / firmware / arm_scmi / powercap.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * System Control and Management Interface (SCMI) Powercap Protocol
4  *
5  * Copyright (C) 2022 ARM Ltd.
6  */
7
8 #define pr_fmt(fmt) "SCMI Notifications POWERCAP - " fmt
9
10 #include <linux/bitfield.h>
11 #include <linux/io.h>
12 #include <linux/module.h>
13 #include <linux/scmi_protocol.h>
14
15 #include <trace/events/scmi.h>
16
17 #include "protocols.h"
18 #include "notify.h"
19
20 enum scmi_powercap_protocol_cmd {
21         POWERCAP_DOMAIN_ATTRIBUTES = 0x3,
22         POWERCAP_CAP_GET = 0x4,
23         POWERCAP_CAP_SET = 0x5,
24         POWERCAP_PAI_GET = 0x6,
25         POWERCAP_PAI_SET = 0x7,
26         POWERCAP_DOMAIN_NAME_GET = 0x8,
27         POWERCAP_MEASUREMENTS_GET = 0x9,
28         POWERCAP_CAP_NOTIFY = 0xa,
29         POWERCAP_MEASUREMENTS_NOTIFY = 0xb,
30         POWERCAP_DESCRIBE_FASTCHANNEL = 0xc,
31 };
32
33 enum {
34         POWERCAP_FC_CAP,
35         POWERCAP_FC_PAI,
36         POWERCAP_FC_MAX,
37 };
38
39 struct scmi_msg_resp_powercap_domain_attributes {
40         __le32 attributes;
41 #define SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(x)          ((x) & BIT(31))
42 #define SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(x) ((x) & BIT(30))
43 #define SUPPORTS_ASYNC_POWERCAP_CAP_SET(x)              ((x) & BIT(29))
44 #define SUPPORTS_EXTENDED_NAMES(x)                      ((x) & BIT(28))
45 #define SUPPORTS_POWERCAP_CAP_CONFIGURATION(x)          ((x) & BIT(27))
46 #define SUPPORTS_POWERCAP_MONITORING(x)                 ((x) & BIT(26))
47 #define SUPPORTS_POWERCAP_PAI_CONFIGURATION(x)          ((x) & BIT(25))
48 #define SUPPORTS_POWERCAP_FASTCHANNELS(x)               ((x) & BIT(22))
49 #define POWERCAP_POWER_UNIT(x)                          \
50                 (FIELD_GET(GENMASK(24, 23), (x)))
51 #define SUPPORTS_POWER_UNITS_MW(x)                      \
52                 (POWERCAP_POWER_UNIT(x) == 0x2)
53 #define SUPPORTS_POWER_UNITS_UW(x)                      \
54                 (POWERCAP_POWER_UNIT(x) == 0x1)
55         u8 name[SCMI_SHORT_NAME_MAX_SIZE];
56         __le32 min_pai;
57         __le32 max_pai;
58         __le32 pai_step;
59         __le32 min_power_cap;
60         __le32 max_power_cap;
61         __le32 power_cap_step;
62         __le32 sustainable_power;
63         __le32 accuracy;
64         __le32 parent_id;
65 };
66
67 struct scmi_msg_powercap_set_cap_or_pai {
68         __le32 domain;
69         __le32 flags;
70 #define CAP_SET_ASYNC           BIT(1)
71 #define CAP_SET_IGNORE_DRESP    BIT(0)
72         __le32 value;
73 };
74
75 struct scmi_msg_resp_powercap_cap_set_complete {
76         __le32 domain;
77         __le32 power_cap;
78 };
79
80 struct scmi_msg_resp_powercap_meas_get {
81         __le32 power;
82         __le32 pai;
83 };
84
85 struct scmi_msg_powercap_notify_cap {
86         __le32 domain;
87         __le32 notify_enable;
88 };
89
90 struct scmi_msg_powercap_notify_thresh {
91         __le32 domain;
92         __le32 notify_enable;
93         __le32 power_thresh_low;
94         __le32 power_thresh_high;
95 };
96
97 struct scmi_powercap_cap_changed_notify_payld {
98         __le32 agent_id;
99         __le32 domain_id;
100         __le32 power_cap;
101         __le32 pai;
102 };
103
104 struct scmi_powercap_meas_changed_notify_payld {
105         __le32 agent_id;
106         __le32 domain_id;
107         __le32 power;
108 };
109
110 struct scmi_powercap_state {
111         bool meas_notif_enabled;
112         u64 thresholds;
113 #define THRESH_LOW(p, id)                               \
114         (lower_32_bits((p)->states[(id)].thresholds))
115 #define THRESH_HIGH(p, id)                              \
116         (upper_32_bits((p)->states[(id)].thresholds))
117 };
118
119 struct powercap_info {
120         u32 version;
121         int num_domains;
122         struct scmi_powercap_state *states;
123         struct scmi_powercap_info *powercaps;
124 };
125
126 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
127         POWERCAP_CAP_NOTIFY,
128         POWERCAP_MEASUREMENTS_NOTIFY,
129 };
130
131 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
132                                 u32 domain, int message_id, bool enable);
133
134 static int
135 scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
136                              struct powercap_info *pi)
137 {
138         int ret;
139         struct scmi_xfer *t;
140
141         ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
142                                       sizeof(u32), &t);
143         if (ret)
144                 return ret;
145
146         ret = ph->xops->do_xfer(ph, t);
147         if (!ret) {
148                 u32 attributes;
149
150                 attributes = get_unaligned_le32(t->rx.buf);
151                 pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
152         }
153
154         ph->xops->xfer_put(ph, t);
155         return ret;
156 }
157
158 static inline int
159 scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
160                        unsigned int step_val, bool configurable)
161 {
162         if (!min_val || !max_val)
163                 return -EPROTO;
164
165         if ((configurable && min_val == max_val) ||
166             (!configurable && min_val != max_val))
167                 return -EPROTO;
168
169         if (min_val != max_val && !step_val)
170                 return -EPROTO;
171
172         return 0;
173 }
174
175 static int
176 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
177                                     struct powercap_info *pinfo, u32 domain)
178 {
179         int ret;
180         u32 flags;
181         struct scmi_xfer *t;
182         struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
183         struct scmi_msg_resp_powercap_domain_attributes *resp;
184
185         ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
186                                       sizeof(domain), sizeof(*resp), &t);
187         if (ret)
188                 return ret;
189
190         put_unaligned_le32(domain, t->tx.buf);
191         resp = t->rx.buf;
192
193         ret = ph->xops->do_xfer(ph, t);
194         if (!ret) {
195                 flags = le32_to_cpu(resp->attributes);
196
197                 dom_info->id = domain;
198                 dom_info->notify_powercap_cap_change =
199                         SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
200                 dom_info->notify_powercap_measurement_change =
201                         SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
202                 dom_info->async_powercap_cap_set =
203                         SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
204                 dom_info->powercap_cap_config =
205                         SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
206                 dom_info->powercap_monitoring =
207                         SUPPORTS_POWERCAP_MONITORING(flags);
208                 dom_info->powercap_pai_config =
209                         SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
210                 dom_info->powercap_scale_mw =
211                         SUPPORTS_POWER_UNITS_MW(flags);
212                 dom_info->powercap_scale_uw =
213                         SUPPORTS_POWER_UNITS_UW(flags);
214                 dom_info->fastchannels =
215                         SUPPORTS_POWERCAP_FASTCHANNELS(flags);
216
217                 strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
218
219                 dom_info->min_pai = le32_to_cpu(resp->min_pai);
220                 dom_info->max_pai = le32_to_cpu(resp->max_pai);
221                 dom_info->pai_step = le32_to_cpu(resp->pai_step);
222                 ret = scmi_powercap_validate(dom_info->min_pai,
223                                              dom_info->max_pai,
224                                              dom_info->pai_step,
225                                              dom_info->powercap_pai_config);
226                 if (ret) {
227                         dev_err(ph->dev,
228                                 "Platform reported inconsistent PAI config for domain %d - %s\n",
229                                 dom_info->id, dom_info->name);
230                         goto clean;
231                 }
232
233                 dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
234                 dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
235                 dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
236                 ret = scmi_powercap_validate(dom_info->min_power_cap,
237                                              dom_info->max_power_cap,
238                                              dom_info->power_cap_step,
239                                              dom_info->powercap_cap_config);
240                 if (ret) {
241                         dev_err(ph->dev,
242                                 "Platform reported inconsistent CAP config for domain %d - %s\n",
243                                 dom_info->id, dom_info->name);
244                         goto clean;
245                 }
246
247                 dom_info->sustainable_power =
248                         le32_to_cpu(resp->sustainable_power);
249                 dom_info->accuracy = le32_to_cpu(resp->accuracy);
250
251                 dom_info->parent_id = le32_to_cpu(resp->parent_id);
252                 if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
253                     (dom_info->parent_id >= pinfo->num_domains ||
254                      dom_info->parent_id == dom_info->id)) {
255                         dev_err(ph->dev,
256                                 "Platform reported inconsistent parent ID for domain %d - %s\n",
257                                 dom_info->id, dom_info->name);
258                         ret = -ENODEV;
259                 }
260         }
261
262 clean:
263         ph->xops->xfer_put(ph, t);
264
265         /*
266          * If supported overwrite short name with the extended one;
267          * on error just carry on and use already provided short name.
268          */
269         if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
270                 ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
271                                             domain, dom_info->name,
272                                             SCMI_MAX_STR_SIZE);
273
274         return ret;
275 }
276
277 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
278 {
279         struct powercap_info *pi = ph->get_priv(ph);
280
281         return pi->num_domains;
282 }
283
284 static const struct scmi_powercap_info *
285 scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
286 {
287         struct powercap_info *pi = ph->get_priv(ph);
288
289         if (domain_id >= pi->num_domains)
290                 return NULL;
291
292         return pi->powercaps + domain_id;
293 }
294
295 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
296                                       u32 domain_id, u32 *power_cap)
297 {
298         int ret;
299         struct scmi_xfer *t;
300
301         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
302                                       sizeof(u32), &t);
303         if (ret)
304                 return ret;
305
306         put_unaligned_le32(domain_id, t->tx.buf);
307         ret = ph->xops->do_xfer(ph, t);
308         if (!ret)
309                 *power_cap = get_unaligned_le32(t->rx.buf);
310
311         ph->xops->xfer_put(ph, t);
312
313         return ret;
314 }
315
316 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
317                                  u32 domain_id, u32 *power_cap)
318 {
319         struct scmi_powercap_info *dom;
320         struct powercap_info *pi = ph->get_priv(ph);
321
322         if (!power_cap || domain_id >= pi->num_domains)
323                 return -EINVAL;
324
325         dom = pi->powercaps + domain_id;
326         if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
327                 *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
328                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
329                                    domain_id, *power_cap, 0);
330                 return 0;
331         }
332
333         return scmi_powercap_xfer_cap_get(ph, domain_id, power_cap);
334 }
335
336 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
337                                       const struct scmi_powercap_info *pc,
338                                       u32 power_cap, bool ignore_dresp)
339 {
340         int ret;
341         struct scmi_xfer *t;
342         struct scmi_msg_powercap_set_cap_or_pai *msg;
343
344         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
345                                       sizeof(*msg), 0, &t);
346         if (ret)
347                 return ret;
348
349         msg = t->tx.buf;
350         msg->domain = cpu_to_le32(pc->id);
351         msg->flags =
352                 cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, !!pc->async_powercap_cap_set) |
353                             FIELD_PREP(CAP_SET_IGNORE_DRESP, !!ignore_dresp));
354         msg->value = cpu_to_le32(power_cap);
355
356         if (!pc->async_powercap_cap_set || ignore_dresp) {
357                 ret = ph->xops->do_xfer(ph, t);
358         } else {
359                 ret = ph->xops->do_xfer_with_response(ph, t);
360                 if (!ret) {
361                         struct scmi_msg_resp_powercap_cap_set_complete *resp;
362
363                         resp = t->rx.buf;
364                         if (le32_to_cpu(resp->domain) == pc->id)
365                                 dev_dbg(ph->dev,
366                                         "Powercap ID %d CAP set async to %u\n",
367                                         pc->id,
368                                         get_unaligned_le32(&resp->power_cap));
369                         else
370                                 ret = -EPROTO;
371                 }
372         }
373
374         ph->xops->xfer_put(ph, t);
375         return ret;
376 }
377
378 static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
379                                  u32 domain_id, u32 power_cap,
380                                  bool ignore_dresp)
381 {
382         const struct scmi_powercap_info *pc;
383
384         pc = scmi_powercap_dom_info_get(ph, domain_id);
385         if (!pc || !pc->powercap_cap_config || !power_cap ||
386             power_cap < pc->min_power_cap ||
387             power_cap > pc->max_power_cap)
388                 return -EINVAL;
389
390         if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
391                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
392
393                 iowrite32(power_cap, fci->set_addr);
394                 ph->hops->fastchannel_db_ring(fci->set_db);
395                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
396                                    domain_id, power_cap, 0);
397                 return 0;
398         }
399
400         return scmi_powercap_xfer_cap_set(ph, pc, power_cap, ignore_dresp);
401 }
402
403 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
404                                       u32 domain_id, u32 *pai)
405 {
406         int ret;
407         struct scmi_xfer *t;
408
409         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
410                                       sizeof(u32), &t);
411         if (ret)
412                 return ret;
413
414         put_unaligned_le32(domain_id, t->tx.buf);
415         ret = ph->xops->do_xfer(ph, t);
416         if (!ret)
417                 *pai = get_unaligned_le32(t->rx.buf);
418
419         ph->xops->xfer_put(ph, t);
420
421         return ret;
422 }
423
424 static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
425                                  u32 domain_id, u32 *pai)
426 {
427         struct scmi_powercap_info *dom;
428         struct powercap_info *pi = ph->get_priv(ph);
429
430         if (!pai || domain_id >= pi->num_domains)
431                 return -EINVAL;
432
433         dom = pi->powercaps + domain_id;
434         if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
435                 *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
436                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
437                                    domain_id, *pai, 0);
438                 return 0;
439         }
440
441         return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
442 }
443
444 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
445                                       u32 domain_id, u32 pai)
446 {
447         int ret;
448         struct scmi_xfer *t;
449         struct scmi_msg_powercap_set_cap_or_pai *msg;
450
451         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
452                                       sizeof(*msg), 0, &t);
453         if (ret)
454                 return ret;
455
456         msg = t->tx.buf;
457         msg->domain = cpu_to_le32(domain_id);
458         msg->flags = cpu_to_le32(0);
459         msg->value = cpu_to_le32(pai);
460
461         ret = ph->xops->do_xfer(ph, t);
462
463         ph->xops->xfer_put(ph, t);
464         return ret;
465 }
466
467 static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
468                                  u32 domain_id, u32 pai)
469 {
470         const struct scmi_powercap_info *pc;
471
472         pc = scmi_powercap_dom_info_get(ph, domain_id);
473         if (!pc || !pc->powercap_pai_config || !pai ||
474             pai < pc->min_pai || pai > pc->max_pai)
475                 return -EINVAL;
476
477         if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
478                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
479
480                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
481                                    domain_id, pai, 0);
482                 iowrite32(pai, fci->set_addr);
483                 ph->hops->fastchannel_db_ring(fci->set_db);
484                 return 0;
485         }
486
487         return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
488 }
489
490 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
491                                           u32 domain_id, u32 *average_power,
492                                           u32 *pai)
493 {
494         int ret;
495         struct scmi_xfer *t;
496         struct scmi_msg_resp_powercap_meas_get *resp;
497         const struct scmi_powercap_info *pc;
498
499         pc = scmi_powercap_dom_info_get(ph, domain_id);
500         if (!pc || !pc->powercap_monitoring || !pai || !average_power)
501                 return -EINVAL;
502
503         ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
504                                       sizeof(u32), sizeof(*resp), &t);
505         if (ret)
506                 return ret;
507
508         resp = t->rx.buf;
509         put_unaligned_le32(domain_id, t->tx.buf);
510         ret = ph->xops->do_xfer(ph, t);
511         if (!ret) {
512                 *average_power = le32_to_cpu(resp->power);
513                 *pai = le32_to_cpu(resp->pai);
514         }
515
516         ph->xops->xfer_put(ph, t);
517         return ret;
518 }
519
520 static int
521 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
522                                          u32 domain_id, u32 *power_thresh_low,
523                                          u32 *power_thresh_high)
524 {
525         struct powercap_info *pi = ph->get_priv(ph);
526
527         if (!power_thresh_low || !power_thresh_high ||
528             domain_id >= pi->num_domains)
529                 return -EINVAL;
530
531         *power_thresh_low =  THRESH_LOW(pi, domain_id);
532         *power_thresh_high = THRESH_HIGH(pi, domain_id);
533
534         return 0;
535 }
536
537 static int
538 scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
539                                          u32 domain_id, u32 power_thresh_low,
540                                          u32 power_thresh_high)
541 {
542         int ret = 0;
543         struct powercap_info *pi = ph->get_priv(ph);
544
545         if (domain_id >= pi->num_domains ||
546             power_thresh_low > power_thresh_high)
547                 return -EINVAL;
548
549         /* Anything to do ? */
550         if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
551             THRESH_HIGH(pi, domain_id) == power_thresh_high)
552                 return ret;
553
554         pi->states[domain_id].thresholds =
555                 (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
556                  FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
557
558         /* Update thresholds if notification already enabled */
559         if (pi->states[domain_id].meas_notif_enabled)
560                 ret = scmi_powercap_notify(ph, domain_id,
561                                            POWERCAP_MEASUREMENTS_NOTIFY,
562                                            true);
563
564         return ret;
565 }
566
567 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
568         .num_domains_get = scmi_powercap_num_domains_get,
569         .info_get = scmi_powercap_dom_info_get,
570         .cap_get = scmi_powercap_cap_get,
571         .cap_set = scmi_powercap_cap_set,
572         .pai_get = scmi_powercap_pai_get,
573         .pai_set = scmi_powercap_pai_set,
574         .measurements_get = scmi_powercap_measurements_get,
575         .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
576         .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
577 };
578
579 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
580                                          u32 domain, struct scmi_fc_info **p_fc)
581 {
582         struct scmi_fc_info *fc;
583
584         fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
585         if (!fc)
586                 return;
587
588         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
589                                    POWERCAP_CAP_SET, 4, domain,
590                                    &fc[POWERCAP_FC_CAP].set_addr,
591                                    &fc[POWERCAP_FC_CAP].set_db);
592
593         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
594                                    POWERCAP_CAP_GET, 4, domain,
595                                    &fc[POWERCAP_FC_CAP].get_addr, NULL);
596
597         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
598                                    POWERCAP_PAI_SET, 4, domain,
599                                    &fc[POWERCAP_FC_PAI].set_addr,
600                                    &fc[POWERCAP_FC_PAI].set_db);
601
602         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
603                                    POWERCAP_PAI_GET, 4, domain,
604                                    &fc[POWERCAP_FC_PAI].get_addr, NULL);
605
606         *p_fc = fc;
607 }
608
609 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
610                                 u32 domain, int message_id, bool enable)
611 {
612         int ret;
613         struct scmi_xfer *t;
614
615         switch (message_id) {
616         case POWERCAP_CAP_NOTIFY:
617         {
618                 struct scmi_msg_powercap_notify_cap *notify;
619
620                 ret = ph->xops->xfer_get_init(ph, message_id,
621                                               sizeof(*notify), 0, &t);
622                 if (ret)
623                         return ret;
624
625                 notify = t->tx.buf;
626                 notify->domain = cpu_to_le32(domain);
627                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
628                 break;
629         }
630         case POWERCAP_MEASUREMENTS_NOTIFY:
631         {
632                 u32 low, high;
633                 struct scmi_msg_powercap_notify_thresh *notify;
634
635                 /*
636                  * Note that we have to pick the most recently configured
637                  * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
638                  * enable request and we fail, complaining, if no thresholds
639                  * were ever set, since this is an indication the API has been
640                  * used wrongly.
641                  */
642                 ret = scmi_powercap_measurements_threshold_get(ph, domain,
643                                                                &low, &high);
644                 if (ret)
645                         return ret;
646
647                 if (enable && !low && !high) {
648                         dev_err(ph->dev,
649                                 "Invalid Measurements Notify thresholds: %u/%u\n",
650                                 low, high);
651                         return -EINVAL;
652                 }
653
654                 ret = ph->xops->xfer_get_init(ph, message_id,
655                                               sizeof(*notify), 0, &t);
656                 if (ret)
657                         return ret;
658
659                 notify = t->tx.buf;
660                 notify->domain = cpu_to_le32(domain);
661                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
662                 notify->power_thresh_low = cpu_to_le32(low);
663                 notify->power_thresh_high = cpu_to_le32(high);
664                 break;
665         }
666         default:
667                 return -EINVAL;
668         }
669
670         ret = ph->xops->do_xfer(ph, t);
671
672         ph->xops->xfer_put(ph, t);
673         return ret;
674 }
675
676 static int
677 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
678                                  u8 evt_id, u32 src_id, bool enable)
679 {
680         int ret, cmd_id;
681         struct powercap_info *pi = ph->get_priv(ph);
682
683         if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
684                 return -EINVAL;
685
686         cmd_id = evt_2_cmd[evt_id];
687         ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
688         if (ret)
689                 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
690                          evt_id, src_id, ret);
691         else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
692                 /*
693                  * On success save the current notification enabled state, so
694                  * as to be able to properly update the notification thresholds
695                  * when they are modified on a domain for which measurement
696                  * notifications were currently enabled.
697                  *
698                  * This is needed because the SCMI Notification core machinery
699                  * and API does not support passing per-notification custom
700                  * arguments at callback registration time.
701                  *
702                  * Note that this can be done here with a simple flag since the
703                  * SCMI core Notifications code takes care of keeping proper
704                  * per-domain enables refcounting, so that this helper function
705                  * will be called only once (for enables) when the first user
706                  * registers a callback on this domain and once more (disable)
707                  * when the last user de-registers its callback.
708                  */
709                 pi->states[src_id].meas_notif_enabled = enable;
710
711         return ret;
712 }
713
714 static void *
715 scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
716                                  u8 evt_id, ktime_t timestamp,
717                                  const void *payld, size_t payld_sz,
718                                  void *report, u32 *src_id)
719 {
720         void *rep = NULL;
721
722         switch (evt_id) {
723         case SCMI_EVENT_POWERCAP_CAP_CHANGED:
724         {
725                 const struct scmi_powercap_cap_changed_notify_payld *p = payld;
726                 struct scmi_powercap_cap_changed_report *r = report;
727
728                 if (sizeof(*p) != payld_sz)
729                         break;
730
731                 r->timestamp = timestamp;
732                 r->agent_id = le32_to_cpu(p->agent_id);
733                 r->domain_id = le32_to_cpu(p->domain_id);
734                 r->power_cap = le32_to_cpu(p->power_cap);
735                 r->pai = le32_to_cpu(p->pai);
736                 *src_id = r->domain_id;
737                 rep = r;
738                 break;
739         }
740         case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
741         {
742                 const struct scmi_powercap_meas_changed_notify_payld *p = payld;
743                 struct scmi_powercap_meas_changed_report *r = report;
744
745                 if (sizeof(*p) != payld_sz)
746                         break;
747
748                 r->timestamp = timestamp;
749                 r->agent_id = le32_to_cpu(p->agent_id);
750                 r->domain_id = le32_to_cpu(p->domain_id);
751                 r->power = le32_to_cpu(p->power);
752                 *src_id = r->domain_id;
753                 rep = r;
754                 break;
755         }
756         default:
757                 break;
758         }
759
760         return rep;
761 }
762
763 static int
764 scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
765 {
766         struct powercap_info *pi = ph->get_priv(ph);
767
768         if (!pi)
769                 return -EINVAL;
770
771         return pi->num_domains;
772 }
773
774 static const struct scmi_event powercap_events[] = {
775         {
776                 .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
777                 .max_payld_sz =
778                         sizeof(struct scmi_powercap_cap_changed_notify_payld),
779                 .max_report_sz =
780                         sizeof(struct scmi_powercap_cap_changed_report),
781         },
782         {
783                 .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
784                 .max_payld_sz =
785                         sizeof(struct scmi_powercap_meas_changed_notify_payld),
786                 .max_report_sz =
787                         sizeof(struct scmi_powercap_meas_changed_report),
788         },
789 };
790
791 static const struct scmi_event_ops powercap_event_ops = {
792         .get_num_sources = scmi_powercap_get_num_sources,
793         .set_notify_enabled = scmi_powercap_set_notify_enabled,
794         .fill_custom_report = scmi_powercap_fill_custom_report,
795 };
796
797 static const struct scmi_protocol_events powercap_protocol_events = {
798         .queue_sz = SCMI_PROTO_QUEUE_SZ,
799         .ops = &powercap_event_ops,
800         .evts = powercap_events,
801         .num_events = ARRAY_SIZE(powercap_events),
802 };
803
804 static int
805 scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
806 {
807         int domain, ret;
808         u32 version;
809         struct powercap_info *pinfo;
810
811         ret = ph->xops->version_get(ph, &version);
812         if (ret)
813                 return ret;
814
815         dev_dbg(ph->dev, "Powercap Version %d.%d\n",
816                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
817
818         pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
819         if (!pinfo)
820                 return -ENOMEM;
821
822         ret = scmi_powercap_attributes_get(ph, pinfo);
823         if (ret)
824                 return ret;
825
826         pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
827                                         sizeof(*pinfo->powercaps),
828                                         GFP_KERNEL);
829         if (!pinfo->powercaps)
830                 return -ENOMEM;
831
832         /*
833          * Note that any failure in retrieving any domain attribute leads to
834          * the whole Powercap protocol initialization failure: this way the
835          * reported Powercap domains are all assured, when accessed, to be well
836          * formed and correlated by sane parent-child relationship (if any).
837          */
838         for (domain = 0; domain < pinfo->num_domains; domain++) {
839                 ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
840                 if (ret)
841                         return ret;
842
843                 if (pinfo->powercaps[domain].fastchannels)
844                         scmi_powercap_domain_init_fc(ph, domain,
845                                                      &pinfo->powercaps[domain].fc_info);
846         }
847
848         pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
849                                      sizeof(*pinfo->states), GFP_KERNEL);
850         if (!pinfo->states)
851                 return -ENOMEM;
852
853         pinfo->version = version;
854
855         return ph->set_priv(ph, pinfo);
856 }
857
858 static const struct scmi_protocol scmi_powercap = {
859         .id = SCMI_PROTOCOL_POWERCAP,
860         .owner = THIS_MODULE,
861         .instance_init = &scmi_powercap_protocol_init,
862         .ops = &powercap_proto_ops,
863         .events = &powercap_protocol_events,
864 };
865
866 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)