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