1 /* 2 * Copyright 2016 NXP Semiconductor, Inc. 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 */ 6 7 #include <common.h> 8 #include <linux/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 if (psci_ver >= ARM_PSCI_VER_1_0) { 73 tmp = fdt_setprop_string(fdt, nodeoff, 74 "compatible", "arm,psci-1.0"); 75 if (tmp) 76 return tmp; 77 } 78 79 if (psci_ver >= ARM_PSCI_VER_0_2) { 80 tmp = fdt_appendprop_string(fdt, nodeoff, 81 "compatible", "arm,psci-0.2"); 82 if (tmp) 83 return tmp; 84 } 85 86 #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT 87 /* 88 * The Secure firmware framework isn't able to support PSCI version 0.1. 89 */ 90 if (psci_ver < ARM_PSCI_VER_0_2) { 91 tmp = fdt_appendprop_string(fdt, nodeoff, 92 "compatible", "arm,psci"); 93 if (tmp) 94 return tmp; 95 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", 96 ARM_PSCI_FN_CPU_SUSPEND); 97 if (tmp) 98 return tmp; 99 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", 100 ARM_PSCI_FN_CPU_OFF); 101 if (tmp) 102 return tmp; 103 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", 104 ARM_PSCI_FN_CPU_ON); 105 if (tmp) 106 return tmp; 107 tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", 108 ARM_PSCI_FN_MIGRATE); 109 if (tmp) 110 return tmp; 111 } 112 #endif 113 114 tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); 115 if (tmp) 116 return tmp; 117 118 #endif 119 return 0; 120 } 121