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