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
20enum 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
33enum {
34	POWERCAP_FC_CAP,
35	POWERCAP_FC_PAI,
36	POWERCAP_FC_MAX,
37};
38
39struct 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
67struct 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
75struct scmi_msg_resp_powercap_cap_set_complete {
76	__le32 domain;
77	__le32 power_cap;
78};
79
80struct scmi_msg_resp_powercap_meas_get {
81	__le32 power;
82	__le32 pai;
83};
84
85struct scmi_msg_powercap_notify_cap {
86	__le32 domain;
87	__le32 notify_enable;
88};
89
90struct scmi_msg_powercap_notify_thresh {
91	__le32 domain;
92	__le32 notify_enable;
93	__le32 power_thresh_low;
94	__le32 power_thresh_high;
95};
96
97struct scmi_powercap_cap_changed_notify_payld {
98	__le32 agent_id;
99	__le32 domain_id;
100	__le32 power_cap;
101	__le32 pai;
102};
103
104struct scmi_powercap_meas_changed_notify_payld {
105	__le32 agent_id;
106	__le32 domain_id;
107	__le32 power;
108};
109
110struct 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
121struct powercap_info {
122	u32 version;
123	int num_domains;
124	struct scmi_powercap_state *states;
125	struct scmi_powercap_info *powercaps;
126};
127
128static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
129	POWERCAP_CAP_NOTIFY,
130	POWERCAP_MEASUREMENTS_NOTIFY,
131};
132
133static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
134				u32 domain, int message_id, bool enable);
135
136static int
137scmi_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
160static inline int
161scmi_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
177static int
178scmi_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
264clean:
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
279static 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
286static const struct scmi_powercap_info *
287scmi_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
297static 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
318static 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
332static 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
347static 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
389static 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
424static 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
448static 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
469static 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
489static 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
512static 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
535static 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
565static int
566scmi_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
582static int
583scmi_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
612static 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
652static 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
677static 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
691static 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
721static 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
788static int
789scmi_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
826static void *
827scmi_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
875static int
876scmi_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
886static 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
903static 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
909static 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
916static int
917scmi_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
981static 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
989DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
990