blob: b1cd368cb593d22363657820ff5c00063bf3d27c [file] [log] [blame]
Jens Wiklander52c798e2015-12-07 14:37:10 +01001/*
2 * Copyright (c) 2016, ARM Limited and Contributors. All rights reserved.
3 *
dp-armfa3cf0b2017-05-03 09:38:09 +01004 * SPDX-License-Identifier: BSD-3-Clause
Jens Wiklander52c798e2015-12-07 14:37:10 +01005 */
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00006
Jens Wiklander52c798e2015-12-07 14:37:10 +01007#include <string.h>
Antonio Nino Diaze0f90632018-12-14 00:18:21 +00008
9#include <libfdt.h>
10
11#include <common/debug.h>
12#include <drivers/console.h>
13#include <lib/psci/psci.h>
14
Isla Mitchelle3631462017-07-14 10:46:32 +010015#include "qemu_private.h"
Jens Wiklander52c798e2015-12-07 14:37:10 +010016
17static int append_psci_compatible(void *fdt, int offs, const char *str)
18{
19 return fdt_appendprop(fdt, offs, "compatible", str, strlen(str) + 1);
20}
21
22int dt_add_psci_node(void *fdt)
23{
24 int offs;
25
26 if (fdt_path_offset(fdt, "/psci") >= 0) {
27 WARN("PSCI Device Tree node already exists!\n");
28 return 0;
29 }
30
31 offs = fdt_path_offset(fdt, "/");
32 if (offs < 0)
33 return -1;
34 offs = fdt_add_subnode(fdt, offs, "psci");
35 if (offs < 0)
36 return -1;
37 if (append_psci_compatible(fdt, offs, "arm,psci-1.0"))
38 return -1;
39 if (append_psci_compatible(fdt, offs, "arm,psci-0.2"))
40 return -1;
41 if (append_psci_compatible(fdt, offs, "arm,psci"))
42 return -1;
43 if (fdt_setprop_string(fdt, offs, "method", "smc"))
44 return -1;
45 if (fdt_setprop_u32(fdt, offs, "cpu_suspend", PSCI_CPU_SUSPEND_AARCH64))
46 return -1;
47 if (fdt_setprop_u32(fdt, offs, "cpu_off", PSCI_CPU_OFF))
48 return -1;
49 if (fdt_setprop_u32(fdt, offs, "cpu_on", PSCI_CPU_ON_AARCH64))
50 return -1;
51 if (fdt_setprop_u32(fdt, offs, "sys_poweroff", PSCI_SYSTEM_OFF))
52 return -1;
53 if (fdt_setprop_u32(fdt, offs, "sys_reset", PSCI_SYSTEM_RESET))
54 return -1;
55 return 0;
56}
57
58static int check_node_compat_prefix(void *fdt, int offs, const char *prefix)
59{
60 const size_t prefix_len = strlen(prefix);
61 size_t l;
62 int plen;
63 const char *prop;
64
65 prop = fdt_getprop(fdt, offs, "compatible", &plen);
66 if (!prop)
67 return -1;
68
69 while (plen > 0) {
70 if (memcmp(prop, prefix, prefix_len) == 0)
71 return 0; /* match */
72
73 l = strlen(prop) + 1;
74 prop += l;
75 plen -= l;
76 }
77
78 return -1;
79}
80
81int dt_add_psci_cpu_enable_methods(void *fdt)
82{
83 int offs = 0;
84
85 while (1) {
86 offs = fdt_next_node(fdt, offs, NULL);
87 if (offs < 0)
88 break;
89 if (fdt_getprop(fdt, offs, "enable-method", NULL))
90 continue; /* already set */
91 if (check_node_compat_prefix(fdt, offs, "arm,cortex-a"))
92 continue; /* no compatible */
93 if (fdt_setprop_string(fdt, offs, "enable-method", "psci"))
94 return -1;
95 /* Need to restart scanning as offsets may have changed */
96 offs = 0;
97 }
98 return 0;
99}