Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1/*
  2 * This program is free software; you can redistribute it and/or modify
  3 * it under the terms of the GNU General Public License version 2 as
  4 * published by the Free Software Foundation.
  5 *
  6 * This program is distributed in the hope that it will be useful,
  7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9 * GNU General Public License for more details.
 10 *
 11 * Copyright (C) 2015 ARM Limited
 12 */
 13
 14#define pr_fmt(fmt) "psci: " fmt
 15
 16#include <linux/arm-smccc.h>
 17#include <linux/cpuidle.h>
 18#include <linux/errno.h>
 19#include <linux/linkage.h>
 20#include <linux/of.h>
 21#include <linux/pm.h>
 22#include <linux/printk.h>
 23#include <linux/psci.h>
 24#include <linux/reboot.h>
 25#include <linux/slab.h>
 26#include <linux/suspend.h>
 27
 28#include <uapi/linux/psci.h>
 29
 30#include <asm/cpuidle.h>
 31#include <asm/cputype.h>
 32#include <asm/system_misc.h>
 33#include <asm/smp_plat.h>
 34#include <asm/suspend.h>
 35
 36/*
 37 * While a 64-bit OS can make calls with SMC32 calling conventions, for some
 38 * calls it is necessary to use SMC64 to pass or return 64-bit values.
 39 * For such calls PSCI_FN_NATIVE(version, name) will choose the appropriate
 40 * (native-width) function ID.
 41 */
 42#ifdef CONFIG_64BIT
 43#define PSCI_FN_NATIVE(version, name)	PSCI_##version##_FN64_##name
 44#else
 45#define PSCI_FN_NATIVE(version, name)	PSCI_##version##_FN_##name
 46#endif
 47
 48/*
 49 * The CPU any Trusted OS is resident on. The trusted OS may reject CPU_OFF
 50 * calls to its resident CPU, so we must avoid issuing those. We never migrate
 51 * a Trusted OS even if it claims to be capable of migration -- doing so will
 52 * require cooperation with a Trusted OS driver.
 53 */
 54static int resident_cpu = -1;
 55
 56bool psci_tos_resident_on(int cpu)
 57{
 58	return cpu == resident_cpu;
 59}
 60
 61struct psci_operations psci_ops;
 62
 63typedef unsigned long (psci_fn)(unsigned long, unsigned long,
 64				unsigned long, unsigned long);
 65static psci_fn *invoke_psci_fn;
 66
 67enum psci_function {
 68	PSCI_FN_CPU_SUSPEND,
 69	PSCI_FN_CPU_ON,
 70	PSCI_FN_CPU_OFF,
 71	PSCI_FN_MIGRATE,
 72	PSCI_FN_MAX,
 73};
 74
 75static u32 psci_function_id[PSCI_FN_MAX];
 76
 77#define PSCI_0_2_POWER_STATE_MASK		\
 78				(PSCI_0_2_POWER_STATE_ID_MASK | \
 79				PSCI_0_2_POWER_STATE_TYPE_MASK | \
 80				PSCI_0_2_POWER_STATE_AFFL_MASK)
 81
 82#define PSCI_1_0_EXT_POWER_STATE_MASK		\
 83				(PSCI_1_0_EXT_POWER_STATE_ID_MASK | \
 84				PSCI_1_0_EXT_POWER_STATE_TYPE_MASK)
 85
 86static u32 psci_cpu_suspend_feature;
 87
 88static inline bool psci_has_ext_power_state(void)
 89{
 90	return psci_cpu_suspend_feature &
 91				PSCI_1_0_FEATURES_CPU_SUSPEND_PF_MASK;
 92}
 93
 94bool psci_power_state_loses_context(u32 state)
 95{
 96	const u32 mask = psci_has_ext_power_state() ?
 97					PSCI_1_0_EXT_POWER_STATE_TYPE_MASK :
 98					PSCI_0_2_POWER_STATE_TYPE_MASK;
 99
100	return state & mask;
101}
102
103bool psci_power_state_is_valid(u32 state)
104{
105	const u32 valid_mask = psci_has_ext_power_state() ?
106			       PSCI_1_0_EXT_POWER_STATE_MASK :
107			       PSCI_0_2_POWER_STATE_MASK;
108
109	return !(state & ~valid_mask);
110}
111
112static unsigned long __invoke_psci_fn_hvc(unsigned long function_id,
113			unsigned long arg0, unsigned long arg1,
114			unsigned long arg2)
115{
116	struct arm_smccc_res res;
117
118	arm_smccc_hvc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
119	return res.a0;
120}
121
122static unsigned long __invoke_psci_fn_smc(unsigned long function_id,
123			unsigned long arg0, unsigned long arg1,
124			unsigned long arg2)
125{
126	struct arm_smccc_res res;
127
128	arm_smccc_smc(function_id, arg0, arg1, arg2, 0, 0, 0, 0, &res);
129	return res.a0;
130}
131
132static int psci_to_linux_errno(int errno)
133{
134	switch (errno) {
135	case PSCI_RET_SUCCESS:
136		return 0;
137	case PSCI_RET_NOT_SUPPORTED:
138		return -EOPNOTSUPP;
139	case PSCI_RET_INVALID_PARAMS:
140	case PSCI_RET_INVALID_ADDRESS:
141		return -EINVAL;
142	case PSCI_RET_DENIED:
143		return -EPERM;
144	};
145
146	return -EINVAL;
147}
148
149static u32 psci_get_version(void)
150{
151	return invoke_psci_fn(PSCI_0_2_FN_PSCI_VERSION, 0, 0, 0);
152}
153
154static int psci_cpu_suspend(u32 state, unsigned long entry_point)
155{
156	int err;
157	u32 fn;
158
159	fn = psci_function_id[PSCI_FN_CPU_SUSPEND];
160	err = invoke_psci_fn(fn, state, entry_point, 0);
161	return psci_to_linux_errno(err);
162}
163
164static int psci_cpu_off(u32 state)
165{
166	int err;
167	u32 fn;
168
169	fn = psci_function_id[PSCI_FN_CPU_OFF];
170	err = invoke_psci_fn(fn, state, 0, 0);
171	return psci_to_linux_errno(err);
172}
173
174static int psci_cpu_on(unsigned long cpuid, unsigned long entry_point)
175{
176	int err;
177	u32 fn;
178
179	fn = psci_function_id[PSCI_FN_CPU_ON];
180	err = invoke_psci_fn(fn, cpuid, entry_point, 0);
181	return psci_to_linux_errno(err);
182}
183
184static int psci_migrate(unsigned long cpuid)
185{
186	int err;
187	u32 fn;
188
189	fn = psci_function_id[PSCI_FN_MIGRATE];
190	err = invoke_psci_fn(fn, cpuid, 0, 0);
191	return psci_to_linux_errno(err);
192}
193
194static int psci_affinity_info(unsigned long target_affinity,
195		unsigned long lowest_affinity_level)
196{
197	return invoke_psci_fn(PSCI_FN_NATIVE(0_2, AFFINITY_INFO),
198			      target_affinity, lowest_affinity_level, 0);
199}
200
201static int psci_migrate_info_type(void)
202{
203	return invoke_psci_fn(PSCI_0_2_FN_MIGRATE_INFO_TYPE, 0, 0, 0);
204}
205
206static unsigned long psci_migrate_info_up_cpu(void)
207{
208	return invoke_psci_fn(PSCI_FN_NATIVE(0_2, MIGRATE_INFO_UP_CPU),
209			      0, 0, 0);
210}
211
212static int get_set_conduit_method(struct device_node *np)
213{
214	const char *method;
215
216	pr_info("probing for conduit method from DT.\n");
217
218	if (of_property_read_string(np, "method", &method)) {
219		pr_warn("missing \"method\" property\n");
220		return -ENXIO;
221	}
222
223	if (!strcmp("hvc", method)) {
224		invoke_psci_fn = __invoke_psci_fn_hvc;
225	} else if (!strcmp("smc", method)) {
226		invoke_psci_fn = __invoke_psci_fn_smc;
227	} else {
228		pr_warn("invalid \"method\" property: %s\n", method);
229		return -EINVAL;
230	}
231	return 0;
232}
233
234static void psci_sys_reset(enum reboot_mode reboot_mode, const char *cmd)
235{
236	invoke_psci_fn(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0);
237}
238
239static void psci_sys_poweroff(void)
240{
241	invoke_psci_fn(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0);
242}
243
244static int __init psci_features(u32 psci_func_id)
245{
246	return invoke_psci_fn(PSCI_1_0_FN_PSCI_FEATURES,
247			      psci_func_id, 0, 0);
248}
249
250#ifdef CONFIG_CPU_IDLE
251static DEFINE_PER_CPU_READ_MOSTLY(u32 *, psci_power_state);
252
253static int psci_dt_cpu_init_idle(struct device_node *cpu_node, int cpu)
254{
255	int i, ret, count = 0;
256	u32 *psci_states;
257	struct device_node *state_node;
258
259	/*
260	 * If the PSCI cpu_suspend function hook has not been initialized
261	 * idle states must not be enabled, so bail out
262	 */
263	if (!psci_ops.cpu_suspend)
264		return -EOPNOTSUPP;
265
266	/* Count idle states */
267	while ((state_node = of_parse_phandle(cpu_node, "cpu-idle-states",
268					      count))) {
269		count++;
270		of_node_put(state_node);
271	}
272
273	if (!count)
274		return -ENODEV;
275
276	psci_states = kcalloc(count, sizeof(*psci_states), GFP_KERNEL);
277	if (!psci_states)
278		return -ENOMEM;
279
280	for (i = 0; i < count; i++) {
281		u32 state;
282
283		state_node = of_parse_phandle(cpu_node, "cpu-idle-states", i);
284
285		ret = of_property_read_u32(state_node,
286					   "arm,psci-suspend-param",
287					   &state);
288		if (ret) {
289			pr_warn(" * %s missing arm,psci-suspend-param property\n",
290				state_node->full_name);
291			of_node_put(state_node);
292			goto free_mem;
293		}
294
295		of_node_put(state_node);
296		pr_debug("psci-power-state %#x index %d\n", state, i);
297		if (!psci_power_state_is_valid(state)) {
298			pr_warn("Invalid PSCI power state %#x\n", state);
299			ret = -EINVAL;
300			goto free_mem;
301		}
302		psci_states[i] = state;
303	}
304	/* Idle states parsed correctly, initialize per-cpu pointer */
305	per_cpu(psci_power_state, cpu) = psci_states;
306	return 0;
307
308free_mem:
309	kfree(psci_states);
310	return ret;
311}
312
313int psci_cpu_init_idle(unsigned int cpu)
314{
315	struct device_node *cpu_node;
316	int ret;
317
318	cpu_node = of_get_cpu_node(cpu, NULL);
319	if (!cpu_node)
320		return -ENODEV;
321
322	ret = psci_dt_cpu_init_idle(cpu_node, cpu);
323
324	of_node_put(cpu_node);
325
326	return ret;
327}
328
329static int psci_suspend_finisher(unsigned long index)
330{
331	u32 *state = __this_cpu_read(psci_power_state);
332
333	return psci_ops.cpu_suspend(state[index - 1],
334				    virt_to_phys(cpu_resume));
335}
336
337int psci_cpu_suspend_enter(unsigned long index)
338{
339	int ret;
340	u32 *state = __this_cpu_read(psci_power_state);
341	/*
342	 * idle state index 0 corresponds to wfi, should never be called
343	 * from the cpu_suspend operations
344	 */
345	if (WARN_ON_ONCE(!index))
346		return -EINVAL;
347
348	if (!psci_power_state_loses_context(state[index - 1]))
349		ret = psci_ops.cpu_suspend(state[index - 1], 0);
350	else
351		ret = cpu_suspend(index, psci_suspend_finisher);
352
353	return ret;
354}
355
356/* ARM specific CPU idle operations */
357#ifdef CONFIG_ARM
358static struct cpuidle_ops psci_cpuidle_ops __initdata = {
359	.suspend = psci_cpu_suspend_enter,
360	.init = psci_dt_cpu_init_idle,
361};
362
363CPUIDLE_METHOD_OF_DECLARE(psci, "psci", &psci_cpuidle_ops);
364#endif
365#endif
366
367static int psci_system_suspend(unsigned long unused)
368{
369	return invoke_psci_fn(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND),
370			      virt_to_phys(cpu_resume), 0, 0);
371}
372
373static int psci_system_suspend_enter(suspend_state_t state)
374{
375	return cpu_suspend(0, psci_system_suspend);
376}
377
378static const struct platform_suspend_ops psci_suspend_ops = {
379	.valid          = suspend_valid_only_mem,
380	.enter          = psci_system_suspend_enter,
381};
382
383static void __init psci_init_system_suspend(void)
384{
385	int ret;
386
387	if (!IS_ENABLED(CONFIG_SUSPEND))
388		return;
389
390	ret = psci_features(PSCI_FN_NATIVE(1_0, SYSTEM_SUSPEND));
391
392	if (ret != PSCI_RET_NOT_SUPPORTED)
393		suspend_set_ops(&psci_suspend_ops);
394}
395
396static void __init psci_init_cpu_suspend(void)
397{
398	int feature = psci_features(psci_function_id[PSCI_FN_CPU_SUSPEND]);
399
400	if (feature != PSCI_RET_NOT_SUPPORTED)
401		psci_cpu_suspend_feature = feature;
402}
403
404/*
405 * Detect the presence of a resident Trusted OS which may cause CPU_OFF to
406 * return DENIED (which would be fatal).
407 */
408static void __init psci_init_migrate(void)
409{
410	unsigned long cpuid;
411	int type, cpu = -1;
412
413	type = psci_ops.migrate_info_type();
414
415	if (type == PSCI_0_2_TOS_MP) {
416		pr_info("Trusted OS migration not required\n");
417		return;
418	}
419
420	if (type == PSCI_RET_NOT_SUPPORTED) {
421		pr_info("MIGRATE_INFO_TYPE not supported.\n");
422		return;
423	}
424
425	if (type != PSCI_0_2_TOS_UP_MIGRATE &&
426	    type != PSCI_0_2_TOS_UP_NO_MIGRATE) {
427		pr_err("MIGRATE_INFO_TYPE returned unknown type (%d)\n", type);
428		return;
429	}
430
431	cpuid = psci_migrate_info_up_cpu();
432	if (cpuid & ~MPIDR_HWID_BITMASK) {
433		pr_warn("MIGRATE_INFO_UP_CPU reported invalid physical ID (0x%lx)\n",
434			cpuid);
435		return;
436	}
437
438	cpu = get_logical_index(cpuid);
439	resident_cpu = cpu >= 0 ? cpu : -1;
440
441	pr_info("Trusted OS resident on physical CPU 0x%lx\n", cpuid);
442}
443
444static void __init psci_0_2_set_functions(void)
445{
446	pr_info("Using standard PSCI v0.2 function IDs\n");
447	psci_function_id[PSCI_FN_CPU_SUSPEND] =
448					PSCI_FN_NATIVE(0_2, CPU_SUSPEND);
449	psci_ops.cpu_suspend = psci_cpu_suspend;
450
451	psci_function_id[PSCI_FN_CPU_OFF] = PSCI_0_2_FN_CPU_OFF;
452	psci_ops.cpu_off = psci_cpu_off;
453
454	psci_function_id[PSCI_FN_CPU_ON] = PSCI_FN_NATIVE(0_2, CPU_ON);
455	psci_ops.cpu_on = psci_cpu_on;
456
457	psci_function_id[PSCI_FN_MIGRATE] = PSCI_FN_NATIVE(0_2, MIGRATE);
458	psci_ops.migrate = psci_migrate;
459
460	psci_ops.affinity_info = psci_affinity_info;
461
462	psci_ops.migrate_info_type = psci_migrate_info_type;
463
464	arm_pm_restart = psci_sys_reset;
465
466	pm_power_off = psci_sys_poweroff;
467}
468
469/*
470 * Probe function for PSCI firmware versions >= 0.2
471 */
472static int __init psci_probe(void)
473{
474	u32 ver = psci_get_version();
475
476	pr_info("PSCIv%d.%d detected in firmware.\n",
477			PSCI_VERSION_MAJOR(ver),
478			PSCI_VERSION_MINOR(ver));
479
480	if (PSCI_VERSION_MAJOR(ver) == 0 && PSCI_VERSION_MINOR(ver) < 2) {
481		pr_err("Conflicting PSCI version detected.\n");
482		return -EINVAL;
483	}
484
485	psci_0_2_set_functions();
486
487	psci_init_migrate();
488
489	if (PSCI_VERSION_MAJOR(ver) >= 1) {
490		psci_init_cpu_suspend();
491		psci_init_system_suspend();
492	}
493
494	return 0;
495}
496
497typedef int (*psci_initcall_t)(const struct device_node *);
498
499/*
500 * PSCI init function for PSCI versions >=0.2
501 *
502 * Probe based on PSCI PSCI_VERSION function
503 */
504static int __init psci_0_2_init(struct device_node *np)
505{
506	int err;
507
508	err = get_set_conduit_method(np);
509
510	if (err)
511		goto out_put_node;
512	/*
513	 * Starting with v0.2, the PSCI specification introduced a call
514	 * (PSCI_VERSION) that allows probing the firmware version, so
515	 * that PSCI function IDs and version specific initialization
516	 * can be carried out according to the specific version reported
517	 * by firmware
518	 */
519	err = psci_probe();
520
521out_put_node:
522	of_node_put(np);
523	return err;
524}
525
526/*
527 * PSCI < v0.2 get PSCI Function IDs via DT.
528 */
529static int __init psci_0_1_init(struct device_node *np)
530{
531	u32 id;
532	int err;
533
534	err = get_set_conduit_method(np);
535
536	if (err)
537		goto out_put_node;
538
539	pr_info("Using PSCI v0.1 Function IDs from DT\n");
540
541	if (!of_property_read_u32(np, "cpu_suspend", &id)) {
542		psci_function_id[PSCI_FN_CPU_SUSPEND] = id;
543		psci_ops.cpu_suspend = psci_cpu_suspend;
544	}
545
546	if (!of_property_read_u32(np, "cpu_off", &id)) {
547		psci_function_id[PSCI_FN_CPU_OFF] = id;
548		psci_ops.cpu_off = psci_cpu_off;
549	}
550
551	if (!of_property_read_u32(np, "cpu_on", &id)) {
552		psci_function_id[PSCI_FN_CPU_ON] = id;
553		psci_ops.cpu_on = psci_cpu_on;
554	}
555
556	if (!of_property_read_u32(np, "migrate", &id)) {
557		psci_function_id[PSCI_FN_MIGRATE] = id;
558		psci_ops.migrate = psci_migrate;
559	}
560
561out_put_node:
562	of_node_put(np);
563	return err;
564}
565
566static const struct of_device_id const psci_of_match[] __initconst = {
567	{ .compatible = "arm,psci",	.data = psci_0_1_init},
568	{ .compatible = "arm,psci-0.2",	.data = psci_0_2_init},
569	{ .compatible = "arm,psci-1.0",	.data = psci_0_2_init},
570	{},
571};
572
573int __init psci_dt_init(void)
574{
575	struct device_node *np;
576	const struct of_device_id *matched_np;
577	psci_initcall_t init_fn;
578
579	np = of_find_matching_node_and_match(NULL, psci_of_match, &matched_np);
580
581	if (!np)
582		return -ENODEV;
583
584	init_fn = (psci_initcall_t)matched_np->data;
585	return init_fn(np);
586}
587
588#ifdef CONFIG_ACPI
589/*
590 * We use PSCI 0.2+ when ACPI is deployed on ARM64 and it's
591 * explicitly clarified in SBBR
592 */
593int __init psci_acpi_init(void)
594{
595	if (!acpi_psci_present()) {
596		pr_info("is not implemented in ACPI.\n");
597		return -EOPNOTSUPP;
598	}
599
600	pr_info("probing for conduit method from ACPI.\n");
601
602	if (acpi_psci_use_hvc())
603		invoke_psci_fn = __invoke_psci_fn_hvc;
604	else
605		invoke_psci_fn = __invoke_psci_fn_smc;
606
607	return psci_probe();
608}
609#endif