183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
245684ae3SHou Zhiqiang /*
345684ae3SHou Zhiqiang * Copyright 2016 NXP Semiconductor, Inc.
445684ae3SHou Zhiqiang */
545684ae3SHou Zhiqiang
645684ae3SHou Zhiqiang #include <common.h>
7b08c8c48SMasahiro Yamada #include <linux/libfdt.h>
845684ae3SHou Zhiqiang #include <fdt_support.h>
945684ae3SHou Zhiqiang #include <linux/sizes.h>
1045684ae3SHou Zhiqiang #include <linux/kernel.h>
1145684ae3SHou Zhiqiang #include <asm/psci.h>
1245684ae3SHou Zhiqiang #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
1345684ae3SHou Zhiqiang #include <asm/armv8/sec_firmware.h>
1445684ae3SHou Zhiqiang #endif
1545684ae3SHou Zhiqiang
fdt_psci(void * fdt)1645684ae3SHou Zhiqiang int fdt_psci(void *fdt)
1745684ae3SHou Zhiqiang {
189a561753Smacro.wave.z@gmail.com #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \
19daa92644SHou Zhiqiang defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
2045684ae3SHou Zhiqiang int nodeoff;
2145684ae3SHou Zhiqiang unsigned int psci_ver = 0;
2245684ae3SHou Zhiqiang int tmp;
2345684ae3SHou Zhiqiang
2445684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/cpus");
2545684ae3SHou Zhiqiang if (nodeoff < 0) {
2645684ae3SHou Zhiqiang printf("couldn't find /cpus\n");
2745684ae3SHou Zhiqiang return nodeoff;
2845684ae3SHou Zhiqiang }
2945684ae3SHou Zhiqiang
3045684ae3SHou Zhiqiang /* add 'enable-method = "psci"' to each cpu node */
3145684ae3SHou Zhiqiang for (tmp = fdt_first_subnode(fdt, nodeoff);
3245684ae3SHou Zhiqiang tmp >= 0;
3345684ae3SHou Zhiqiang tmp = fdt_next_subnode(fdt, tmp)) {
3445684ae3SHou Zhiqiang const struct fdt_property *prop;
3545684ae3SHou Zhiqiang int len;
3645684ae3SHou Zhiqiang
3745684ae3SHou Zhiqiang prop = fdt_get_property(fdt, tmp, "device_type", &len);
3845684ae3SHou Zhiqiang if (!prop)
3945684ae3SHou Zhiqiang continue;
4045684ae3SHou Zhiqiang if (len < 4)
4145684ae3SHou Zhiqiang continue;
4245684ae3SHou Zhiqiang if (strcmp(prop->data, "cpu"))
4345684ae3SHou Zhiqiang continue;
4445684ae3SHou Zhiqiang
4545684ae3SHou Zhiqiang /*
4645684ae3SHou Zhiqiang * Not checking rv here, our approach is to skip over errors in
4745684ae3SHou Zhiqiang * individual cpu nodes, hopefully some of the nodes are
4845684ae3SHou Zhiqiang * processed correctly and those will boot
4945684ae3SHou Zhiqiang */
5045684ae3SHou Zhiqiang fdt_setprop_string(fdt, tmp, "enable-method", "psci");
5145684ae3SHou Zhiqiang }
5245684ae3SHou Zhiqiang
5345684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/psci");
5445684ae3SHou Zhiqiang if (nodeoff >= 0)
5545684ae3SHou Zhiqiang goto init_psci_node;
5645684ae3SHou Zhiqiang
5745684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/");
5845684ae3SHou Zhiqiang if (nodeoff < 0)
5945684ae3SHou Zhiqiang return nodeoff;
6045684ae3SHou Zhiqiang
6145684ae3SHou Zhiqiang nodeoff = fdt_add_subnode(fdt, nodeoff, "psci");
6245684ae3SHou Zhiqiang if (nodeoff < 0)
6345684ae3SHou Zhiqiang return nodeoff;
6445684ae3SHou Zhiqiang
6545684ae3SHou Zhiqiang init_psci_node:
6645684ae3SHou Zhiqiang #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
6745684ae3SHou Zhiqiang psci_ver = sec_firmware_support_psci_version();
689a561753Smacro.wave.z@gmail.com #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
69bded2189SHou Zhiqiang psci_ver = ARM_PSCI_VER_1_0;
70326bd726SStephen Warren #elif defined(CONFIG_ARMV7_PSCI_0_2)
71326bd726SStephen Warren psci_ver = ARM_PSCI_VER_0_2;
7245684ae3SHou Zhiqiang #endif
73678382c7SAndre Heider if (psci_ver >= ARM_PSCI_VER_1_0) {
742c774165SHou Zhiqiang tmp = fdt_setprop_string(fdt, nodeoff,
752c774165SHou Zhiqiang "compatible", "arm,psci-1.0");
762c774165SHou Zhiqiang if (tmp)
772c774165SHou Zhiqiang return tmp;
78678382c7SAndre Heider }
79678382c7SAndre Heider
80678382c7SAndre Heider if (psci_ver >= ARM_PSCI_VER_0_2) {
812c774165SHou Zhiqiang tmp = fdt_appendprop_string(fdt, nodeoff,
822c774165SHou Zhiqiang "compatible", "arm,psci-0.2");
832c774165SHou Zhiqiang if (tmp)
842c774165SHou Zhiqiang return tmp;
85678382c7SAndre Heider }
86678382c7SAndre Heider
87678382c7SAndre Heider #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
882c774165SHou Zhiqiang /*
892c774165SHou Zhiqiang * The Secure firmware framework isn't able to support PSCI version 0.1.
902c774165SHou Zhiqiang */
91678382c7SAndre Heider if (psci_ver < ARM_PSCI_VER_0_2) {
922c774165SHou Zhiqiang tmp = fdt_appendprop_string(fdt, nodeoff,
932c774165SHou Zhiqiang "compatible", "arm,psci");
9445684ae3SHou Zhiqiang if (tmp)
9545684ae3SHou Zhiqiang return tmp;
9645684ae3SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend",
9745684ae3SHou Zhiqiang ARM_PSCI_FN_CPU_SUSPEND);
9845684ae3SHou Zhiqiang if (tmp)
9945684ae3SHou Zhiqiang return tmp;
1002c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off",
1012c774165SHou Zhiqiang ARM_PSCI_FN_CPU_OFF);
10245684ae3SHou Zhiqiang if (tmp)
10345684ae3SHou Zhiqiang return tmp;
1042c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on",
1052c774165SHou Zhiqiang ARM_PSCI_FN_CPU_ON);
10645684ae3SHou Zhiqiang if (tmp)
10745684ae3SHou Zhiqiang return tmp;
1082c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "migrate",
1092c774165SHou Zhiqiang ARM_PSCI_FN_MIGRATE);
11045684ae3SHou Zhiqiang if (tmp)
11145684ae3SHou Zhiqiang return tmp;
1122c774165SHou Zhiqiang }
113678382c7SAndre Heider #endif
1142c774165SHou Zhiqiang
1152c774165SHou Zhiqiang tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc");
1162c774165SHou Zhiqiang if (tmp)
1172c774165SHou Zhiqiang return tmp;
1182c774165SHou Zhiqiang
119*74c69cdcSStephen Warren tmp = fdt_setprop_string(fdt, nodeoff, "status", "okay");
120*74c69cdcSStephen Warren if (tmp)
121*74c69cdcSStephen Warren return tmp;
122*74c69cdcSStephen Warren
12345684ae3SHou Zhiqiang #endif
12445684ae3SHou Zhiqiang return 0;
12545684ae3SHou Zhiqiang }
126