1
/* Copyright 2013-2014 IBM Corp.
3
* Licensed under the Apache License, Version 2.0 (the "License");
4
* you may not use this file except in compliance with the License.
5
* You may obtain a copy of the License at
7
* http://www.apache.org/licenses/LICENSE-2.0
9
* Unless required by applicable law or agreed to in writing, software
10
* distributed under the License is distributed on an "AS IS" BASIS,
11
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
23
#include <interrupts.h>
27
#include <ccan/str/str.h>
33
#define FDT_DBG(fmt, a...) prlog(PR_DEBUG, "FDT: " fmt, ##a)
35
#define FDT_DBG(fmt, a...)
38
static void __save_err(int err, const char *str)
40
FDT_DBG("rc: %d from \"%s\"\n", err, str);
41
if (err && !fdt_error) {
42
prerror("FDT: Error %d from \"%s\"\n", err, str);
47
#define save_err(...) __save_err(__VA_ARGS__, #__VA_ARGS__)
49
static void dt_property_cell(void *fdt, const char *name, u32 cell)
51
save_err(fdt_property_cell(fdt, name, cell));
54
static void dt_begin_node(void *fdt, const struct dt_node *dn)
56
save_err(fdt_begin_node(fdt, dn->name));
58
dt_property_cell(fdt, "phandle", dn->phandle);
61
static void dt_property(void *fdt, const struct dt_property *p)
63
save_err(fdt_property(fdt, p->name, p->prop, p->len));
66
static void dt_end_node(void *fdt)
68
save_err(fdt_end_node(fdt));
72
static void dump_fdt(void *fdt)
74
int i, off, depth, err;
76
prlog(PR_INFO, "Device tree %u@%p\n", fdt_totalsize(fdt), fdt);
77
err = fdt_check_header(fdt);
79
prerror("fdt_check_header: %s\n", fdt_strerror(err));
82
prlog(PR_INFO, "fdt_check_header passed\n");
84
prlog(PR_INFO, "fdt_num_mem_rsv = %u\n", fdt_num_mem_rsv(fdt));
85
for (i = 0; i < fdt_num_mem_rsv(fdt); i++) {
88
err = fdt_get_mem_rsv(fdt, i, &addr, &size);
90
prlog(PR_INFO, " ERR %s\n", fdt_strerror(err));
93
prlog(PR_INFO, " mem_rsv[%i] = %lu@%#lx\n",
94
i, (long)addr, (long)size);
97
for (off = fdt_next_node(fdt, 0, &depth);
99
off = fdt_next_node(fdt, off, &depth)) {
103
name = fdt_get_name(fdt, off, &len);
105
prerror("fdt: offset %i no name!\n", off);
108
prlog(PR_INFO, "name: %s [%u]\n", name, off);
112
static inline void dump_fdt(void *fdt __unused) { }
115
static void flatten_dt_properties(void *fdt, const struct dt_node *dn)
117
const struct dt_property *p;
119
list_for_each(&dn->properties, p, list) {
120
if (strstarts(p->name, DT_PRIVATE))
123
FDT_DBG(" prop: %s size: %ld\n", p->name, p->len);
128
static void flatten_dt_node(void *fdt, const struct dt_node *root,
131
const struct dt_node *i;
134
FDT_DBG("node: %s\n", root->name);
135
dt_begin_node(fdt, root);
136
flatten_dt_properties(fdt, root);
139
list_for_each(&root->children, i, list)
140
flatten_dt_node(fdt, i, false);
146
static void create_dtb_reservemap(void *fdt, const struct dt_node *root)
149
const uint64_t *ranges;
150
const struct dt_property *prop;
153
/* Duplicate the reserved-ranges property into the fdt reservemap */
154
prop = dt_find_property(root, "reserved-ranges");
156
ranges = (const void *)prop->prop;
158
for (i = 0; i < prop->len / (sizeof(uint64_t) * 2); i++) {
161
save_err(fdt_add_reservemap_entry(fdt, base, size));
165
save_err(fdt_finish_reservemap(fdt));
168
static int __create_dtb(void *fdt, size_t len,
169
const struct dt_node *root,
172
fdt_create(fdt, len);
173
if (root == dt_root && !exclusive)
174
create_dtb_reservemap(fdt, root);
175
flatten_dt_node(fdt, root, exclusive);
177
save_err(fdt_finish(fdt));
179
prerror("dtb: error %s\n", fdt_strerror(fdt_error));
187
void *create_dtb(const struct dt_node *root, bool exclusive)
190
size_t len = DEVICE_TREE_MAX_SIZE;
191
uint32_t old_last_phandle = last_phandle;
195
last_phandle = old_last_phandle;
199
prerror("dtb: could not malloc %lu\n", (long)len);
203
ret = __create_dtb(fdt, len, root, exclusive);
210
} while (ret == -FDT_ERR_NOSPACE);
215
static int64_t opal_get_device_tree(uint32_t phandle,
216
uint64_t buf, uint64_t len)
218
struct dt_node *root;
219
void *fdt = (void *)buf;
220
uint32_t old_last_phandle;
224
root = dt_find_by_phandle(dt_root, phandle);
226
return OPAL_PARAMETER;
229
fdt = create_dtb(root, true);
231
return OPAL_INTERNAL_ERROR;
232
totalsize = fdt_totalsize(fdt);
238
return OPAL_PARAMETER;
241
old_last_phandle = last_phandle;
242
ret = __create_dtb(fdt, len, root, true);
244
last_phandle = old_last_phandle;
245
if (ret == -FDT_ERR_NOSPACE)
253
opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);