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