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
23enum 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
36enum {
37	POWERCAP_FC_CAP,
38	POWERCAP_FC_PAI,
39	POWERCAP_FC_MAX,
40};
41
42struct 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
70struct 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
78struct scmi_msg_resp_powercap_cap_set_complete {
79	__le32 domain;
80	__le32 power_cap;
81};
82
83struct scmi_msg_resp_powercap_meas_get {
84	__le32 power;
85	__le32 pai;
86};
87
88struct scmi_msg_powercap_notify_cap {
89	__le32 domain;
90	__le32 notify_enable;
91};
92
93struct scmi_msg_powercap_notify_thresh {
94	__le32 domain;
95	__le32 notify_enable;
96	__le32 power_thresh_low;
97	__le32 power_thresh_high;
98};
99
100struct scmi_powercap_cap_changed_notify_payld {
101	__le32 agent_id;
102	__le32 domain_id;
103	__le32 power_cap;
104	__le32 pai;
105};
106
107struct scmi_powercap_meas_changed_notify_payld {
108	__le32 agent_id;
109	__le32 domain_id;
110	__le32 power;
111};
112
113struct 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
124struct 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
133static enum scmi_powercap_protocol_cmd evt_2_cmd[] = {
134	POWERCAP_CAP_NOTIFY,
135	POWERCAP_MEASUREMENTS_NOTIFY,
136};
137
138static int scmi_powercap_notify(const struct scmi_protocol_handle *ph,
139				u32 domain, int message_id, bool enable);
140
141static int
142scmi_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
177static inline int
178scmi_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
194static int
195scmi_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
283clean:
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
298static 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
305static const struct scmi_powercap_info *
306scmi_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
316static 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
337static 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
351static 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
366static 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
408static 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
443static 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
467static 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
488static 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
508static 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
531static 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
554static 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
584static int
585scmi_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
601static int
602scmi_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
631static 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
671static 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
696static 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
710static 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_FC_PAI].rate_limit);
740
741	*p_fc = fc;
742}
743
744static 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
811static bool
812scmi_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
831static int
832scmi_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
869static void *
870scmi_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
918static int
919scmi_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
929static 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
946static 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
953static 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
960static int
961scmi_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
1025static 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
1034DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(powercap, scmi_powercap)
1035