145684ae3SHou Zhiqiang /*
245684ae3SHou Zhiqiang * Copyright 2016 NXP Semiconductor, Inc.
345684ae3SHou Zhiqiang *
445684ae3SHou Zhiqiang * SPDX-License-Identifier: GPL-2.0+
545684ae3SHou Zhiqiang */
645684ae3SHou Zhiqiang
745684ae3SHou Zhiqiang #include <common.h>
8*0e00a84cSMasahiro Yamada #include <linux/libfdt.h>
945684ae3SHou Zhiqiang #include <fdt_support.h>
1045684ae3SHou Zhiqiang #include <linux/sizes.h>
1145684ae3SHou Zhiqiang #include <linux/kernel.h>
1245684ae3SHou Zhiqiang #include <asm/psci.h>
1345684ae3SHou Zhiqiang #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
1445684ae3SHou Zhiqiang #include <asm/armv8/sec_firmware.h>
1545684ae3SHou Zhiqiang #endif
1645684ae3SHou Zhiqiang
fdt_psci(void * fdt)1745684ae3SHou Zhiqiang int fdt_psci(void *fdt)
1845684ae3SHou Zhiqiang {
199a561753Smacro.wave.z@gmail.com #if defined(CONFIG_ARMV7_PSCI) || defined(CONFIG_ARMV8_PSCI) || \
20daa92644SHou Zhiqiang defined(CONFIG_SEC_FIRMWARE_ARMV8_PSCI)
2145684ae3SHou Zhiqiang int nodeoff;
2245684ae3SHou Zhiqiang unsigned int psci_ver = 0;
2345684ae3SHou Zhiqiang int tmp;
2445684ae3SHou Zhiqiang
2545684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/cpus");
2645684ae3SHou Zhiqiang if (nodeoff < 0) {
2745684ae3SHou Zhiqiang printf("couldn't find /cpus\n");
2845684ae3SHou Zhiqiang return nodeoff;
2945684ae3SHou Zhiqiang }
3045684ae3SHou Zhiqiang
3145684ae3SHou Zhiqiang /* add 'enable-method = "psci"' to each cpu node */
3245684ae3SHou Zhiqiang for (tmp = fdt_first_subnode(fdt, nodeoff);
3345684ae3SHou Zhiqiang tmp >= 0;
3445684ae3SHou Zhiqiang tmp = fdt_next_subnode(fdt, tmp)) {
3545684ae3SHou Zhiqiang const struct fdt_property *prop;
3645684ae3SHou Zhiqiang int len;
3745684ae3SHou Zhiqiang
3845684ae3SHou Zhiqiang prop = fdt_get_property(fdt, tmp, "device_type", &len);
3945684ae3SHou Zhiqiang if (!prop)
4045684ae3SHou Zhiqiang continue;
4145684ae3SHou Zhiqiang if (len < 4)
4245684ae3SHou Zhiqiang continue;
4345684ae3SHou Zhiqiang if (strcmp(prop->data, "cpu"))
4445684ae3SHou Zhiqiang continue;
4545684ae3SHou Zhiqiang
4645684ae3SHou Zhiqiang /*
4745684ae3SHou Zhiqiang * Not checking rv here, our approach is to skip over errors in
4845684ae3SHou Zhiqiang * individual cpu nodes, hopefully some of the nodes are
4945684ae3SHou Zhiqiang * processed correctly and those will boot
5045684ae3SHou Zhiqiang */
5145684ae3SHou Zhiqiang fdt_setprop_string(fdt, tmp, "enable-method", "psci");
5245684ae3SHou Zhiqiang }
5345684ae3SHou Zhiqiang
5445684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/psci");
5545684ae3SHou Zhiqiang if (nodeoff >= 0)
5645684ae3SHou Zhiqiang goto init_psci_node;
5745684ae3SHou Zhiqiang
5845684ae3SHou Zhiqiang nodeoff = fdt_path_offset(fdt, "/");
5945684ae3SHou Zhiqiang if (nodeoff < 0)
6045684ae3SHou Zhiqiang return nodeoff;
6145684ae3SHou Zhiqiang
6245684ae3SHou Zhiqiang nodeoff = fdt_add_subnode(fdt, nodeoff, "psci");
6345684ae3SHou Zhiqiang if (nodeoff < 0)
6445684ae3SHou Zhiqiang return nodeoff;
6545684ae3SHou Zhiqiang
6645684ae3SHou Zhiqiang init_psci_node:
6745684ae3SHou Zhiqiang #ifdef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
6845684ae3SHou Zhiqiang psci_ver = sec_firmware_support_psci_version();
699a561753Smacro.wave.z@gmail.com #elif defined(CONFIG_ARMV7_PSCI_1_0) || defined(CONFIG_ARMV8_PSCI)
70bded2189SHou Zhiqiang psci_ver = ARM_PSCI_VER_1_0;
7145684ae3SHou Zhiqiang #endif
7245684ae3SHou Zhiqiang switch (psci_ver) {
732c774165SHou Zhiqiang case 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;
782c774165SHou Zhiqiang case ARM_PSCI_VER_0_2:
792c774165SHou Zhiqiang tmp = fdt_appendprop_string(fdt, nodeoff,
802c774165SHou Zhiqiang "compatible", "arm,psci-0.2");
812c774165SHou Zhiqiang if (tmp)
822c774165SHou Zhiqiang return tmp;
8345684ae3SHou Zhiqiang default:
842c774165SHou Zhiqiang /*
852c774165SHou Zhiqiang * The Secure firmware framework isn't able to support PSCI version 0.1.
862c774165SHou Zhiqiang */
872c774165SHou Zhiqiang #ifndef CONFIG_ARMV8_SEC_FIRMWARE_SUPPORT
882c774165SHou Zhiqiang tmp = fdt_appendprop_string(fdt, nodeoff,
892c774165SHou Zhiqiang "compatible", "arm,psci");
9045684ae3SHou Zhiqiang if (tmp)
9145684ae3SHou Zhiqiang return tmp;
9245684ae3SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_suspend",
9345684ae3SHou Zhiqiang ARM_PSCI_FN_CPU_SUSPEND);
9445684ae3SHou Zhiqiang if (tmp)
9545684ae3SHou Zhiqiang return tmp;
962c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_off",
972c774165SHou Zhiqiang ARM_PSCI_FN_CPU_OFF);
9845684ae3SHou Zhiqiang if (tmp)
9945684ae3SHou Zhiqiang return tmp;
1002c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "cpu_on",
1012c774165SHou Zhiqiang ARM_PSCI_FN_CPU_ON);
10245684ae3SHou Zhiqiang if (tmp)
10345684ae3SHou Zhiqiang return tmp;
1042c774165SHou Zhiqiang tmp = fdt_setprop_u32(fdt, nodeoff, "migrate",
1052c774165SHou Zhiqiang ARM_PSCI_FN_MIGRATE);
10645684ae3SHou Zhiqiang if (tmp)
10745684ae3SHou Zhiqiang return tmp;
10845684ae3SHou Zhiqiang #endif
1092c774165SHou Zhiqiang break;
1102c774165SHou Zhiqiang }
1112c774165SHou Zhiqiang
1122c774165SHou Zhiqiang tmp = fdt_setprop_string(fdt, nodeoff, "method", "smc");
1132c774165SHou Zhiqiang if (tmp)
1142c774165SHou Zhiqiang return tmp;
1152c774165SHou Zhiqiang
11645684ae3SHou Zhiqiang #endif
11745684ae3SHou Zhiqiang return 0;
11845684ae3SHou Zhiqiang }
119