fdt_subr.c revision 1.1 1 1.1 jmcneill /* $NetBSD: fdt_subr.c,v 1.1 2015/12/13 17:30:40 jmcneill Exp $ */
2 1.1 jmcneill
3 1.1 jmcneill /*-
4 1.1 jmcneill * Copyright (c) 2015 Jared D. McNeill <jmcneill (at) invisible.ca>
5 1.1 jmcneill * All rights reserved.
6 1.1 jmcneill *
7 1.1 jmcneill * Redistribution and use in source and binary forms, with or without
8 1.1 jmcneill * modification, are permitted provided that the following conditions
9 1.1 jmcneill * are met:
10 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright
11 1.1 jmcneill * notice, this list of conditions and the following disclaimer.
12 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the
14 1.1 jmcneill * documentation and/or other materials provided with the distribution.
15 1.1 jmcneill *
16 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 jmcneill * SUCH DAMAGE.
27 1.1 jmcneill */
28 1.1 jmcneill
29 1.1 jmcneill #include <sys/cdefs.h>
30 1.1 jmcneill __KERNEL_RCSID(0, "$NetBSD: fdt_subr.c,v 1.1 2015/12/13 17:30:40 jmcneill Exp $");
31 1.1 jmcneill
32 1.1 jmcneill #include <sys/param.h>
33 1.1 jmcneill #include <sys/bus.h>
34 1.1 jmcneill #include <sys/kmem.h>
35 1.1 jmcneill
36 1.1 jmcneill #include <libfdt.h>
37 1.1 jmcneill #include <dev/ofw/openfirm.h>
38 1.1 jmcneill #include <dev/fdt/fdt_openfirm.h>
39 1.1 jmcneill #include <dev/fdt/fdtvar.h>
40 1.1 jmcneill
41 1.1 jmcneill struct fdtbus_interrupt_controller {
42 1.1 jmcneill device_t ic_dev;
43 1.1 jmcneill int ic_phandle;
44 1.1 jmcneill const struct fdtbus_interrupt_controller_func *ic_funcs;
45 1.1 jmcneill
46 1.1 jmcneill struct fdtbus_interrupt_controller *ic_next;
47 1.1 jmcneill };
48 1.1 jmcneill
49 1.1 jmcneill static struct fdtbus_interrupt_controller *fdtbus_ic = NULL;
50 1.1 jmcneill
51 1.1 jmcneill struct fdtbus_i2c_controller {
52 1.1 jmcneill device_t i2c_dev;
53 1.1 jmcneill int i2c_phandle;
54 1.1 jmcneill const struct fdtbus_i2c_controller_func *i2c_funcs;
55 1.1 jmcneill
56 1.1 jmcneill struct fdtbus_i2c_controller *i2c_next;
57 1.1 jmcneill };
58 1.1 jmcneill
59 1.1 jmcneill static struct fdtbus_i2c_controller *fdtbus_i2c = NULL;
60 1.1 jmcneill
61 1.1 jmcneill struct fdtbus_gpio_controller {
62 1.1 jmcneill device_t gc_dev;
63 1.1 jmcneill int gc_phandle;
64 1.1 jmcneill const struct fdtbus_gpio_controller_func *gc_funcs;
65 1.1 jmcneill
66 1.1 jmcneill struct fdtbus_gpio_controller *gc_next;
67 1.1 jmcneill };
68 1.1 jmcneill
69 1.1 jmcneill static struct fdtbus_gpio_controller *fdtbus_gc = NULL;
70 1.1 jmcneill
71 1.1 jmcneill struct fdtbus_regulator_controller {
72 1.1 jmcneill device_t rc_dev;
73 1.1 jmcneill int rc_phandle;
74 1.1 jmcneill const struct fdtbus_regulator_controller_func *rc_funcs;
75 1.1 jmcneill
76 1.1 jmcneill struct fdtbus_regulator_controller *rc_next;
77 1.1 jmcneill };
78 1.1 jmcneill
79 1.1 jmcneill static struct fdtbus_regulator_controller *fdtbus_rc = NULL;
80 1.1 jmcneill
81 1.1 jmcneill static int
82 1.1 jmcneill fdtbus_get_addr_cells(int phandle)
83 1.1 jmcneill {
84 1.1 jmcneill int val, addr_cells, error;
85 1.1 jmcneill
86 1.1 jmcneill const int parent = OF_parent(phandle);
87 1.1 jmcneill if (parent == -1)
88 1.1 jmcneill return -1;
89 1.1 jmcneill
90 1.1 jmcneill error = OF_getprop(parent, "#address-cells", &val, sizeof(val));
91 1.1 jmcneill if (error <= 0) {
92 1.1 jmcneill addr_cells = 2;
93 1.1 jmcneill } else {
94 1.1 jmcneill addr_cells = fdt32_to_cpu(val);
95 1.1 jmcneill }
96 1.1 jmcneill
97 1.1 jmcneill return addr_cells;
98 1.1 jmcneill }
99 1.1 jmcneill
100 1.1 jmcneill static int
101 1.1 jmcneill fdtbus_get_size_cells(int phandle)
102 1.1 jmcneill {
103 1.1 jmcneill int val, size_cells, error;
104 1.1 jmcneill
105 1.1 jmcneill const int parent = OF_parent(phandle);
106 1.1 jmcneill if (parent == -1)
107 1.1 jmcneill return -1;
108 1.1 jmcneill
109 1.1 jmcneill error = OF_getprop(parent, "#size-cells", &val, sizeof(val));
110 1.1 jmcneill if (error <= 0) {
111 1.1 jmcneill size_cells = 0;
112 1.1 jmcneill } else {
113 1.1 jmcneill size_cells = fdt32_to_cpu(val);
114 1.1 jmcneill }
115 1.1 jmcneill
116 1.1 jmcneill return size_cells;
117 1.1 jmcneill }
118 1.1 jmcneill
119 1.1 jmcneill static int
120 1.1 jmcneill fdtbus_get_interrupt_parent(int phandle)
121 1.1 jmcneill {
122 1.1 jmcneill u_int interrupt_parent;
123 1.1 jmcneill int len;
124 1.1 jmcneill
125 1.1 jmcneill while (phandle >= 0) {
126 1.1 jmcneill len = OF_getprop(phandle, "interrupt-parent",
127 1.1 jmcneill &interrupt_parent, sizeof(interrupt_parent));
128 1.1 jmcneill if (len == sizeof(interrupt_parent)) {
129 1.1 jmcneill break;
130 1.1 jmcneill }
131 1.1 jmcneill if (phandle == 0) {
132 1.1 jmcneill return -1;
133 1.1 jmcneill }
134 1.1 jmcneill phandle = OF_parent(phandle);
135 1.1 jmcneill }
136 1.1 jmcneill if (phandle < 0) {
137 1.1 jmcneill return -1;
138 1.1 jmcneill }
139 1.1 jmcneill
140 1.1 jmcneill interrupt_parent = fdt32_to_cpu(interrupt_parent);
141 1.1 jmcneill
142 1.1 jmcneill const void *data = fdt_openfirm_get_data();
143 1.1 jmcneill const int off = fdt_node_offset_by_phandle(data, interrupt_parent);
144 1.1 jmcneill if (off < 0) {
145 1.1 jmcneill return -1;
146 1.1 jmcneill }
147 1.1 jmcneill
148 1.1 jmcneill return fdt_openfirm_get_phandle(off);
149 1.1 jmcneill }
150 1.1 jmcneill
151 1.1 jmcneill static struct fdtbus_interrupt_controller *
152 1.1 jmcneill fdtbus_get_interrupt_controller(int phandle)
153 1.1 jmcneill {
154 1.1 jmcneill struct fdtbus_interrupt_controller *ic;
155 1.1 jmcneill
156 1.1 jmcneill const int ic_phandle = fdtbus_get_interrupt_parent(phandle);
157 1.1 jmcneill if (ic_phandle < 0) {
158 1.1 jmcneill return NULL;
159 1.1 jmcneill }
160 1.1 jmcneill
161 1.1 jmcneill for (ic = fdtbus_ic; ic; ic = ic->ic_next) {
162 1.1 jmcneill if (ic->ic_phandle == ic_phandle) {
163 1.1 jmcneill return ic;
164 1.1 jmcneill }
165 1.1 jmcneill }
166 1.1 jmcneill
167 1.1 jmcneill return NULL;
168 1.1 jmcneill }
169 1.1 jmcneill
170 1.1 jmcneill int
171 1.1 jmcneill fdtbus_register_interrupt_controller(device_t dev, int phandle,
172 1.1 jmcneill const struct fdtbus_interrupt_controller_func *funcs)
173 1.1 jmcneill {
174 1.1 jmcneill struct fdtbus_interrupt_controller *ic;
175 1.1 jmcneill
176 1.1 jmcneill ic = kmem_alloc(sizeof(*ic), KM_SLEEP);
177 1.1 jmcneill ic->ic_dev = dev;
178 1.1 jmcneill ic->ic_phandle = phandle;
179 1.1 jmcneill ic->ic_funcs = funcs;
180 1.1 jmcneill
181 1.1 jmcneill ic->ic_next = fdtbus_ic;
182 1.1 jmcneill fdtbus_ic = ic;
183 1.1 jmcneill
184 1.1 jmcneill return 0;
185 1.1 jmcneill }
186 1.1 jmcneill
187 1.1 jmcneill void *
188 1.1 jmcneill fdtbus_intr_establish(int phandle, u_int index, int ipl, int flags,
189 1.1 jmcneill int (*func)(void *), void *arg)
190 1.1 jmcneill {
191 1.1 jmcneill struct fdtbus_interrupt_controller *ic;
192 1.1 jmcneill
193 1.1 jmcneill ic = fdtbus_get_interrupt_controller(phandle);
194 1.1 jmcneill if (ic == NULL)
195 1.1 jmcneill return NULL;
196 1.1 jmcneill
197 1.1 jmcneill return ic->ic_funcs->establish(ic->ic_dev, phandle, index, ipl,
198 1.1 jmcneill flags, func, arg);
199 1.1 jmcneill }
200 1.1 jmcneill
201 1.1 jmcneill void
202 1.1 jmcneill fdtbus_intr_disestablish(int phandle, void *ih)
203 1.1 jmcneill {
204 1.1 jmcneill struct fdtbus_interrupt_controller *ic;
205 1.1 jmcneill
206 1.1 jmcneill ic = fdtbus_get_interrupt_controller(phandle);
207 1.1 jmcneill KASSERT(ic != NULL);
208 1.1 jmcneill
209 1.1 jmcneill return ic->ic_funcs->disestablish(ic->ic_dev, ih);
210 1.1 jmcneill }
211 1.1 jmcneill
212 1.1 jmcneill bool
213 1.1 jmcneill fdtbus_intr_str(int phandle, u_int index, char *buf, size_t buflen)
214 1.1 jmcneill {
215 1.1 jmcneill struct fdtbus_interrupt_controller *ic;
216 1.1 jmcneill
217 1.1 jmcneill ic = fdtbus_get_interrupt_controller(phandle);
218 1.1 jmcneill if (ic == NULL)
219 1.1 jmcneill return false;
220 1.1 jmcneill
221 1.1 jmcneill return ic->ic_funcs->intrstr(ic->ic_dev, phandle, index, buf, buflen);
222 1.1 jmcneill }
223 1.1 jmcneill
224 1.1 jmcneill int
225 1.1 jmcneill fdtbus_register_gpio_controller(device_t dev, int phandle,
226 1.1 jmcneill const struct fdtbus_gpio_controller_func *funcs)
227 1.1 jmcneill {
228 1.1 jmcneill struct fdtbus_gpio_controller *gc;
229 1.1 jmcneill
230 1.1 jmcneill gc = kmem_alloc(sizeof(*gc), KM_SLEEP);
231 1.1 jmcneill gc->gc_dev = dev;
232 1.1 jmcneill gc->gc_phandle = phandle;
233 1.1 jmcneill gc->gc_funcs = funcs;
234 1.1 jmcneill
235 1.1 jmcneill gc->gc_next = fdtbus_gc;
236 1.1 jmcneill fdtbus_gc = gc;
237 1.1 jmcneill
238 1.1 jmcneill return 0;
239 1.1 jmcneill }
240 1.1 jmcneill
241 1.1 jmcneill static struct fdtbus_gpio_controller *
242 1.1 jmcneill fdtbus_get_gpio_controller(int phandle)
243 1.1 jmcneill {
244 1.1 jmcneill struct fdtbus_gpio_controller *gc;
245 1.1 jmcneill
246 1.1 jmcneill for (gc = fdtbus_gc; gc; gc = gc->gc_next) {
247 1.1 jmcneill if (gc->gc_phandle == phandle) {
248 1.1 jmcneill return gc;
249 1.1 jmcneill }
250 1.1 jmcneill }
251 1.1 jmcneill
252 1.1 jmcneill return NULL;
253 1.1 jmcneill }
254 1.1 jmcneill
255 1.1 jmcneill struct fdtbus_gpio_pin *
256 1.1 jmcneill fdtbus_gpio_acquire(int phandle, const char *prop, int flags)
257 1.1 jmcneill {
258 1.1 jmcneill struct fdtbus_gpio_controller *gc;
259 1.1 jmcneill struct fdtbus_gpio_pin *gp;
260 1.1 jmcneill int gpio_phandle, len;
261 1.1 jmcneill u_int *data;
262 1.1 jmcneill
263 1.1 jmcneill gpio_phandle = fdtbus_get_phandle(phandle, prop);
264 1.1 jmcneill if (gpio_phandle == -1) {
265 1.1 jmcneill return NULL;
266 1.1 jmcneill }
267 1.1 jmcneill
268 1.1 jmcneill gc = fdtbus_get_gpio_controller(gpio_phandle);
269 1.1 jmcneill if (gc == NULL) {
270 1.1 jmcneill return NULL;
271 1.1 jmcneill }
272 1.1 jmcneill
273 1.1 jmcneill len = OF_getproplen(phandle, prop);
274 1.1 jmcneill if (len < 4) {
275 1.1 jmcneill return NULL;
276 1.1 jmcneill }
277 1.1 jmcneill
278 1.1 jmcneill data = kmem_alloc(len, KM_SLEEP);
279 1.1 jmcneill if (OF_getprop(phandle, prop, data, len) != len) {
280 1.1 jmcneill kmem_free(data, len);
281 1.1 jmcneill return NULL;
282 1.1 jmcneill }
283 1.1 jmcneill
284 1.1 jmcneill gp = kmem_alloc(sizeof(*gp), KM_SLEEP);
285 1.1 jmcneill gp->gp_gc = gc;
286 1.1 jmcneill gp->gp_priv = gc->gc_funcs->acquire(gc->gc_dev, data, len, flags);
287 1.1 jmcneill if (gp->gp_priv == NULL) {
288 1.1 jmcneill kmem_free(data, len);
289 1.1 jmcneill return NULL;
290 1.1 jmcneill }
291 1.1 jmcneill
292 1.1 jmcneill return gp;
293 1.1 jmcneill }
294 1.1 jmcneill
295 1.1 jmcneill void
296 1.1 jmcneill fdtbus_gpio_release(struct fdtbus_gpio_pin *gp)
297 1.1 jmcneill {
298 1.1 jmcneill struct fdtbus_gpio_controller *gc = gp->gp_gc;
299 1.1 jmcneill
300 1.1 jmcneill gc->gc_funcs->release(gc->gc_dev, gp->gp_priv);
301 1.1 jmcneill kmem_free(gp, sizeof(*gp));
302 1.1 jmcneill }
303 1.1 jmcneill
304 1.1 jmcneill int
305 1.1 jmcneill fdtbus_gpio_read(struct fdtbus_gpio_pin *gp)
306 1.1 jmcneill {
307 1.1 jmcneill struct fdtbus_gpio_controller *gc = gp->gp_gc;
308 1.1 jmcneill
309 1.1 jmcneill return gc->gc_funcs->read(gc->gc_dev, gp->gp_priv);
310 1.1 jmcneill }
311 1.1 jmcneill
312 1.1 jmcneill void
313 1.1 jmcneill fdtbus_gpio_write(struct fdtbus_gpio_pin *gp, int val)
314 1.1 jmcneill {
315 1.1 jmcneill struct fdtbus_gpio_controller *gc = gp->gp_gc;
316 1.1 jmcneill
317 1.1 jmcneill gc->gc_funcs->write(gc->gc_dev, gp->gp_priv, val);
318 1.1 jmcneill }
319 1.1 jmcneill
320 1.1 jmcneill int
321 1.1 jmcneill fdtbus_register_regulator_controller(device_t dev, int phandle,
322 1.1 jmcneill const struct fdtbus_regulator_controller_func *funcs)
323 1.1 jmcneill {
324 1.1 jmcneill struct fdtbus_regulator_controller *rc;
325 1.1 jmcneill
326 1.1 jmcneill rc = kmem_alloc(sizeof(*rc), KM_SLEEP);
327 1.1 jmcneill rc->rc_dev = dev;
328 1.1 jmcneill rc->rc_phandle = phandle;
329 1.1 jmcneill rc->rc_funcs = funcs;
330 1.1 jmcneill
331 1.1 jmcneill rc->rc_next = fdtbus_rc;
332 1.1 jmcneill fdtbus_rc = rc;
333 1.1 jmcneill
334 1.1 jmcneill return 0;
335 1.1 jmcneill }
336 1.1 jmcneill
337 1.1 jmcneill static struct fdtbus_regulator_controller *
338 1.1 jmcneill fdtbus_get_regulator_controller(int phandle)
339 1.1 jmcneill {
340 1.1 jmcneill struct fdtbus_regulator_controller *rc;
341 1.1 jmcneill
342 1.1 jmcneill for (rc = fdtbus_rc; rc; rc = rc->rc_next) {
343 1.1 jmcneill if (rc->rc_phandle == phandle) {
344 1.1 jmcneill return rc;
345 1.1 jmcneill }
346 1.1 jmcneill }
347 1.1 jmcneill
348 1.1 jmcneill return NULL;
349 1.1 jmcneill }
350 1.1 jmcneill
351 1.1 jmcneill struct fdtbus_regulator *
352 1.1 jmcneill fdtbus_regulator_acquire(int phandle, const char *prop)
353 1.1 jmcneill {
354 1.1 jmcneill struct fdtbus_regulator_controller *rc;
355 1.1 jmcneill struct fdtbus_regulator *reg;
356 1.1 jmcneill int regulator_phandle;
357 1.1 jmcneill int error;
358 1.1 jmcneill
359 1.1 jmcneill regulator_phandle = fdtbus_get_phandle(phandle, prop);
360 1.1 jmcneill if (regulator_phandle == -1) {
361 1.1 jmcneill return NULL;
362 1.1 jmcneill }
363 1.1 jmcneill
364 1.1 jmcneill rc = fdtbus_get_regulator_controller(regulator_phandle);
365 1.1 jmcneill if (rc == NULL) {
366 1.1 jmcneill return NULL;
367 1.1 jmcneill }
368 1.1 jmcneill
369 1.1 jmcneill error = rc->rc_funcs->acquire(rc->rc_dev);
370 1.1 jmcneill if (error) {
371 1.1 jmcneill return NULL;
372 1.1 jmcneill }
373 1.1 jmcneill
374 1.1 jmcneill reg = kmem_alloc(sizeof(*reg), KM_SLEEP);
375 1.1 jmcneill reg->reg_rc = rc;
376 1.1 jmcneill
377 1.1 jmcneill return reg;
378 1.1 jmcneill }
379 1.1 jmcneill
380 1.1 jmcneill void
381 1.1 jmcneill fdtbus_regulator_release(struct fdtbus_regulator *reg)
382 1.1 jmcneill {
383 1.1 jmcneill struct fdtbus_regulator_controller *rc = reg->reg_rc;
384 1.1 jmcneill
385 1.1 jmcneill rc->rc_funcs->release(rc->rc_dev);
386 1.1 jmcneill
387 1.1 jmcneill kmem_free(reg, sizeof(*reg));
388 1.1 jmcneill }
389 1.1 jmcneill
390 1.1 jmcneill int
391 1.1 jmcneill fdtbus_regulator_enable(struct fdtbus_regulator *reg)
392 1.1 jmcneill {
393 1.1 jmcneill struct fdtbus_regulator_controller *rc = reg->reg_rc;
394 1.1 jmcneill
395 1.1 jmcneill return rc->rc_funcs->enable(rc->rc_dev, true);
396 1.1 jmcneill }
397 1.1 jmcneill
398 1.1 jmcneill int
399 1.1 jmcneill fdtbus_regulator_disable(struct fdtbus_regulator *reg)
400 1.1 jmcneill {
401 1.1 jmcneill struct fdtbus_regulator_controller *rc = reg->reg_rc;
402 1.1 jmcneill
403 1.1 jmcneill return rc->rc_funcs->enable(rc->rc_dev, false);
404 1.1 jmcneill }
405 1.1 jmcneill
406 1.1 jmcneill int
407 1.1 jmcneill fdtbus_register_i2c_controller(device_t dev, int phandle,
408 1.1 jmcneill const struct fdtbus_i2c_controller_func *funcs)
409 1.1 jmcneill {
410 1.1 jmcneill struct fdtbus_i2c_controller *i2c;
411 1.1 jmcneill
412 1.1 jmcneill i2c = kmem_alloc(sizeof(*i2c), KM_SLEEP);
413 1.1 jmcneill i2c->i2c_dev = dev;
414 1.1 jmcneill i2c->i2c_phandle = phandle;
415 1.1 jmcneill i2c->i2c_funcs = funcs;
416 1.1 jmcneill
417 1.1 jmcneill i2c->i2c_next = fdtbus_i2c;
418 1.1 jmcneill fdtbus_i2c = i2c;
419 1.1 jmcneill
420 1.1 jmcneill return 0;
421 1.1 jmcneill }
422 1.1 jmcneill
423 1.1 jmcneill static struct fdtbus_i2c_controller *
424 1.1 jmcneill fdtbus_get_i2c_controller(int phandle)
425 1.1 jmcneill {
426 1.1 jmcneill struct fdtbus_i2c_controller *i2c;
427 1.1 jmcneill
428 1.1 jmcneill for (i2c = fdtbus_i2c; i2c; i2c = i2c->i2c_next) {
429 1.1 jmcneill if (i2c->i2c_phandle == phandle) {
430 1.1 jmcneill return i2c;
431 1.1 jmcneill }
432 1.1 jmcneill }
433 1.1 jmcneill
434 1.1 jmcneill return NULL;
435 1.1 jmcneill }
436 1.1 jmcneill
437 1.1 jmcneill i2c_tag_t
438 1.1 jmcneill fdtbus_get_i2c_tag(int phandle)
439 1.1 jmcneill {
440 1.1 jmcneill struct fdtbus_i2c_controller *i2c;
441 1.1 jmcneill
442 1.1 jmcneill i2c = fdtbus_get_i2c_controller(phandle);
443 1.1 jmcneill if (i2c == NULL)
444 1.1 jmcneill return NULL;
445 1.1 jmcneill
446 1.1 jmcneill return i2c->i2c_funcs->get_tag(i2c->i2c_dev);
447 1.1 jmcneill }
448 1.1 jmcneill
449 1.1 jmcneill int
450 1.1 jmcneill fdtbus_get_phandle(int phandle, const char *prop)
451 1.1 jmcneill {
452 1.1 jmcneill u_int phandle_ref;
453 1.1 jmcneill u_int *buf;
454 1.1 jmcneill int len;
455 1.1 jmcneill
456 1.1 jmcneill len = OF_getproplen(phandle, prop);
457 1.1 jmcneill if (len < sizeof(phandle_ref))
458 1.1 jmcneill return -1;
459 1.1 jmcneill
460 1.1 jmcneill buf = kmem_alloc(len, KM_SLEEP);
461 1.1 jmcneill
462 1.1 jmcneill if (OF_getprop(phandle, prop, buf, len) != len) {
463 1.1 jmcneill kmem_free(buf, len);
464 1.1 jmcneill return -1;
465 1.1 jmcneill }
466 1.1 jmcneill
467 1.1 jmcneill phandle_ref = fdt32_to_cpu(buf[0]);
468 1.1 jmcneill kmem_free(buf, len);
469 1.1 jmcneill
470 1.1 jmcneill const void *data = fdt_openfirm_get_data();
471 1.1 jmcneill const int off = fdt_node_offset_by_phandle(data, phandle_ref);
472 1.1 jmcneill if (off < 0) {
473 1.1 jmcneill return -1;
474 1.1 jmcneill }
475 1.1 jmcneill
476 1.1 jmcneill return fdt_openfirm_get_phandle(off);
477 1.1 jmcneill }
478 1.1 jmcneill
479 1.1 jmcneill int
480 1.1 jmcneill fdtbus_get_reg(int phandle, u_int index, bus_addr_t *paddr, bus_size_t *psize)
481 1.1 jmcneill {
482 1.1 jmcneill bus_addr_t addr;
483 1.1 jmcneill bus_size_t size;
484 1.1 jmcneill uint8_t *buf;
485 1.1 jmcneill int len;
486 1.1 jmcneill
487 1.1 jmcneill const int addr_cells = fdtbus_get_addr_cells(phandle);
488 1.1 jmcneill const int size_cells = fdtbus_get_size_cells(phandle);
489 1.1 jmcneill if (addr_cells == -1 || size_cells == -1)
490 1.1 jmcneill return -1;
491 1.1 jmcneill
492 1.1 jmcneill const u_int reglen = size_cells * 4 + addr_cells * 4;
493 1.1 jmcneill if (reglen == 0)
494 1.1 jmcneill return -1;
495 1.1 jmcneill
496 1.1 jmcneill len = OF_getproplen(phandle, "reg");
497 1.1 jmcneill if (len <= 0)
498 1.1 jmcneill return -1;
499 1.1 jmcneill
500 1.1 jmcneill const u_int nregs = len / reglen;
501 1.1 jmcneill
502 1.1 jmcneill if (index >= nregs)
503 1.1 jmcneill return -1;
504 1.1 jmcneill
505 1.1 jmcneill buf = kmem_alloc(len, KM_SLEEP);
506 1.1 jmcneill if (buf == NULL)
507 1.1 jmcneill return -1;
508 1.1 jmcneill
509 1.1 jmcneill len = OF_getprop(phandle, "reg", buf, len);
510 1.1 jmcneill
511 1.1 jmcneill switch (addr_cells) {
512 1.1 jmcneill case 0:
513 1.1 jmcneill addr = 0;
514 1.1 jmcneill break;
515 1.1 jmcneill case 1:
516 1.1 jmcneill addr = be32dec(&buf[index * reglen + 0]);
517 1.1 jmcneill break;
518 1.1 jmcneill case 2:
519 1.1 jmcneill addr = be64dec(&buf[index * reglen + 0]);
520 1.1 jmcneill break;
521 1.1 jmcneill default:
522 1.1 jmcneill panic("fdtbus_get_reg: unsupported addr_cells %d", addr_cells);
523 1.1 jmcneill }
524 1.1 jmcneill
525 1.1 jmcneill switch (size_cells) {
526 1.1 jmcneill case 0:
527 1.1 jmcneill size = 0;
528 1.1 jmcneill break;
529 1.1 jmcneill case 1:
530 1.1 jmcneill size = be32dec(&buf[index * reglen + addr_cells * 4]);
531 1.1 jmcneill break;
532 1.1 jmcneill case 2:
533 1.1 jmcneill size = be64dec(&buf[index * reglen + addr_cells * 4]);
534 1.1 jmcneill break;
535 1.1 jmcneill default:
536 1.1 jmcneill panic("fdtbus_get_reg: unsupported size_cells %d", size_cells);
537 1.1 jmcneill }
538 1.1 jmcneill
539 1.1 jmcneill if (paddr)
540 1.1 jmcneill *paddr = addr;
541 1.1 jmcneill if (psize)
542 1.1 jmcneill *psize = size;
543 1.1 jmcneill
544 1.1 jmcneill kmem_free(buf, len);
545 1.1 jmcneill
546 1.1 jmcneill return 0;
547 1.1 jmcneill }
548