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_ARMV8_PSCI) || defined(CONFIG_ARMV7_PSCI) 20 int nodeoff; 21 unsigned int psci_ver = 0; 22 char *psci_compt; 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 /* 55 * The PSCI node might be called "/psci" or might be called something 56 * else but contain either of the compatible strings 57 * "arm,psci"/"arm,psci-0.2" 58 */ 59 nodeoff = fdt_path_offset(fdt, "/psci"); 60 if (nodeoff >= 0) 61 goto init_psci_node; 62 63 nodeoff = fdt_node_offset_by_compatible(fdt, -1, "arm,psci"); 64 if (nodeoff >= 0) 65 goto init_psci_node; 66 67 nodeoff = fdt_node_offset_by_compatible(fdt, -1, "arm,psci-0.2"); 68 if (nodeoff >= 0) 69 goto init_psci_node; 70 71 nodeoff = fdt_node_offset_by_compatible(fdt, -1, "arm,psci-1.0"); 72 if (nodeoff >= 0) 73 goto init_psci_node; 74 75 nodeoff = fdt_path_offset(fdt, "/"); 76 if (nodeoff < 0) 77 return nodeoff; 78 79 nodeoff = fdt_add_subnode(fdt, nodeoff, "psci"); 80 if (nodeoff < 0) 81 return nodeoff; 82 83 init_psci_node: 84 #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT 85 psci_ver = sec_firmware_support_psci_version(); 86 #endif 87 switch (psci_ver) { 88 case 0x00010000: 89 psci_compt = "arm,psci-1.0"; 90 break; 91 case 0x00000002: 92 psci_compt = "arm,psci-0.2"; 93 break; 94 default: 95 psci_compt = "arm,psci"; 96 break; 97 } 98 99 tmp = fdt_setprop_string(fdt, nodeoff, "compatible", psci_compt); 100 if (tmp) 101 return tmp; 102 tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); 103 if (tmp) 104 return tmp; 105 106 #ifdef CONFIG_ARMV7_PSCI 107 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", 108 ARM_PSCI_FN_CPU_SUSPEND); 109 if (tmp) 110 return tmp; 111 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", ARM_PSCI_FN_CPU_OFF); 112 if (tmp) 113 return tmp; 114 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", ARM_PSCI_FN_CPU_ON); 115 if (tmp) 116 return tmp; 117 tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", ARM_PSCI_FN_MIGRATE); 118 if (tmp) 119 return tmp; 120 #endif 121 #endif 122 return 0; 123 } 124