1 /* 2 * PSCI API 3 * From arch/arm[64]/kernel/psci.c 4 * 5 * Copyright (C) 2015, Red Hat Inc, Andrew Jones <drjones@redhat.com> 6 * 7 * This work is licensed under the terms of the GNU LGPL, version 2. 8 */ 9 #include <devicetree.h> 10 #include <asm/psci.h> 11 #include <asm/setup.h> 12 #include <asm/page.h> 13 #include <asm/smp.h> 14 15 static int psci_invoke_none(unsigned int function_id, unsigned long arg0, 16 unsigned long arg1, unsigned long arg2) 17 { 18 printf("No PSCI method configured! Can't invoke...\n"); 19 return PSCI_RET_NOT_PRESENT; 20 } 21 22 psci_invoke_fn psci_invoke = psci_invoke_none; 23 24 int psci_cpu_on(unsigned long cpuid, unsigned long entry_point) 25 { 26 #ifdef __arm__ 27 return psci_invoke(PSCI_0_2_FN_CPU_ON, cpuid, entry_point, 0); 28 #else 29 return psci_invoke(PSCI_0_2_FN64_CPU_ON, cpuid, entry_point, 0); 30 #endif 31 } 32 33 extern void secondary_entry(void); 34 int cpu_psci_cpu_boot(unsigned int cpu) 35 { 36 int err = psci_cpu_on(cpus[cpu], __pa(secondary_entry)); 37 if (err) 38 printf("failed to boot CPU%d (%d)\n", cpu, err); 39 return err; 40 } 41 42 void cpu_psci_cpu_die(void) 43 { 44 int err = psci_invoke(PSCI_0_2_FN_CPU_OFF, 0, 0, 0); 45 printf("CPU%d unable to power off (error = %d)\n", smp_processor_id(), err); 46 } 47 48 void psci_system_reset(void) 49 { 50 psci_invoke(PSCI_0_2_FN_SYSTEM_RESET, 0, 0, 0); 51 } 52 53 void psci_system_off(void) 54 { 55 int err = psci_invoke(PSCI_0_2_FN_SYSTEM_OFF, 0, 0, 0); 56 printf("CPU%d unable to do system off (error = %d)\n", smp_processor_id(), err); 57 } 58 59 void psci_set_conduit(void) 60 { 61 const void *fdt = dt_fdt(); 62 const struct fdt_property *method; 63 int node, len; 64 65 node = fdt_node_offset_by_compatible(fdt, -1, "arm,psci-0.2"); 66 assert_msg(node >= 0, "PSCI v0.2 compatibility required"); 67 68 method = fdt_get_property(fdt, node, "method", &len); 69 assert(method != NULL && len == 4); 70 71 if (strcmp(method->data, "hvc") == 0) 72 psci_invoke = psci_invoke_hvc; 73 else if (strcmp(method->data, "smc") == 0) 74 psci_invoke = psci_invoke_smc; 75 else 76 assert_msg(false, "Unknown PSCI conduit: %s", method->data); 77 } 78