]>
Commit | Line | Data |
---|---|---|
45684ae3 HZ |
1 | /* |
2 | * Copyright 2016 NXP Semiconductor, Inc. | |
3 | * | |
4 | * SPDX-License-Identifier: GPL-2.0+ | |
5 | */ | |
6 | ||
7 | #include <common.h> | |
b08c8c48 | 8 | #include <linux/libfdt.h> |
45684ae3 HZ |
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 | { | |
9a561753 | 19 | #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \ |
daa92644 | 20 | defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI) |
45684ae3 HZ |
21 | int nodeoff; |
22 | unsigned int psci_ver = 0; | |
45684ae3 HZ |
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 | ||
45684ae3 HZ |
54 | nodeoff = fdt_path_offset(fdt, "/psci"); |
55 | if (nodeoff >= 0) | |
56 | goto init_psci_node; | |
57 | ||
45684ae3 HZ |
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(); | |
9a561753 | 69 | #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI) |
bded2189 | 70 | psci_ver = ARM_PSCI_VER_1_0; |
45684ae3 | 71 | #endif |
678382c7 | 72 | if (psci_ver >= ARM_PSCI_VER_1_0) { |
2c774165 HZ |
73 | tmp = fdt_setprop_string(fdt, nodeoff, |
74 | "compatible", "arm,psci-1.0"); | |
75 | if (tmp) | |
76 | return tmp; | |
678382c7 AH |
77 | } |
78 | ||
79 | if (psci_ver >= ARM_PSCI_VER_0_2) { | |
2c774165 HZ |
80 | tmp = fdt_appendprop_string(fdt, nodeoff, |
81 | "compatible", "arm,psci-0.2"); | |
82 | if (tmp) | |
83 | return tmp; | |
678382c7 AH |
84 | } |
85 | ||
86 | #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT | |
2c774165 HZ |
87 | /* |
88 | * The Secure firmware framework isn't able to support PSCI version 0.1. | |
89 | */ | |
678382c7 | 90 | if (psci_ver < ARM_PSCI_VER_0_2) { |
2c774165 HZ |
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; | |
45684ae3 | 111 | } |
678382c7 | 112 | #endif |
45684ae3 | 113 | |
45684ae3 HZ |
114 | tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc"); |
115 | if (tmp) | |
116 | return tmp; | |
117 | ||
45684ae3 HZ |
118 | #endif |
119 | return 0; | |
120 | } |