xref: /optee_os/core/kernel/dt.c (revision 77327d7a47019cf9f66972403d0de1c32fe4cdee)
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3  * Copyright (c) 2016, Linaro Limited
4  */
5 
6 #include <assert.h>
7 #include <kernel/dt.h>
8 #include <kernel/linker.h>
9 #include <libfdt.h>
10 #include <mm/core_memprot.h>
11 #include <mm/core_mmu.h>
12 #include <string.h>
13 #include <trace.h>
14 
15 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
16 {
17 	const struct dt_device_match *dm;
18 	const struct dt_driver *drv;
19 
20 	for_each_dt_driver(drv) {
21 		for (dm = drv->match_table; dm; dm++) {
22 			if (!dm->compatible) {
23 				break;
24 			}
25 			if (!fdt_node_check_compatible(fdt, offs,
26 						       dm->compatible)) {
27 				return drv;
28 			}
29 		}
30 	}
31 
32 	return NULL;
33 }
34 
35 const struct dt_driver *__dt_driver_start(void)
36 {
37 	return &__rodata_dtdrv_start;
38 }
39 
40 const struct dt_driver *__dt_driver_end(void)
41 {
42 	return &__rodata_dtdrv_end;
43 }
44 
45 bool dt_have_prop(const void *fdt, int offs, const char *propname)
46 {
47 	const void *prop;
48 
49 	prop = fdt_getprop(fdt, offs, propname, NULL);
50 
51 	return prop;
52 }
53 
54 int dt_map_dev(const void *fdt, int offs, vaddr_t *base, size_t *size)
55 {
56 	enum teecore_memtypes mtype;
57 	paddr_t pbase;
58 	vaddr_t vbase;
59 	ssize_t sz;
60 	int st;
61 
62 	assert(cpu_mmu_enabled());
63 
64 	st = _fdt_get_status(fdt, offs);
65 	if (st == DT_STATUS_DISABLED)
66 		return -1;
67 
68 	pbase = _fdt_reg_base_address(fdt, offs);
69 	if (pbase == DT_INFO_INVALID_REG)
70 		return -1;
71 	sz = _fdt_reg_size(fdt, offs);
72 	if (sz < 0)
73 		return -1;
74 
75 	if ((st & DT_STATUS_OK_SEC) && !(st & DT_STATUS_OK_NSEC))
76 		mtype = MEM_AREA_IO_SEC;
77 	else
78 		mtype = MEM_AREA_IO_NSEC;
79 
80 	/* Check if we have a mapping, create one if needed */
81 	if (!core_mmu_add_mapping(mtype, pbase, sz)) {
82 		EMSG("Failed to map %zu bytes at PA 0x%"PRIxPA,
83 		     (size_t)sz, pbase);
84 		return -1;
85 	}
86 	vbase = (vaddr_t)phys_to_virt(pbase, mtype);
87 	if (!vbase) {
88 		EMSG("Failed to get VA for PA 0x%"PRIxPA, pbase);
89 		return -1;
90 	}
91 
92 	*base = vbase;
93 	*size = sz;
94 	return 0;
95 }
96 
97 /* Read a physical address (n=1 or 2 cells) */
98 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n)
99 {
100 	paddr_t addr;
101 
102 	if (n < 1 || n > 2)
103 		goto bad;
104 
105 	addr = fdt32_to_cpu(*cell);
106 	cell++;
107 	if (n == 2) {
108 #ifdef ARM32
109 		if (addr) {
110 			/* High order 32 bits can't be nonzero */
111 			goto bad;
112 		}
113 		addr = fdt32_to_cpu(*cell);
114 #else
115 		addr = (addr << 32) | fdt32_to_cpu(*cell);
116 #endif
117 	}
118 
119 	if (!addr)
120 		goto bad;
121 
122 	return addr;
123 bad:
124 	return DT_INFO_INVALID_REG;
125 
126 }
127 
128 paddr_t _fdt_reg_base_address(const void *fdt, int offs)
129 {
130 	const void *reg;
131 	int ncells;
132 	int len;
133 	int parent;
134 
135 	parent = fdt_parent_offset(fdt, offs);
136 	if (parent < 0)
137 		return DT_INFO_INVALID_REG;
138 
139 	reg = fdt_getprop(fdt, offs, "reg", &len);
140 	if (!reg)
141 		return DT_INFO_INVALID_REG;
142 
143 	ncells = fdt_address_cells(fdt, parent);
144 	if (ncells < 0)
145 		return DT_INFO_INVALID_REG;
146 
147 	return _fdt_read_paddr(reg, ncells);
148 }
149 
150 ssize_t _fdt_reg_size(const void *fdt, int offs)
151 {
152 	const uint32_t *reg;
153 	uint32_t sz;
154 	int n;
155 	int len;
156 	int parent;
157 
158 	parent = fdt_parent_offset(fdt, offs);
159 	if (parent < 0)
160 		return DT_INFO_INVALID_REG;
161 
162 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
163 	if (!reg)
164 		return -1;
165 
166 	n = fdt_address_cells(fdt, parent);
167 	if (n < 1 || n > 2)
168 		return -1;
169 
170 	reg += n;
171 
172 	n = fdt_size_cells(fdt, parent);
173 	if (n < 1 || n > 2)
174 		return -1;
175 
176 	sz = fdt32_to_cpu(*reg);
177 	if (n == 2) {
178 		if (sz)
179 			return -1;
180 		reg++;
181 		sz = fdt32_to_cpu(*reg);
182 	}
183 
184 	return sz;
185 }
186 
187 static bool is_okay(const char *st, int len)
188 {
189 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
190 }
191 
192 int _fdt_get_status(const void *fdt, int offs)
193 {
194 	const char *prop;
195 	int st = 0;
196 	int len;
197 
198 	prop = fdt_getprop(fdt, offs, "status", &len);
199 	if (!prop || is_okay(prop, len)) {
200 		/* If status is not specified, it defaults to "okay" */
201 		st |= DT_STATUS_OK_NSEC;
202 	}
203 
204 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
205 	if (!prop) {
206 		/*
207 		 * When secure-status is not specified it defaults to the same
208 		 * value as status
209 		 */
210 		if (st & DT_STATUS_OK_NSEC)
211 			st |= DT_STATUS_OK_SEC;
212 	} else {
213 		if (is_okay(prop, len))
214 			st |= DT_STATUS_OK_SEC;
215 	}
216 
217 	return st;
218 }
219 
220 void _fdt_fill_device_info(void *fdt, struct dt_node_info *info, int offs)
221 {
222 	struct dt_node_info dinfo = {
223 		.reg = DT_INFO_INVALID_REG,
224 		.clock = DT_INFO_INVALID_CLOCK,
225 		.reset = DT_INFO_INVALID_RESET,
226 	};
227 	const fdt32_t *cuint;
228 
229 	dinfo.reg = _fdt_reg_base_address(fdt, offs);
230 
231 	cuint = fdt_getprop(fdt, offs, "clocks", NULL);
232 	if (cuint) {
233 		cuint++;
234 		dinfo.clock = (int)fdt32_to_cpu(*cuint);
235 	}
236 
237 	cuint = fdt_getprop(fdt, offs, "resets", NULL);
238 	if (cuint) {
239 		cuint++;
240 		dinfo.reset = (int)fdt32_to_cpu(*cuint);
241 	}
242 
243 	dinfo.status = _fdt_get_status(fdt, offs);
244 
245 	*info = dinfo;
246 }
247