Home | History | Annotate | Line # | Download | only in fdt
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