xref: /optee_os/core/kernel/dt.c (revision 9fe4c79784dbccb3eaa561e3ccd81855c675ee12)
1 /*
2  * Copyright (c) 2016, Linaro Limited
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <kernel/dt.h>
29 #include <libfdt.h>
30 #include <string.h>
31 
32 const struct dt_driver *dt_find_compatible_driver(const void *fdt, int offs)
33 {
34 	const struct dt_device_match *dm;
35 	const struct dt_driver *drv;
36 
37 	for_each_dt_driver(drv)
38 		for (dm = drv->match_table; dm; dm++)
39 			if (!fdt_node_check_compatible(fdt, offs,
40 						       dm->compatible))
41 				return drv;
42 
43 	return NULL;
44 }
45 
46 const struct dt_driver *__dt_driver_start(void)
47 {
48 	return &__rodata_dtdrv_start;
49 }
50 
51 const struct dt_driver *__dt_driver_end(void)
52 {
53 	return &__rodata_dtdrv_end;
54 }
55 
56 /* Read a physical address (n=1 or 2 cells) */
57 static paddr_t _fdt_read_paddr(const uint32_t *cell, int n)
58 {
59 	paddr_t addr;
60 
61 	if (n < 1 || n > 2)
62 		goto bad;
63 
64 	addr = fdt32_to_cpu(*cell);
65 	cell++;
66 	if (n == 2) {
67 #ifdef ARM32
68 		if (addr) {
69 			/* High order 32 bits can't be nonzero */
70 			goto bad;
71 		}
72 		addr = fdt32_to_cpu(*cell);
73 #else
74 		addr = (addr << 32) | fdt32_to_cpu(*cell);
75 #endif
76 	}
77 
78 	if (!addr)
79 		goto bad;
80 
81 	return addr;
82 bad:
83 	return (paddr_t)-1;
84 
85 }
86 
87 paddr_t _fdt_reg_base_address(const void *fdt, int offs)
88 {
89 	const void *reg;
90 	int ncells;
91 	int len;
92 
93 	reg = fdt_getprop(fdt, offs, "reg", &len);
94 	if (!reg)
95 		return (paddr_t)-1;
96 
97 	ncells = fdt_address_cells(fdt, offs);
98 	if (ncells < 0)
99 		return (paddr_t)-1;
100 
101 	return _fdt_read_paddr(reg, ncells);
102 }
103 
104 ssize_t _fdt_reg_size(const void *fdt, int offs)
105 {
106 	const uint32_t *reg;
107 	uint32_t sz;
108 	int n;
109 	int len;
110 
111 	reg = (const uint32_t *)fdt_getprop(fdt, offs, "reg", &len);
112 	if (!reg)
113 		return -1;
114 
115 	n = fdt_address_cells(fdt, offs);
116 	if (n < 1 || n > 2)
117 		return -1;
118 
119 	reg += n;
120 
121 	n = fdt_size_cells(fdt, offs);
122 	if (n < 1 || n > 2)
123 		return -1;
124 
125 	sz = fdt32_to_cpu(*reg);
126 	if (n == 2) {
127 		if (sz)
128 			return -1;
129 		reg++;
130 		sz = fdt32_to_cpu(*reg);
131 	}
132 
133 	return sz;
134 }
135 
136 static bool is_okay(const char *st, int len)
137 {
138 	return !strncmp(st, "ok", len) || !strncmp(st, "okay", len);
139 }
140 
141 int _fdt_get_status(const void *fdt, int offs)
142 {
143 	const char *prop;
144 	int st = 0;
145 	int len;
146 
147 	prop = fdt_getprop(fdt, offs, "status", &len);
148 	if (!prop || is_okay(prop, len)) {
149 		/* If status is not specified, it defaults to "okay" */
150 		st |= DT_STATUS_OK_NSEC;
151 	}
152 
153 	prop = fdt_getprop(fdt, offs, "secure-status", &len);
154 	if (!prop) {
155 		/*
156 		 * When secure-status is not specified it defaults to the same
157 		 * value as status
158 		 */
159 		if (st & DT_STATUS_OK_NSEC)
160 			st |= DT_STATUS_OK_SEC;
161 	} else {
162 		if (is_okay(prop, len))
163 			st |= DT_STATUS_OK_SEC;
164 	}
165 
166 	return st;
167 }
168