drm/rockchip: vop2: Fix the windows switch between different layers
[drm/drm-misc.git] / arch / riscv / kernel / pi / fdt_early.c
blob9bdee2fafe47e4a889132ebe2d0d360717c464e9
1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/types.h>
3 #include <linux/init.h>
4 #include <linux/libfdt.h>
5 #include <linux/ctype.h>
7 #include "pi.h"
9 u64 get_kaslr_seed(uintptr_t dtb_pa)
11 int node, len;
12 fdt64_t *prop;
13 u64 ret;
15 node = fdt_path_offset((void *)dtb_pa, "/chosen");
16 if (node < 0)
17 return 0;
19 prop = fdt_getprop_w((void *)dtb_pa, node, "kaslr-seed", &len);
20 if (!prop || len != sizeof(u64))
21 return 0;
23 ret = fdt64_to_cpu(*prop);
24 *prop = 0;
25 return ret;
28 /**
29 * fdt_device_is_available - check if a device is available for use
31 * @fdt: pointer to the device tree blob
32 * @node: offset of the node whose property to find
34 * Returns true if the status property is absent or set to "okay" or "ok",
35 * false otherwise
37 static bool fdt_device_is_available(const void *fdt, int node)
39 const char *status;
40 int statlen;
42 status = fdt_getprop(fdt, node, "status", &statlen);
43 if (!status)
44 return true;
46 if (statlen > 0) {
47 if (!strcmp(status, "okay") || !strcmp(status, "ok"))
48 return true;
51 return false;
54 /* Copy of fdt_nodename_eq_ */
55 static int fdt_node_name_eq(const void *fdt, int offset,
56 const char *s)
58 int olen;
59 int len = strlen(s);
60 const char *p = fdt_get_name(fdt, offset, &olen);
62 if (!p || olen < len)
63 /* short match */
64 return 0;
66 if (memcmp(p, s, len) != 0)
67 return 0;
69 if (p[len] == '\0')
70 return 1;
71 else if (!memchr(s, '@', len) && (p[len] == '@'))
72 return 1;
73 else
74 return 0;
77 /**
78 * isa_string_contains - check if isa string contains an extension
80 * @isa_str: isa string to search
81 * @ext_name: the extension to search for
83 * Returns true if the extension is in the given isa string,
84 * false otherwise
86 static bool isa_string_contains(const char *isa_str, const char *ext_name)
88 size_t i, single_end, len = strlen(ext_name);
89 char ext_end;
91 /* Error must contain rv32/64 */
92 if (strlen(isa_str) < 4)
93 return false;
95 if (len == 1) {
96 single_end = strcspn(isa_str, "sSxXzZ");
97 /* Search for single chars between rv32/64 and multi-letter extensions */
98 for (i = 4; i < single_end; i++) {
99 if (tolower(isa_str[i]) == ext_name[0])
100 return true;
102 return false;
105 /* Skip to start of multi-letter extensions */
106 isa_str = strpbrk(isa_str, "sSxXzZ");
107 while (isa_str) {
108 if (strncasecmp(isa_str, ext_name, len) == 0) {
109 ext_end = isa_str[len];
110 /* Check if matches the whole extension. */
111 if (ext_end == '\0' || ext_end == '_')
112 return true;
114 /* Multi-letter extensions must be split from other multi-letter
115 * extensions with an "_", the end of a multi-letter extension will
116 * either be the null character or the "_" at the start of the next
117 * multi-letter extension.
119 isa_str = strchr(isa_str, '_');
120 if (isa_str)
121 isa_str++;
124 return false;
128 * early_cpu_isa_ext_available - check if cpu node has an extension
130 * @fdt: pointer to the device tree blob
131 * @node: offset of the cpu node
132 * @ext_name: the extension to search for
134 * Returns true if the cpu node has the extension,
135 * false otherwise
137 static bool early_cpu_isa_ext_available(const void *fdt, int node, const char *ext_name)
139 const void *prop;
140 int len;
142 prop = fdt_getprop(fdt, node, "riscv,isa-extensions", &len);
143 if (prop && fdt_stringlist_contains(prop, len, ext_name))
144 return true;
146 prop = fdt_getprop(fdt, node, "riscv,isa", &len);
147 if (prop && isa_string_contains(prop, ext_name))
148 return true;
150 return false;
154 * fdt_early_match_extension_isa - check if all cpu nodes have an extension
156 * @fdt: pointer to the device tree blob
157 * @ext_name: the extension to search for
159 * Returns true if the all available the cpu nodes have the extension,
160 * false otherwise
162 bool fdt_early_match_extension_isa(const void *fdt, const char *ext_name)
164 int node, parent;
165 bool ret = false;
167 parent = fdt_path_offset(fdt, "/cpus");
168 if (parent < 0)
169 return false;
171 fdt_for_each_subnode(node, fdt, parent) {
172 if (!fdt_node_name_eq(fdt, node, "cpu"))
173 continue;
175 if (!fdt_device_is_available(fdt, node))
176 continue;
178 if (!early_cpu_isa_ext_available(fdt, node, ext_name))
179 return false;
181 ret = true;
184 return ret;