1 /* 2 * Copyright (C) 2013 - ARM Ltd 3 * Author: Marc Zyngier <marc.zyngier@arm.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18 #include <common.h> 19 #include <stdio_dev.h> 20 #include <linux/ctype.h> 21 #include <linux/types.h> 22 #include <asm/global_data.h> 23 #include <libfdt.h> 24 #include <fdt_support.h> 25 #include <asm/armv7.h> 26 #include <asm/psci.h> 27 28 static int fdt_psci(void *fdt) 29 { 30 #ifdef CONFIG_ARMV7_PSCI 31 int nodeoff; 32 int tmp; 33 34 nodeoff = fdt_path_offset(fdt, "/cpus"); 35 if (nodeoff < 0) { 36 printf("couldn't find /cpus\n"); 37 return nodeoff; 38 } 39 40 /* add 'enable-method = "psci"' to each cpu node */ 41 for (tmp = fdt_first_subnode(fdt, nodeoff); 42 tmp >= 0; 43 tmp = fdt_next_subnode(fdt, tmp)) { 44 const struct fdt_property *prop; 45 int len; 46 47 prop = fdt_get_property(fdt, tmp, "device_type", &len); 48 if (!prop) 49 continue; 50 if (len < 4) 51 continue; 52 if (strcmp(prop->data, "cpu")) 53 continue; 54 55 fdt_setprop_string(fdt, tmp, "enable-method", "psci"); 56 } 57 58 nodeoff = fdt_path_offset(fdt, "/psci"); 59 if (nodeoff < 0) { 60 nodeoff = fdt_path_offset(fdt, "/"); 61 if (nodeoff < 0) 62 return nodeoff; 63 64 nodeoff = fdt_add_subnode(fdt, nodeoff, "psci"); 65 if (nodeoff < 0) 66 return nodeoff; 67 } 68 69 tmp = fdt_setprop_string(fdt, nodeoff, "compatible", "arm,psci"); 70 if (tmp) 71 return tmp; 72 tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); 73 if (tmp) 74 return tmp; 75 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend", ARM_PSCI_FN_CPU_SUSPEND); 76 if (tmp) 77 return tmp; 78 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off", ARM_PSCI_FN_CPU_OFF); 79 if (tmp) 80 return tmp; 81 tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on", ARM_PSCI_FN_CPU_ON); 82 if (tmp) 83 return tmp; 84 tmp = fdt_setprop_u32(fdt, nodeoff, "migrate", ARM_PSCI_FN_MIGRATE); 85 if (tmp) 86 return tmp; 87 #endif 88 return 0; 89 } 90 91 int psci_update_dt(void *fdt) 92 { 93 #if defined(CONFIG_ARMV7_NONSEC) || defined(CONFIG_ARMV7_VIRT) 94 if (!armv7_boot_nonsec()) 95 return 0; 96 #endif 97 #ifndef CONFIG_ARMV7_SECURE_BASE 98 /* secure code lives in RAM, keep it alive */ 99 fdt_add_mem_rsv(fdt, (unsigned long)__secure_start, 100 __secure_end - __secure_start); 101 #endif 102 103 return fdt_psci(fdt); 104 } 105