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