xref: /openbmc/linux/drivers/firmware/arm_scmi/perf.c (revision 045f77ba)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * System Control and Management Interface (SCMI) Performance Protocol
4  *
5  * Copyright (C) 2018 ARM Ltd.
6  */
7 
8 #include <linux/of.h>
9 #include <linux/platform_device.h>
10 #include <linux/pm_opp.h>
11 #include <linux/sort.h>
12 
13 #include "common.h"
14 
15 enum scmi_performance_protocol_cmd {
16 	PERF_DOMAIN_ATTRIBUTES = 0x3,
17 	PERF_DESCRIBE_LEVELS = 0x4,
18 	PERF_LIMITS_SET = 0x5,
19 	PERF_LIMITS_GET = 0x6,
20 	PERF_LEVEL_SET = 0x7,
21 	PERF_LEVEL_GET = 0x8,
22 	PERF_NOTIFY_LIMITS = 0x9,
23 	PERF_NOTIFY_LEVEL = 0xa,
24 };
25 
26 struct scmi_opp {
27 	u32 perf;
28 	u32 power;
29 	u32 trans_latency_us;
30 };
31 
32 struct scmi_msg_resp_perf_attributes {
33 	__le16 num_domains;
34 	__le16 flags;
35 #define POWER_SCALE_IN_MILLIWATT(x)	((x) & BIT(0))
36 	__le32 stats_addr_low;
37 	__le32 stats_addr_high;
38 	__le32 stats_size;
39 };
40 
41 struct scmi_msg_resp_perf_domain_attributes {
42 	__le32 flags;
43 #define SUPPORTS_SET_LIMITS(x)		((x) & BIT(31))
44 #define SUPPORTS_SET_PERF_LVL(x)	((x) & BIT(30))
45 #define SUPPORTS_PERF_LIMIT_NOTIFY(x)	((x) & BIT(29))
46 #define SUPPORTS_PERF_LEVEL_NOTIFY(x)	((x) & BIT(28))
47 	__le32 rate_limit_us;
48 	__le32 sustained_freq_khz;
49 	__le32 sustained_perf_level;
50 	    u8 name[SCMI_MAX_STR_SIZE];
51 };
52 
53 struct scmi_msg_perf_describe_levels {
54 	__le32 domain;
55 	__le32 level_index;
56 };
57 
58 struct scmi_perf_set_limits {
59 	__le32 domain;
60 	__le32 max_level;
61 	__le32 min_level;
62 };
63 
64 struct scmi_perf_get_limits {
65 	__le32 max_level;
66 	__le32 min_level;
67 };
68 
69 struct scmi_perf_set_level {
70 	__le32 domain;
71 	__le32 level;
72 };
73 
74 struct scmi_perf_notify_level_or_limits {
75 	__le32 domain;
76 	__le32 notify_enable;
77 };
78 
79 struct scmi_msg_resp_perf_describe_levels {
80 	__le16 num_returned;
81 	__le16 num_remaining;
82 	struct {
83 		__le32 perf_val;
84 		__le32 power;
85 		__le16 transition_latency_us;
86 		__le16 reserved;
87 	} opp[0];
88 };
89 
90 struct perf_dom_info {
91 	bool set_limits;
92 	bool set_perf;
93 	bool perf_limit_notify;
94 	bool perf_level_notify;
95 	u32 opp_count;
96 	u32 sustained_freq_khz;
97 	u32 sustained_perf_level;
98 	u32 mult_factor;
99 	char name[SCMI_MAX_STR_SIZE];
100 	struct scmi_opp opp[MAX_OPPS];
101 };
102 
103 struct scmi_perf_info {
104 	int num_domains;
105 	bool power_scale_mw;
106 	u64 stats_addr;
107 	u32 stats_size;
108 	struct perf_dom_info *dom_info;
109 };
110 
111 static int scmi_perf_attributes_get(const struct scmi_handle *handle,
112 				    struct scmi_perf_info *pi)
113 {
114 	int ret;
115 	struct scmi_xfer *t;
116 	struct scmi_msg_resp_perf_attributes *attr;
117 
118 	ret = scmi_xfer_get_init(handle, PROTOCOL_ATTRIBUTES,
119 				 SCMI_PROTOCOL_PERF, 0, sizeof(*attr), &t);
120 	if (ret)
121 		return ret;
122 
123 	attr = t->rx.buf;
124 
125 	ret = scmi_do_xfer(handle, t);
126 	if (!ret) {
127 		u16 flags = le16_to_cpu(attr->flags);
128 
129 		pi->num_domains = le16_to_cpu(attr->num_domains);
130 		pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
131 		pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
132 				(u64)le32_to_cpu(attr->stats_addr_high) << 32;
133 		pi->stats_size = le32_to_cpu(attr->stats_size);
134 	}
135 
136 	scmi_xfer_put(handle, t);
137 	return ret;
138 }
139 
140 static int
141 scmi_perf_domain_attributes_get(const struct scmi_handle *handle, u32 domain,
142 				struct perf_dom_info *dom_info)
143 {
144 	int ret;
145 	struct scmi_xfer *t;
146 	struct scmi_msg_resp_perf_domain_attributes *attr;
147 
148 	ret = scmi_xfer_get_init(handle, PERF_DOMAIN_ATTRIBUTES,
149 				 SCMI_PROTOCOL_PERF, sizeof(domain),
150 				 sizeof(*attr), &t);
151 	if (ret)
152 		return ret;
153 
154 	*(__le32 *)t->tx.buf = cpu_to_le32(domain);
155 	attr = t->rx.buf;
156 
157 	ret = scmi_do_xfer(handle, t);
158 	if (!ret) {
159 		u32 flags = le32_to_cpu(attr->flags);
160 
161 		dom_info->set_limits = SUPPORTS_SET_LIMITS(flags);
162 		dom_info->set_perf = SUPPORTS_SET_PERF_LVL(flags);
163 		dom_info->perf_limit_notify = SUPPORTS_PERF_LIMIT_NOTIFY(flags);
164 		dom_info->perf_level_notify = SUPPORTS_PERF_LEVEL_NOTIFY(flags);
165 		dom_info->sustained_freq_khz =
166 					le32_to_cpu(attr->sustained_freq_khz);
167 		dom_info->sustained_perf_level =
168 					le32_to_cpu(attr->sustained_perf_level);
169 		dom_info->mult_factor =	(dom_info->sustained_freq_khz * 1000) /
170 					dom_info->sustained_perf_level;
171 		memcpy(dom_info->name, attr->name, SCMI_MAX_STR_SIZE);
172 	}
173 
174 	scmi_xfer_put(handle, t);
175 	return ret;
176 }
177 
178 static int opp_cmp_func(const void *opp1, const void *opp2)
179 {
180 	const struct scmi_opp *t1 = opp1, *t2 = opp2;
181 
182 	return t1->perf - t2->perf;
183 }
184 
185 static int
186 scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain,
187 			      struct perf_dom_info *perf_dom)
188 {
189 	int ret, cnt;
190 	u32 tot_opp_cnt = 0;
191 	u16 num_returned, num_remaining;
192 	struct scmi_xfer *t;
193 	struct scmi_opp *opp;
194 	struct scmi_msg_perf_describe_levels *dom_info;
195 	struct scmi_msg_resp_perf_describe_levels *level_info;
196 
197 	ret = scmi_xfer_get_init(handle, PERF_DESCRIBE_LEVELS,
198 				 SCMI_PROTOCOL_PERF, sizeof(*dom_info), 0, &t);
199 	if (ret)
200 		return ret;
201 
202 	dom_info = t->tx.buf;
203 	level_info = t->rx.buf;
204 
205 	do {
206 		dom_info->domain = cpu_to_le32(domain);
207 		/* Set the number of OPPs to be skipped/already read */
208 		dom_info->level_index = cpu_to_le32(tot_opp_cnt);
209 
210 		ret = scmi_do_xfer(handle, t);
211 		if (ret)
212 			break;
213 
214 		num_returned = le16_to_cpu(level_info->num_returned);
215 		num_remaining = le16_to_cpu(level_info->num_remaining);
216 		if (tot_opp_cnt + num_returned > MAX_OPPS) {
217 			dev_err(handle->dev, "No. of OPPs exceeded MAX_OPPS");
218 			break;
219 		}
220 
221 		opp = &perf_dom->opp[tot_opp_cnt];
222 		for (cnt = 0; cnt < num_returned; cnt++, opp++) {
223 			opp->perf = le32_to_cpu(level_info->opp[cnt].perf_val);
224 			opp->power = le32_to_cpu(level_info->opp[cnt].power);
225 			opp->trans_latency_us = le16_to_cpu
226 				(level_info->opp[cnt].transition_latency_us);
227 
228 			dev_dbg(handle->dev, "Level %d Power %d Latency %dus\n",
229 				opp->perf, opp->power, opp->trans_latency_us);
230 		}
231 
232 		tot_opp_cnt += num_returned;
233 		/*
234 		 * check for both returned and remaining to avoid infinite
235 		 * loop due to buggy firmware
236 		 */
237 	} while (num_returned && num_remaining);
238 
239 	perf_dom->opp_count = tot_opp_cnt;
240 	scmi_xfer_put(handle, t);
241 
242 	sort(perf_dom->opp, tot_opp_cnt, sizeof(*opp), opp_cmp_func, NULL);
243 	return ret;
244 }
245 
246 static int scmi_perf_limits_set(const struct scmi_handle *handle, u32 domain,
247 				u32 max_perf, u32 min_perf)
248 {
249 	int ret;
250 	struct scmi_xfer *t;
251 	struct scmi_perf_set_limits *limits;
252 
253 	ret = scmi_xfer_get_init(handle, PERF_LIMITS_SET, SCMI_PROTOCOL_PERF,
254 				 sizeof(*limits), 0, &t);
255 	if (ret)
256 		return ret;
257 
258 	limits = t->tx.buf;
259 	limits->domain = cpu_to_le32(domain);
260 	limits->max_level = cpu_to_le32(max_perf);
261 	limits->min_level = cpu_to_le32(min_perf);
262 
263 	ret = scmi_do_xfer(handle, t);
264 
265 	scmi_xfer_put(handle, t);
266 	return ret;
267 }
268 
269 static int scmi_perf_limits_get(const struct scmi_handle *handle, u32 domain,
270 				u32 *max_perf, u32 *min_perf)
271 {
272 	int ret;
273 	struct scmi_xfer *t;
274 	struct scmi_perf_get_limits *limits;
275 
276 	ret = scmi_xfer_get_init(handle, PERF_LIMITS_GET, SCMI_PROTOCOL_PERF,
277 				 sizeof(__le32), 0, &t);
278 	if (ret)
279 		return ret;
280 
281 	*(__le32 *)t->tx.buf = cpu_to_le32(domain);
282 
283 	ret = scmi_do_xfer(handle, t);
284 	if (!ret) {
285 		limits = t->rx.buf;
286 
287 		*max_perf = le32_to_cpu(limits->max_level);
288 		*min_perf = le32_to_cpu(limits->min_level);
289 	}
290 
291 	scmi_xfer_put(handle, t);
292 	return ret;
293 }
294 
295 static int scmi_perf_level_set(const struct scmi_handle *handle, u32 domain,
296 			       u32 level, bool poll)
297 {
298 	int ret;
299 	struct scmi_xfer *t;
300 	struct scmi_perf_set_level *lvl;
301 
302 	ret = scmi_xfer_get_init(handle, PERF_LEVEL_SET, SCMI_PROTOCOL_PERF,
303 				 sizeof(*lvl), 0, &t);
304 	if (ret)
305 		return ret;
306 
307 	t->hdr.poll_completion = poll;
308 	lvl = t->tx.buf;
309 	lvl->domain = cpu_to_le32(domain);
310 	lvl->level = cpu_to_le32(level);
311 
312 	ret = scmi_do_xfer(handle, t);
313 
314 	scmi_xfer_put(handle, t);
315 	return ret;
316 }
317 
318 static int scmi_perf_level_get(const struct scmi_handle *handle, u32 domain,
319 			       u32 *level, bool poll)
320 {
321 	int ret;
322 	struct scmi_xfer *t;
323 
324 	ret = scmi_xfer_get_init(handle, PERF_LEVEL_GET, SCMI_PROTOCOL_PERF,
325 				 sizeof(u32), sizeof(u32), &t);
326 	if (ret)
327 		return ret;
328 
329 	t->hdr.poll_completion = poll;
330 	*(__le32 *)t->tx.buf = cpu_to_le32(domain);
331 
332 	ret = scmi_do_xfer(handle, t);
333 	if (!ret)
334 		*level = le32_to_cpu(*(__le32 *)t->rx.buf);
335 
336 	scmi_xfer_put(handle, t);
337 	return ret;
338 }
339 
340 /* Device specific ops */
341 static int scmi_dev_domain_id(struct device *dev)
342 {
343 	struct of_phandle_args clkspec;
344 
345 	if (of_parse_phandle_with_args(dev->of_node, "clocks", "#clock-cells",
346 				       0, &clkspec))
347 		return -EINVAL;
348 
349 	return clkspec.args[0];
350 }
351 
352 static int scmi_dvfs_device_opps_add(const struct scmi_handle *handle,
353 				     struct device *dev)
354 {
355 	int idx, ret, domain;
356 	unsigned long freq;
357 	struct scmi_opp *opp;
358 	struct perf_dom_info *dom;
359 	struct scmi_perf_info *pi = handle->perf_priv;
360 
361 	domain = scmi_dev_domain_id(dev);
362 	if (domain < 0)
363 		return domain;
364 
365 	dom = pi->dom_info + domain;
366 
367 	for (opp = dom->opp, idx = 0; idx < dom->opp_count; idx++, opp++) {
368 		freq = opp->perf * dom->mult_factor;
369 
370 		ret = dev_pm_opp_add(dev, freq, 0);
371 		if (ret) {
372 			dev_warn(dev, "failed to add opp %luHz\n", freq);
373 
374 			while (idx-- > 0) {
375 				freq = (--opp)->perf * dom->mult_factor;
376 				dev_pm_opp_remove(dev, freq);
377 			}
378 			return ret;
379 		}
380 	}
381 	return 0;
382 }
383 
384 static int scmi_dvfs_transition_latency_get(const struct scmi_handle *handle,
385 					    struct device *dev)
386 {
387 	struct perf_dom_info *dom;
388 	struct scmi_perf_info *pi = handle->perf_priv;
389 	int domain = scmi_dev_domain_id(dev);
390 
391 	if (domain < 0)
392 		return domain;
393 
394 	dom = pi->dom_info + domain;
395 	/* uS to nS */
396 	return dom->opp[dom->opp_count - 1].trans_latency_us * 1000;
397 }
398 
399 static int scmi_dvfs_freq_set(const struct scmi_handle *handle, u32 domain,
400 			      unsigned long freq, bool poll)
401 {
402 	struct scmi_perf_info *pi = handle->perf_priv;
403 	struct perf_dom_info *dom = pi->dom_info + domain;
404 
405 	return scmi_perf_level_set(handle, domain, freq / dom->mult_factor,
406 				   poll);
407 }
408 
409 static int scmi_dvfs_freq_get(const struct scmi_handle *handle, u32 domain,
410 			      unsigned long *freq, bool poll)
411 {
412 	int ret;
413 	u32 level;
414 	struct scmi_perf_info *pi = handle->perf_priv;
415 	struct perf_dom_info *dom = pi->dom_info + domain;
416 
417 	ret = scmi_perf_level_get(handle, domain, &level, poll);
418 	if (!ret)
419 		*freq = level * dom->mult_factor;
420 
421 	return ret;
422 }
423 
424 static struct scmi_perf_ops perf_ops = {
425 	.limits_set = scmi_perf_limits_set,
426 	.limits_get = scmi_perf_limits_get,
427 	.level_set = scmi_perf_level_set,
428 	.level_get = scmi_perf_level_get,
429 	.device_domain_id = scmi_dev_domain_id,
430 	.transition_latency_get = scmi_dvfs_transition_latency_get,
431 	.device_opps_add = scmi_dvfs_device_opps_add,
432 	.freq_set = scmi_dvfs_freq_set,
433 	.freq_get = scmi_dvfs_freq_get,
434 };
435 
436 static int scmi_perf_protocol_init(struct scmi_handle *handle)
437 {
438 	int domain;
439 	u32 version;
440 	struct scmi_perf_info *pinfo;
441 
442 	scmi_version_get(handle, SCMI_PROTOCOL_PERF, &version);
443 
444 	dev_dbg(handle->dev, "Performance Version %d.%d\n",
445 		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));
446 
447 	pinfo = devm_kzalloc(handle->dev, sizeof(*pinfo), GFP_KERNEL);
448 	if (!pinfo)
449 		return -ENOMEM;
450 
451 	scmi_perf_attributes_get(handle, pinfo);
452 
453 	pinfo->dom_info = devm_kcalloc(handle->dev, pinfo->num_domains,
454 				       sizeof(*pinfo->dom_info), GFP_KERNEL);
455 	if (!pinfo->dom_info)
456 		return -ENOMEM;
457 
458 	for (domain = 0; domain < pinfo->num_domains; domain++) {
459 		struct perf_dom_info *dom = pinfo->dom_info + domain;
460 
461 		scmi_perf_domain_attributes_get(handle, domain, dom);
462 		scmi_perf_describe_levels_get(handle, domain, dom);
463 	}
464 
465 	handle->perf_ops = &perf_ops;
466 	handle->perf_priv = pinfo;
467 
468 	return 0;
469 }
470 
471 static int __init scmi_perf_init(void)
472 {
473 	return scmi_protocol_register(SCMI_PROTOCOL_PERF,
474 				      &scmi_perf_protocol_init);
475 }
476 subsys_initcall(scmi_perf_init);
477