1 /* 2 * Copyright 2016 NXP Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <libfdt.h> 9 #include <fdt_support.h> 10 #include <linux/sizes.h> 11 #include <linux/kernel.h> 12 #include <asm/psci.h> 13 #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT 14 #include <asm/armv8/sec_firmware.h> 15 #endif 16 17 int fdt_psci(void *fdt) 18 { 19 #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \ 20 defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) 21 int nodeoff; 22 unsigned int psci_ver = 0; 23 int tmp; 24 25 nodeoff = fdt_path_offset(fdt, "/cpus"); 26 if (nodeoff < 0) { 27 printf("couldn't find /cpus\n"); 28 return nodeoff; 29 } 30 31 /* add 'enable-method = "psci"' to each cpu node */ 32 for (tmp = fdt_first_subnode(fdt, nodeoff); 33 tmp >= 0; 34 tmp = fdt_next_subnode(fdt, tmp)) { 35 const struct fdt_property *prop; 36 int len; 37 38 prop = fdt_get_property(fdt, tmp, "device_type", &len); 39 if (!prop) 40 continue; 41 if (len < 4) 42 continue; 43 if (strcmp(prop->data, "cpu")) 44 continue; 45 46 /* 47 * Not checking rv here, our approach is to skip over errors in 48 * individual cpu nodes, hopefully some of the nodes are 49 * processed correctly and those will boot 50 */ 51 fdt_setprop_string(fdt, tmp, "enable-method", "psci"); 52 } 53 54 nodeoff = fdt_path_offset(fdt, "/psci"); 55 if (nodeoff >= 0) 56 goto init_psci_node; 57 58 nodeoff = fdt_path_offset(fdt, "/"); 59 if (nodeoff < 0) 60 return nodeoff; 61 62 nodeoff = fdt_add_subnode(fdt, nodeoff, "psci"); 63 if (nodeoff < 0) 64 return nodeoff; 65 66 init_psci_node: 67 #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT 68 psci_ver = sec_firmware_support_psci_version(); 69 #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) 70 psci_ver = ARM_PSCI_VER_1_0; 71 #endif 72 switch (psci_ver) { 73 case ARM_PSCI_VER_1_0: 74 tmp = fdt_setprop_string(fdt, nodeoff, 75 "compatible", "arm,psci-1.0"); 76 if (tmp) 77 return tmp; 78 case ARM_PSCI_VER_0_2: 79 tmp = fdt_appendprop_string(fdt, nodeoff, 80 "compatible", "arm,psci-0.2"); 81 if (tmp) 82 return tmp; 83 default: 84 /* 85 * The Secure firmware framework isn't able to support PSCI version 0.1. 86 */ 87 #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT 88 tmp = fdt_appendprop_string(fdt, nodeoff, 89 "compatible", "arm,psci"); 90 if (tmp) 91 return tmp; 92 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", 93 ARM_PSCI_FN_CPU_SUSPEND); 94 if (tmp) 95 return tmp; 96 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", 97 ARM_PSCI_FN_CPU_OFF); 98 if (tmp) 99 return tmp; 100 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", 101 ARM_PSCI_FN_CPU_ON); 102 if (tmp) 103 return tmp; 104 tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", 105 ARM_PSCI_FN_MIGRATE); 106 if (tmp) 107 return tmp; 108 #endif 109 break; 110 } 111 112 tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); 113 if (tmp) 114 return tmp; 115 116 #endif 117 return 0; 118 } 119