GNU Linux-libre 6.7.9-gnu
[releases.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 enabled;
112         u32 last_pcap;
113         bool meas_notif_enabled;
114         u64 thresholds;
115 #define THRESH_LOW(p, id)                               \
116         (lower_32_bits((p)->states[(id)].thresholds))
117 #define THRESH_HIGH(p, id)                              \
118         (upper_32_bits((p)->states[(id)].thresholds))
119 };
120
121 struct powercap_info {
122         u32 version;
123         int num_domains;
124         struct scmi_powercap_state *states;
125         struct scmi_powercap_info *powercaps;
126 };
127
128 static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
129         POWERCAP_CAP_NOTIFY,
130         POWERCAP_MEASUREMENTS_NOTIFY,
131 };
132
133 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
134                                 u32 domain, int message_id, bool enable);
135
136 static int
137 scmi_powercap_attributes_get(const struct scmi_protocol_handle *ph,
138                              struct powercap_info *pi)
139 {
140         int ret;
141         struct scmi_xfer *t;
142
143         ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES, 0,
144                                       sizeof(u32), &t);
145         if (ret)
146                 return ret;
147
148         ret = ph->xops->do_xfer(ph, t);
149         if (!ret) {
150                 u32 attributes;
151
152                 attributes = get_unaligned_le32(t->rx.buf);
153                 pi->num_domains = FIELD_GET(GENMASK(15, 0), attributes);
154         }
155
156         ph->xops->xfer_put(ph, t);
157         return ret;
158 }
159
160 static inline int
161 scmi_powercap_validate(unsigned int min_val, unsigned int max_val,
162                        unsigned int step_val, bool configurable)
163 {
164         if (!min_val || !max_val)
165                 return -EPROTO;
166
167         if ((configurable && min_val == max_val) ||
168             (!configurable && min_val != max_val))
169                 return -EPROTO;
170
171         if (min_val != max_val && !step_val)
172                 return -EPROTO;
173
174         return 0;
175 }
176
177 static int
178 scmi_powercap_domain_attributes_get(const struct scmi_protocol_handle *ph,
179                                     struct powercap_info *pinfo, u32 domain)
180 {
181         int ret;
182         u32 flags;
183         struct scmi_xfer *t;
184         struct scmi_powercap_info *dom_info = pinfo->powercaps + domain;
185         struct scmi_msg_resp_powercap_domain_attributes *resp;
186
187         ret = ph->xops->xfer_get_init(ph, POWERCAP_DOMAIN_ATTRIBUTES,
188                                       sizeof(domain), sizeof(*resp), &t);
189         if (ret)
190                 return ret;
191
192         put_unaligned_le32(domain, t->tx.buf);
193         resp = t->rx.buf;
194
195         ret = ph->xops->do_xfer(ph, t);
196         if (!ret) {
197                 flags = le32_to_cpu(resp->attributes);
198
199                 dom_info->id = domain;
200                 dom_info->notify_powercap_cap_change =
201                         SUPPORTS_POWERCAP_CAP_CHANGE_NOTIFY(flags);
202                 dom_info->notify_powercap_measurement_change =
203                         SUPPORTS_POWERCAP_MEASUREMENTS_CHANGE_NOTIFY(flags);
204                 dom_info->async_powercap_cap_set =
205                         SUPPORTS_ASYNC_POWERCAP_CAP_SET(flags);
206                 dom_info->powercap_cap_config =
207                         SUPPORTS_POWERCAP_CAP_CONFIGURATION(flags);
208                 dom_info->powercap_monitoring =
209                         SUPPORTS_POWERCAP_MONITORING(flags);
210                 dom_info->powercap_pai_config =
211                         SUPPORTS_POWERCAP_PAI_CONFIGURATION(flags);
212                 dom_info->powercap_scale_mw =
213                         SUPPORTS_POWER_UNITS_MW(flags);
214                 dom_info->powercap_scale_uw =
215                         SUPPORTS_POWER_UNITS_UW(flags);
216                 dom_info->fastchannels =
217                         SUPPORTS_POWERCAP_FASTCHANNELS(flags);
218
219                 strscpy(dom_info->name, resp->name, SCMI_SHORT_NAME_MAX_SIZE);
220
221                 dom_info->min_pai = le32_to_cpu(resp->min_pai);
222                 dom_info->max_pai = le32_to_cpu(resp->max_pai);
223                 dom_info->pai_step = le32_to_cpu(resp->pai_step);
224                 ret = scmi_powercap_validate(dom_info->min_pai,
225                                              dom_info->max_pai,
226                                              dom_info->pai_step,
227                                              dom_info->powercap_pai_config);
228                 if (ret) {
229                         dev_err(ph->dev,
230                                 "Platform reported inconsistent PAI config for domain %d - %s\n",
231                                 dom_info->id, dom_info->name);
232                         goto clean;
233                 }
234
235                 dom_info->min_power_cap = le32_to_cpu(resp->min_power_cap);
236                 dom_info->max_power_cap = le32_to_cpu(resp->max_power_cap);
237                 dom_info->power_cap_step = le32_to_cpu(resp->power_cap_step);
238                 ret = scmi_powercap_validate(dom_info->min_power_cap,
239                                              dom_info->max_power_cap,
240                                              dom_info->power_cap_step,
241                                              dom_info->powercap_cap_config);
242                 if (ret) {
243                         dev_err(ph->dev,
244                                 "Platform reported inconsistent CAP config for domain %d - %s\n",
245                                 dom_info->id, dom_info->name);
246                         goto clean;
247                 }
248
249                 dom_info->sustainable_power =
250                         le32_to_cpu(resp->sustainable_power);
251                 dom_info->accuracy = le32_to_cpu(resp->accuracy);
252
253                 dom_info->parent_id = le32_to_cpu(resp->parent_id);
254                 if (dom_info->parent_id != SCMI_POWERCAP_ROOT_ZONE_ID &&
255                     (dom_info->parent_id >= pinfo->num_domains ||
256                      dom_info->parent_id == dom_info->id)) {
257                         dev_err(ph->dev,
258                                 "Platform reported inconsistent parent ID for domain %d - %s\n",
259                                 dom_info->id, dom_info->name);
260                         ret = -ENODEV;
261                 }
262         }
263
264 clean:
265         ph->xops->xfer_put(ph, t);
266
267         /*
268          * If supported overwrite short name with the extended one;
269          * on error just carry on and use already provided short name.
270          */
271         if (!ret && SUPPORTS_EXTENDED_NAMES(flags))
272                 ph->hops->extended_name_get(ph, POWERCAP_DOMAIN_NAME_GET,
273                                             domain, dom_info->name,
274                                             SCMI_MAX_STR_SIZE);
275
276         return ret;
277 }
278
279 static int scmi_powercap_num_domains_get(const struct scmi_protocol_handle *ph)
280 {
281         struct powercap_info *pi = ph->get_priv(ph);
282
283         return pi->num_domains;
284 }
285
286 static const struct scmi_powercap_info *
287 scmi_powercap_dom_info_get(const struct scmi_protocol_handle *ph, u32 domain_id)
288 {
289         struct powercap_info *pi = ph->get_priv(ph);
290
291         if (domain_id >= pi->num_domains)
292                 return NULL;
293
294         return pi->powercaps + domain_id;
295 }
296
297 static int scmi_powercap_xfer_cap_get(const struct scmi_protocol_handle *ph,
298                                       u32 domain_id, u32 *power_cap)
299 {
300         int ret;
301         struct scmi_xfer *t;
302
303         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_GET, sizeof(u32),
304                                       sizeof(u32), &t);
305         if (ret)
306                 return ret;
307
308         put_unaligned_le32(domain_id, t->tx.buf);
309         ret = ph->xops->do_xfer(ph, t);
310         if (!ret)
311                 *power_cap = get_unaligned_le32(t->rx.buf);
312
313         ph->xops->xfer_put(ph, t);
314
315         return ret;
316 }
317
318 static int __scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
319                                    const struct scmi_powercap_info *dom,
320                                    u32 *power_cap)
321 {
322         if (dom->fc_info && dom->fc_info[POWERCAP_FC_CAP].get_addr) {
323                 *power_cap = ioread32(dom->fc_info[POWERCAP_FC_CAP].get_addr);
324                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_GET,
325                                    dom->id, *power_cap, 0);
326                 return 0;
327         }
328
329         return scmi_powercap_xfer_cap_get(ph, dom->id, power_cap);
330 }
331
332 static int scmi_powercap_cap_get(const struct scmi_protocol_handle *ph,
333                                  u32 domain_id, u32 *power_cap)
334 {
335         const struct scmi_powercap_info *dom;
336
337         if (!power_cap)
338                 return -EINVAL;
339
340         dom = scmi_powercap_dom_info_get(ph, domain_id);
341         if (!dom)
342                 return -EINVAL;
343
344         return __scmi_powercap_cap_get(ph, dom, power_cap);
345 }
346
347 static int scmi_powercap_xfer_cap_set(const struct scmi_protocol_handle *ph,
348                                       const struct scmi_powercap_info *pc,
349                                       u32 power_cap, bool ignore_dresp)
350 {
351         int ret;
352         struct scmi_xfer *t;
353         struct scmi_msg_powercap_set_cap_or_pai *msg;
354
355         ret = ph->xops->xfer_get_init(ph, POWERCAP_CAP_SET,
356                                       sizeof(*msg), 0, &t);
357         if (ret)
358                 return ret;
359
360         msg = t->tx.buf;
361         msg->domain = cpu_to_le32(pc->id);
362         msg->flags =
363                 cpu_to_le32(FIELD_PREP(CAP_SET_ASYNC, pc->async_powercap_cap_set) |
364                             FIELD_PREP(CAP_SET_IGNORE_DRESP, ignore_dresp));
365         msg->value = cpu_to_le32(power_cap);
366
367         if (!pc->async_powercap_cap_set || ignore_dresp) {
368                 ret = ph->xops->do_xfer(ph, t);
369         } else {
370                 ret = ph->xops->do_xfer_with_response(ph, t);
371                 if (!ret) {
372                         struct scmi_msg_resp_powercap_cap_set_complete *resp;
373
374                         resp = t->rx.buf;
375                         if (le32_to_cpu(resp->domain) == pc->id)
376                                 dev_dbg(ph->dev,
377                                         "Powercap ID %d CAP set async to %u\n",
378                                         pc->id,
379                                         get_unaligned_le32(&resp->power_cap));
380                         else
381                                 ret = -EPROTO;
382                 }
383         }
384
385         ph->xops->xfer_put(ph, t);
386         return ret;
387 }
388
389 static int __scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
390                                    struct powercap_info *pi, u32 domain_id,
391                                    u32 power_cap, bool ignore_dresp)
392 {
393         int ret = -EINVAL;
394         const struct scmi_powercap_info *pc;
395
396         pc = scmi_powercap_dom_info_get(ph, domain_id);
397         if (!pc || !pc->powercap_cap_config)
398                 return ret;
399
400         if (power_cap &&
401             (power_cap < pc->min_power_cap || power_cap > pc->max_power_cap))
402                 return ret;
403
404         if (pc->fc_info && pc->fc_info[POWERCAP_FC_CAP].set_addr) {
405                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_CAP];
406
407                 iowrite32(power_cap, fci->set_addr);
408                 ph->hops->fastchannel_db_ring(fci->set_db);
409                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_CAP_SET,
410                                    domain_id, power_cap, 0);
411                 ret = 0;
412         } else {
413                 ret = scmi_powercap_xfer_cap_set(ph, pc, power_cap,
414                                                  ignore_dresp);
415         }
416
417         /* Save the last explicitly set non-zero powercap value */
418         if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 && !ret && power_cap)
419                 pi->states[domain_id].last_pcap = power_cap;
420
421         return ret;
422 }
423
424 static int scmi_powercap_cap_set(const struct scmi_protocol_handle *ph,
425                                  u32 domain_id, u32 power_cap,
426                                  bool ignore_dresp)
427 {
428         struct powercap_info *pi = ph->get_priv(ph);
429
430         /*
431          * Disallow zero as a possible explicitly requested powercap:
432          * there are enable/disable operations for this.
433          */
434         if (!power_cap)
435                 return -EINVAL;
436
437         /* Just log the last set request if acting on a disabled domain */
438         if (PROTOCOL_REV_MAJOR(pi->version) >= 0x2 &&
439             !pi->states[domain_id].enabled) {
440                 pi->states[domain_id].last_pcap = power_cap;
441                 return 0;
442         }
443
444         return __scmi_powercap_cap_set(ph, pi, domain_id,
445                                        power_cap, ignore_dresp);
446 }
447
448 static int scmi_powercap_xfer_pai_get(const struct scmi_protocol_handle *ph,
449                                       u32 domain_id, u32 *pai)
450 {
451         int ret;
452         struct scmi_xfer *t;
453
454         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_GET, sizeof(u32),
455                                       sizeof(u32), &t);
456         if (ret)
457                 return ret;
458
459         put_unaligned_le32(domain_id, t->tx.buf);
460         ret = ph->xops->do_xfer(ph, t);
461         if (!ret)
462                 *pai = get_unaligned_le32(t->rx.buf);
463
464         ph->xops->xfer_put(ph, t);
465
466         return ret;
467 }
468
469 static int scmi_powercap_pai_get(const struct scmi_protocol_handle *ph,
470                                  u32 domain_id, u32 *pai)
471 {
472         struct scmi_powercap_info *dom;
473         struct powercap_info *pi = ph->get_priv(ph);
474
475         if (!pai || domain_id >= pi->num_domains)
476                 return -EINVAL;
477
478         dom = pi->powercaps + domain_id;
479         if (dom->fc_info && dom->fc_info[POWERCAP_FC_PAI].get_addr) {
480                 *pai = ioread32(dom->fc_info[POWERCAP_FC_PAI].get_addr);
481                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_GET,
482                                    domain_id, *pai, 0);
483                 return 0;
484         }
485
486         return scmi_powercap_xfer_pai_get(ph, domain_id, pai);
487 }
488
489 static int scmi_powercap_xfer_pai_set(const struct scmi_protocol_handle *ph,
490                                       u32 domain_id, u32 pai)
491 {
492         int ret;
493         struct scmi_xfer *t;
494         struct scmi_msg_powercap_set_cap_or_pai *msg;
495
496         ret = ph->xops->xfer_get_init(ph, POWERCAP_PAI_SET,
497                                       sizeof(*msg), 0, &t);
498         if (ret)
499                 return ret;
500
501         msg = t->tx.buf;
502         msg->domain = cpu_to_le32(domain_id);
503         msg->flags = cpu_to_le32(0);
504         msg->value = cpu_to_le32(pai);
505
506         ret = ph->xops->do_xfer(ph, t);
507
508         ph->xops->xfer_put(ph, t);
509         return ret;
510 }
511
512 static int scmi_powercap_pai_set(const struct scmi_protocol_handle *ph,
513                                  u32 domain_id, u32 pai)
514 {
515         const struct scmi_powercap_info *pc;
516
517         pc = scmi_powercap_dom_info_get(ph, domain_id);
518         if (!pc || !pc->powercap_pai_config || !pai ||
519             pai < pc->min_pai || pai > pc->max_pai)
520                 return -EINVAL;
521
522         if (pc->fc_info && pc->fc_info[POWERCAP_FC_PAI].set_addr) {
523                 struct scmi_fc_info *fci = &pc->fc_info[POWERCAP_FC_PAI];
524
525                 trace_scmi_fc_call(SCMI_PROTOCOL_POWERCAP, POWERCAP_PAI_SET,
526                                    domain_id, pai, 0);
527                 iowrite32(pai, fci->set_addr);
528                 ph->hops->fastchannel_db_ring(fci->set_db);
529                 return 0;
530         }
531
532         return scmi_powercap_xfer_pai_set(ph, domain_id, pai);
533 }
534
535 static int scmi_powercap_measurements_get(const struct scmi_protocol_handle *ph,
536                                           u32 domain_id, u32 *average_power,
537                                           u32 *pai)
538 {
539         int ret;
540         struct scmi_xfer *t;
541         struct scmi_msg_resp_powercap_meas_get *resp;
542         const struct scmi_powercap_info *pc;
543
544         pc = scmi_powercap_dom_info_get(ph, domain_id);
545         if (!pc || !pc->powercap_monitoring || !pai || !average_power)
546                 return -EINVAL;
547
548         ret = ph->xops->xfer_get_init(ph, POWERCAP_MEASUREMENTS_GET,
549                                       sizeof(u32), sizeof(*resp), &t);
550         if (ret)
551                 return ret;
552
553         resp = t->rx.buf;
554         put_unaligned_le32(domain_id, t->tx.buf);
555         ret = ph->xops->do_xfer(ph, t);
556         if (!ret) {
557                 *average_power = le32_to_cpu(resp->power);
558                 *pai = le32_to_cpu(resp->pai);
559         }
560
561         ph->xops->xfer_put(ph, t);
562         return ret;
563 }
564
565 static int
566 scmi_powercap_measurements_threshold_get(const struct scmi_protocol_handle *ph,
567                                          u32 domain_id, u32 *power_thresh_low,
568                                          u32 *power_thresh_high)
569 {
570         struct powercap_info *pi = ph->get_priv(ph);
571
572         if (!power_thresh_low || !power_thresh_high ||
573             domain_id >= pi->num_domains)
574                 return -EINVAL;
575
576         *power_thresh_low =  THRESH_LOW(pi, domain_id);
577         *power_thresh_high = THRESH_HIGH(pi, domain_id);
578
579         return 0;
580 }
581
582 static int
583 scmi_powercap_measurements_threshold_set(const struct scmi_protocol_handle *ph,
584                                          u32 domain_id, u32 power_thresh_low,
585                                          u32 power_thresh_high)
586 {
587         int ret = 0;
588         struct powercap_info *pi = ph->get_priv(ph);
589
590         if (domain_id >= pi->num_domains ||
591             power_thresh_low > power_thresh_high)
592                 return -EINVAL;
593
594         /* Anything to do ? */
595         if (THRESH_LOW(pi, domain_id) == power_thresh_low &&
596             THRESH_HIGH(pi, domain_id) == power_thresh_high)
597                 return ret;
598
599         pi->states[domain_id].thresholds =
600                 (FIELD_PREP(GENMASK_ULL(31, 0), power_thresh_low) |
601                  FIELD_PREP(GENMASK_ULL(63, 32), power_thresh_high));
602
603         /* Update thresholds if notification already enabled */
604         if (pi->states[domain_id].meas_notif_enabled)
605                 ret = scmi_powercap_notify(ph, domain_id,
606                                            POWERCAP_MEASUREMENTS_NOTIFY,
607                                            true);
608
609         return ret;
610 }
611
612 static int scmi_powercap_cap_enable_set(const struct scmi_protocol_handle *ph,
613                                         u32 domain_id, bool enable)
614 {
615         int ret;
616         u32 power_cap;
617         struct powercap_info *pi = ph->get_priv(ph);
618
619         if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
620                 return -EINVAL;
621
622         if (enable == pi->states[domain_id].enabled)
623                 return 0;
624
625         if (enable) {
626                 /* Cannot enable with a zero powercap. */
627                 if (!pi->states[domain_id].last_pcap)
628                         return -EINVAL;
629
630                 ret = __scmi_powercap_cap_set(ph, pi, domain_id,
631                                               pi->states[domain_id].last_pcap,
632                                               true);
633         } else {
634                 ret = __scmi_powercap_cap_set(ph, pi, domain_id, 0, true);
635         }
636
637         if (ret)
638                 return ret;
639
640         /*
641          * Update our internal state to reflect final platform state: the SCMI
642          * server could have ignored a disable request and kept enforcing some
643          * powercap limit requested by other agents.
644          */
645         ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
646         if (!ret)
647                 pi->states[domain_id].enabled = !!power_cap;
648
649         return ret;
650 }
651
652 static int scmi_powercap_cap_enable_get(const struct scmi_protocol_handle *ph,
653                                         u32 domain_id, bool *enable)
654 {
655         int ret;
656         u32 power_cap;
657         struct powercap_info *pi = ph->get_priv(ph);
658
659         *enable = true;
660         if (PROTOCOL_REV_MAJOR(pi->version) < 0x2)
661                 return 0;
662
663         /*
664          * Report always real platform state; platform could have ignored
665          * a previous disable request. Default true on any error.
666          */
667         ret = scmi_powercap_cap_get(ph, domain_id, &power_cap);
668         if (!ret)
669                 *enable = !!power_cap;
670
671         /* Update internal state with current real platform state */
672         pi->states[domain_id].enabled = *enable;
673
674         return 0;
675 }
676
677 static const struct scmi_powercap_proto_ops powercap_proto_ops = {
678         .num_domains_get = scmi_powercap_num_domains_get,
679         .info_get = scmi_powercap_dom_info_get,
680         .cap_get = scmi_powercap_cap_get,
681         .cap_set = scmi_powercap_cap_set,
682         .cap_enable_set = scmi_powercap_cap_enable_set,
683         .cap_enable_get = scmi_powercap_cap_enable_get,
684         .pai_get = scmi_powercap_pai_get,
685         .pai_set = scmi_powercap_pai_set,
686         .measurements_get = scmi_powercap_measurements_get,
687         .measurements_threshold_set = scmi_powercap_measurements_threshold_set,
688         .measurements_threshold_get = scmi_powercap_measurements_threshold_get,
689 };
690
691 static void scmi_powercap_domain_init_fc(const struct scmi_protocol_handle *ph,
692                                          u32 domain, struct scmi_fc_info **p_fc)
693 {
694         struct scmi_fc_info *fc;
695
696         fc = devm_kcalloc(ph->dev, POWERCAP_FC_MAX, sizeof(*fc), GFP_KERNEL);
697         if (!fc)
698                 return;
699
700         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
701                                    POWERCAP_CAP_SET, 4, domain,
702                                    &fc[POWERCAP_FC_CAP].set_addr,
703                                    &fc[POWERCAP_FC_CAP].set_db);
704
705         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
706                                    POWERCAP_CAP_GET, 4, domain,
707                                    &fc[POWERCAP_FC_CAP].get_addr, NULL);
708
709         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
710                                    POWERCAP_PAI_SET, 4, domain,
711                                    &fc[POWERCAP_FC_PAI].set_addr,
712                                    &fc[POWERCAP_FC_PAI].set_db);
713
714         ph->hops->fastchannel_init(ph, POWERCAP_DESCRIBE_FASTCHANNEL,
715                                    POWERCAP_PAI_GET, 4, domain,
716                                    &fc[POWERCAP_FC_PAI].get_addr, NULL);
717
718         *p_fc = fc;
719 }
720
721 static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
722                                 u32 domain, int message_id, bool enable)
723 {
724         int ret;
725         struct scmi_xfer *t;
726
727         switch (message_id) {
728         case POWERCAP_CAP_NOTIFY:
729         {
730                 struct scmi_msg_powercap_notify_cap *notify;
731
732                 ret = ph->xops->xfer_get_init(ph, message_id,
733                                               sizeof(*notify), 0, &t);
734                 if (ret)
735                         return ret;
736
737                 notify = t->tx.buf;
738                 notify->domain = cpu_to_le32(domain);
739                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
740                 break;
741         }
742         case POWERCAP_MEASUREMENTS_NOTIFY:
743         {
744                 u32 low, high;
745                 struct scmi_msg_powercap_notify_thresh *notify;
746
747                 /*
748                  * Note that we have to pick the most recently configured
749                  * thresholds to build a proper POWERCAP_MEASUREMENTS_NOTIFY
750                  * enable request and we fail, complaining, if no thresholds
751                  * were ever set, since this is an indication the API has been
752                  * used wrongly.
753                  */
754                 ret = scmi_powercap_measurements_threshold_get(ph, domain,
755                                                                &low, &high);
756                 if (ret)
757                         return ret;
758
759                 if (enable && !low && !high) {
760                         dev_err(ph->dev,
761                                 "Invalid Measurements Notify thresholds: %u/%u\n",
762                                 low, high);
763                         return -EINVAL;
764                 }
765
766                 ret = ph->xops->xfer_get_init(ph, message_id,
767                                               sizeof(*notify), 0, &t);
768                 if (ret)
769                         return ret;
770
771                 notify = t->tx.buf;
772                 notify->domain = cpu_to_le32(domain);
773                 notify->notify_enable = cpu_to_le32(enable ? BIT(0) : 0);
774                 notify->power_thresh_low = cpu_to_le32(low);
775                 notify->power_thresh_high = cpu_to_le32(high);
776                 break;
777         }
778         default:
779                 return -EINVAL;
780         }
781
782         ret = ph->xops->do_xfer(ph, t);
783
784         ph->xops->xfer_put(ph, t);
785         return ret;
786 }
787
788 static int
789 scmi_powercap_set_notify_enabled(const struct scmi_protocol_handle *ph,
790                                  u8 evt_id, u32 src_id, bool enable)
791 {
792         int ret, cmd_id;
793         struct powercap_info *pi = ph->get_priv(ph);
794
795         if (evt_id >= ARRAY_SIZE(evt_2_cmd) || src_id >= pi->num_domains)
796                 return -EINVAL;
797
798         cmd_id = evt_2_cmd[evt_id];
799         ret = scmi_powercap_notify(ph, src_id, cmd_id, enable);
800         if (ret)
801                 pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",
802                          evt_id, src_id, ret);
803         else if (cmd_id == POWERCAP_MEASUREMENTS_NOTIFY)
804                 /*
805                  * On success save the current notification enabled state, so
806                  * as to be able to properly update the notification thresholds
807                  * when they are modified on a domain for which measurement
808                  * notifications were currently enabled.
809                  *
810                  * This is needed because the SCMI Notification core machinery
811                  * and API does not support passing per-notification custom
812                  * arguments at callback registration time.
813                  *
814                  * Note that this can be done here with a simple flag since the
815                  * SCMI core Notifications code takes care of keeping proper
816                  * per-domain enables refcounting, so that this helper function
817                  * will be called only once (for enables) when the first user
818                  * registers a callback on this domain and once more (disable)
819                  * when the last user de-registers its callback.
820                  */
821                 pi->states[src_id].meas_notif_enabled = enable;
822
823         return ret;
824 }
825
826 static void *
827 scmi_powercap_fill_custom_report(const struct scmi_protocol_handle *ph,
828                                  u8 evt_id, ktime_t timestamp,
829                                  const void *payld, size_t payld_sz,
830                                  void *report, u32 *src_id)
831 {
832         void *rep = NULL;
833
834         switch (evt_id) {
835         case SCMI_EVENT_POWERCAP_CAP_CHANGED:
836         {
837                 const struct scmi_powercap_cap_changed_notify_payld *p = payld;
838                 struct scmi_powercap_cap_changed_report *r = report;
839
840                 if (sizeof(*p) != payld_sz)
841                         break;
842
843                 r->timestamp = timestamp;
844                 r->agent_id = le32_to_cpu(p->agent_id);
845                 r->domain_id = le32_to_cpu(p->domain_id);
846                 r->power_cap = le32_to_cpu(p->power_cap);
847                 r->pai = le32_to_cpu(p->pai);
848                 *src_id = r->domain_id;
849                 rep = r;
850                 break;
851         }
852         case SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED:
853         {
854                 const struct scmi_powercap_meas_changed_notify_payld *p = payld;
855                 struct scmi_powercap_meas_changed_report *r = report;
856
857                 if (sizeof(*p) != payld_sz)
858                         break;
859
860                 r->timestamp = timestamp;
861                 r->agent_id = le32_to_cpu(p->agent_id);
862                 r->domain_id = le32_to_cpu(p->domain_id);
863                 r->power = le32_to_cpu(p->power);
864                 *src_id = r->domain_id;
865                 rep = r;
866                 break;
867         }
868         default:
869                 break;
870         }
871
872         return rep;
873 }
874
875 static int
876 scmi_powercap_get_num_sources(const struct scmi_protocol_handle *ph)
877 {
878         struct powercap_info *pi = ph->get_priv(ph);
879
880         if (!pi)
881                 return -EINVAL;
882
883         return pi->num_domains;
884 }
885
886 static const struct scmi_event powercap_events[] = {
887         {
888                 .id = SCMI_EVENT_POWERCAP_CAP_CHANGED,
889                 .max_payld_sz =
890                         sizeof(struct scmi_powercap_cap_changed_notify_payld),
891                 .max_report_sz =
892                         sizeof(struct scmi_powercap_cap_changed_report),
893         },
894         {
895                 .id = SCMI_EVENT_POWERCAP_MEASUREMENTS_CHANGED,
896                 .max_payld_sz =
897                         sizeof(struct scmi_powercap_meas_changed_notify_payld),
898                 .max_report_sz =
899                         sizeof(struct scmi_powercap_meas_changed_report),
900         },
901 };
902
903 static const struct scmi_event_ops powercap_event_ops = {
904         .get_num_sources = scmi_powercap_get_num_sources,
905         .set_notify_enabled = scmi_powercap_set_notify_enabled,
906         .fill_custom_report = scmi_powercap_fill_custom_report,
907 };
908
909 static const struct scmi_protocol_events powercap_protocol_events = {
910         .queue_sz = SCMI_PROTO_QUEUE_SZ,
911         .ops = &powercap_event_ops,
912         .evts = powercap_events,
913         .num_events = ARRAY_SIZE(powercap_events),
914 };
915
916 static int
917 scmi_powercap_protocol_init(const struct scmi_protocol_handle *ph)
918 {
919         int domain, ret;
920         u32 version;
921         struct powercap_info *pinfo;
922
923         ret = ph->xops->version_get(ph, &version);
924         if (ret)
925                 return ret;
926
927         dev_dbg(ph->dev, "Powercap Version %d.%d\n",
928                 PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
929
930         pinfo = devm_kzalloc(ph->dev, sizeof(*pinfo), GFP_KERNEL);
931         if (!pinfo)
932                 return -ENOMEM;
933
934         ret = scmi_powercap_attributes_get(ph, pinfo);
935         if (ret)
936                 return ret;
937
938         pinfo->powercaps = devm_kcalloc(ph->dev, pinfo->num_domains,
939                                         sizeof(*pinfo->powercaps),
940                                         GFP_KERNEL);
941         if (!pinfo->powercaps)
942                 return -ENOMEM;
943
944         pinfo->states = devm_kcalloc(ph->dev, pinfo->num_domains,
945                                      sizeof(*pinfo->states), GFP_KERNEL);
946         if (!pinfo->states)
947                 return -ENOMEM;
948
949         /*
950          * Note that any failure in retrieving any domain attribute leads to
951          * the whole Powercap protocol initialization failure: this way the
952          * reported Powercap domains are all assured, when accessed, to be well
953          * formed and correlated by sane parent-child relationship (if any).
954          */
955         for (domain = 0; domain < pinfo->num_domains; domain++) {
956                 ret = scmi_powercap_domain_attributes_get(ph, pinfo, domain);
957                 if (ret)
958                         return ret;
959
960                 if (pinfo->powercaps[domain].fastchannels)
961                         scmi_powercap_domain_init_fc(ph, domain,
962                                                      &pinfo->powercaps[domain].fc_info);
963
964                 /* Grab initial state when disable is supported. */
965                 if (PROTOCOL_REV_MAJOR(version) >= 0x2) {
966                         ret = __scmi_powercap_cap_get(ph,
967                                                       &pinfo->powercaps[domain],
968                                                       &pinfo->states[domain].last_pcap);
969                         if (ret)
970                                 return ret;
971
972                         pinfo->states[domain].enabled =
973                                 !!pinfo->states[domain].last_pcap;
974                 }
975         }
976
977         pinfo->version = version;
978         return ph->set_priv(ph, pinfo);
979 }
980
981 static const struct scmi_protocol scmi_powercap = {
982         .id = SCMI_PROTOCOL_POWERCAP,
983         .owner = THIS_MODULE,
984         .instance_init = &scmi_powercap_protocol_init,
985         .ops = &powercap_proto_ops,
986         .events = &powercap_protocol_events,
987 };
988
989 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)