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