xref: /freebsd/sys/powerpc/mpc85xx/lbc.c (revision 2e3f49888ec8851bafb22011533217487764fdb0)
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 2006-2008, Juniper Networks, Inc.
5  * Copyright (c) 2008 Semihalf, Rafal Czubak
6  * Copyright (c) 2009 The FreeBSD Foundation
7  * All rights reserved.
8  *
9  * Portions of this software were developed by Semihalf
10  * under sponsorship from the FreeBSD Foundation.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. The name of the author may not be used to endorse or promote products
21  *    derived from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
30  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
31  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 #include "opt_platform.h"
37 
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/ktr.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
43 #include <sys/module.h>
44 #include <sys/bus.h>
45 #include <sys/rman.h>
46 #include <machine/bus.h>
47 
48 #include <vm/vm.h>
49 #include <vm/pmap.h>
50 
51 #include <dev/fdt/fdt_common.h>
52 #include <dev/ofw/ofw_bus.h>
53 #include <dev/ofw/ofw_bus_subr.h>
54 
55 #include <powerpc/mpc85xx/mpc85xx.h>
56 
57 #include "ofw_bus_if.h"
58 #include "lbc.h"
59 
60 #ifdef DEBUG
61 #define debugf(fmt, args...) do { printf("%s(): ", __func__);	\
62     printf(fmt,##args); } while (0)
63 #else
64 #define debugf(fmt, args...)
65 #endif
66 
67 static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
68 
69 static int lbc_probe(device_t);
70 static int lbc_attach(device_t);
71 static int lbc_shutdown(device_t);
72 static int lbc_map_resource(device_t, device_t, int, struct resource *,
73     struct resource_map_request *, struct resource_map *);
74 static int lbc_unmap_resource(device_t, device_t, int, struct resource *,
75     struct resource_map *map);
76 static int lbc_activate_resource(device_t bus, device_t child,
77     int type, int rid, struct resource *r);
78 static int lbc_deactivate_resource(device_t bus,
79     device_t child, int type __unused, int rid,
80     struct resource *r);
81 static struct rman *lbc_get_rman(device_t, int, u_int);
82 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
83     rman_res_t, rman_res_t, rman_res_t, u_int);
84 static int lbc_adjust_resource(device_t, device_t, int, struct resource *,
85     rman_res_t, rman_res_t);
86 static int lbc_print_child(device_t, device_t);
87 static int lbc_release_resource(device_t, device_t, int, int,
88     struct resource *);
89 static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
90 
91 /*
92  * Bus interface definition
93  */
94 static device_method_t lbc_methods[] = {
95 	/* Device interface */
96 	DEVMETHOD(device_probe,		lbc_probe),
97 	DEVMETHOD(device_attach,	lbc_attach),
98 	DEVMETHOD(device_shutdown,	lbc_shutdown),
99 
100 	/* Bus interface */
101 	DEVMETHOD(bus_print_child,	lbc_print_child),
102 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
103 	DEVMETHOD(bus_teardown_intr,	NULL),
104 
105 	DEVMETHOD(bus_get_rman,		lbc_get_rman),
106 	DEVMETHOD(bus_alloc_resource,	lbc_alloc_resource),
107 	DEVMETHOD(bus_adjust_resource,	lbc_adjust_resource),
108 	DEVMETHOD(bus_release_resource,	lbc_release_resource),
109 	DEVMETHOD(bus_activate_resource, lbc_activate_resource),
110 	DEVMETHOD(bus_deactivate_resource, lbc_deactivate_resource),
111 	DEVMETHOD(bus_map_resource,	lbc_map_resource),
112 	DEVMETHOD(bus_unmap_resource,	lbc_unmap_resource),
113 
114 	/* OFW bus interface */
115 	DEVMETHOD(ofw_bus_get_devinfo,	lbc_get_devinfo),
116 	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
117 	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
118 	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
119 	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
120 	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
121 	{ 0, 0 }
122 };
123 
124 static driver_t lbc_driver = {
125 	"lbc",
126 	lbc_methods,
127 	sizeof(struct lbc_softc)
128 };
129 
130 EARLY_DRIVER_MODULE(lbc, ofwbus, lbc_driver, 0, 0, BUS_PASS_BUS);
131 
132 /*
133  * Calculate address mask used by OR(n) registers. Use memory region size to
134  * determine mask value. The size must be a power of two and within the range
135  * of 32KB - 4GB. Otherwise error code is returned. Value representing
136  * 4GB size can be passed as 0xffffffff.
137  */
138 static uint32_t
139 lbc_address_mask(uint32_t size)
140 {
141 	int n = 15;
142 
143 	if (size == ~0)
144 		return (0);
145 
146 	while (n < 32) {
147 		if (size == (1U << n))
148 			break;
149 		n++;
150 	}
151 
152 	if (n == 32)
153 		return (EINVAL);
154 
155 	return (0xffff8000 << (n - 15));
156 }
157 
158 static void
159 lbc_banks_unmap(struct lbc_softc *sc)
160 {
161 	int r;
162 
163 	r = 0;
164 	while (r < LBC_DEV_MAX) {
165 		if (sc->sc_range[r].size == 0)
166 			return;
167 
168 		pmap_unmapdev((void *)sc->sc_range[r].kva,
169 		    sc->sc_range[r].size);
170 		law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr,
171 		    sc->sc_range[r].size);
172 		r++;
173 	}
174 }
175 
176 static int
177 lbc_banks_map(struct lbc_softc *sc)
178 {
179 	vm_paddr_t end, start;
180 	vm_size_t size;
181 	u_int i, r, ranges, s;
182 	int error;
183 
184 	bzero(sc->sc_range, sizeof(sc->sc_range));
185 
186 	/*
187 	 * Determine number of discontiguous address ranges to program.
188 	 */
189 	ranges = 0;
190 	for (i = 0; i < LBC_DEV_MAX; i++) {
191 		size = sc->sc_banks[i].size;
192 		if (size == 0)
193 			continue;
194 
195 		start = sc->sc_banks[i].addr;
196 		for (r = 0; r < ranges; r++) {
197 			/* Avoid wrap-around bugs. */
198 			end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size;
199 			if (start > 0 && end == start - 1) {
200 				sc->sc_range[r].size += size;
201 				break;
202 			}
203 			/* Avoid wrap-around bugs. */
204 			end = start - 1 + size;
205 			if (sc->sc_range[r].addr > 0 &&
206 			    end == sc->sc_range[r].addr - 1) {
207 				sc->sc_range[r].addr = start;
208 				sc->sc_range[r].size += size;
209 				break;
210 			}
211 		}
212 		if (r == ranges) {
213 			/* New range; add using insertion sort */
214 			r = 0;
215 			while (r < ranges && sc->sc_range[r].addr < start)
216 				r++;
217 			for (s = ranges; s > r; s--)
218 				sc->sc_range[s] = sc->sc_range[s-1];
219 			sc->sc_range[r].addr = start;
220 			sc->sc_range[r].size = size;
221 			ranges++;
222 		}
223 	}
224 
225 	/*
226 	 * Ranges are sorted so quickly go over the list to merge ranges
227 	 * that grew toward each other while building the ranges.
228 	 */
229 	r = 0;
230 	while (r < ranges - 1) {
231 		end = sc->sc_range[r].addr + sc->sc_range[r].size;
232 		if (end != sc->sc_range[r+1].addr) {
233 			r++;
234 			continue;
235 		}
236 		sc->sc_range[r].size += sc->sc_range[r+1].size;
237 		for (s = r + 1; s < ranges - 1; s++)
238 			sc->sc_range[s] = sc->sc_range[s+1];
239 		bzero(&sc->sc_range[s], sizeof(sc->sc_range[s]));
240 		ranges--;
241 	}
242 
243 	/*
244 	 * Configure LAW for the LBC ranges and map the physical memory
245 	 * range into KVA.
246 	 */
247 	for (r = 0; r < ranges; r++) {
248 		start = sc->sc_range[r].addr;
249 		size = sc->sc_range[r].size;
250 		error = law_enable(OCP85XX_TGTIF_LBC, start, size);
251 		if (error)
252 			return (error);
253 		sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size);
254 	}
255 
256 	/* XXX: need something better here? */
257 	if (ranges == 0)
258 		return (EINVAL);
259 
260 	/* Assign KVA to banks based on the enclosing range. */
261 	for (i = 0; i < LBC_DEV_MAX; i++) {
262 		size = sc->sc_banks[i].size;
263 		if (size == 0)
264 			continue;
265 
266 		start = sc->sc_banks[i].addr;
267 		for (r = 0; r < ranges; r++) {
268 			end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size;
269 			if (start >= sc->sc_range[r].addr &&
270 			    start - 1 + size <= end)
271 				break;
272 		}
273 		if (r < ranges) {
274 			sc->sc_banks[i].kva = sc->sc_range[r].kva +
275 			    (start - sc->sc_range[r].addr);
276 		}
277 	}
278 
279 	return (0);
280 }
281 
282 static int
283 lbc_banks_enable(struct lbc_softc *sc)
284 {
285 	uint32_t size;
286 	uint32_t regval;
287 	int error, i;
288 
289 	for (i = 0; i < LBC_DEV_MAX; i++) {
290 		size = sc->sc_banks[i].size;
291 		if (size == 0)
292 			continue;
293 
294 		/*
295 		 * Compute and program BR value.
296 		 */
297 		regval = sc->sc_banks[i].addr;
298 		switch (sc->sc_banks[i].width) {
299 		case 8:
300 			regval |= (1 << 11);
301 			break;
302 		case 16:
303 			regval |= (2 << 11);
304 			break;
305 		case 32:
306 			regval |= (3 << 11);
307 			break;
308 		default:
309 			error = EINVAL;
310 			goto fail;
311 		}
312 		regval |= (sc->sc_banks[i].decc << 9);
313 		regval |= (sc->sc_banks[i].wp << 8);
314 		regval |= (sc->sc_banks[i].msel << 5);
315 		regval |= (sc->sc_banks[i].atom << 2);
316 		regval |= 1;
317 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
318 		    LBC85XX_BR(i), regval);
319 
320 		/*
321 		 * Compute and program OR value.
322 		 */
323 		regval = lbc_address_mask(size);
324 		switch (sc->sc_banks[i].msel) {
325 		case LBCRES_MSEL_GPCM:
326 			/* TODO Add flag support for option registers */
327 			regval |= 0x0ff7;
328 			break;
329 		case LBCRES_MSEL_FCM:
330 			/* TODO Add flag support for options register */
331 			regval |= 0x0796;
332 			break;
333 		case LBCRES_MSEL_UPMA:
334 		case LBCRES_MSEL_UPMB:
335 		case LBCRES_MSEL_UPMC:
336 			printf("UPM mode not supported yet!");
337 			error = ENOSYS;
338 			goto fail;
339 		}
340 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
341 		    LBC85XX_OR(i), regval);
342 	}
343 
344 	return (0);
345 
346 fail:
347 	lbc_banks_unmap(sc);
348 	return (error);
349 }
350 
351 static void
352 fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di)
353 {
354 	pcell_t width;
355 	int bank;
356 
357 	if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0)
358 		return;
359 
360 	bank = di->di_bank;
361 	if (sc->sc_banks[bank].size == 0)
362 		return;
363 
364 	/* Express width in bits. */
365 	sc->sc_banks[bank].width = width * 8;
366 }
367 
368 static int
369 fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
370     struct lbc_devinfo *di)
371 {
372 	rman_res_t start, end, count;
373 	pcell_t *reg, *regptr;
374 	pcell_t addr_cells, size_cells;
375 	int tuple_size, tuples;
376 	int i, j, rv, bank;
377 
378 	if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
379 		return (ENXIO);
380 
381 	tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
382 	tuples = OF_getencprop_alloc_multi(node, "reg", tuple_size,
383 	    (void **)&reg);
384 	debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
385 	debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
386 	if (tuples <= 0)
387 		/* No 'reg' property in this node. */
388 		return (0);
389 
390 	regptr = reg;
391 	for (i = 0; i < tuples; i++) {
392 		bank = fdt_data_get((void *)reg, 1);
393 		di->di_bank = bank;
394 		reg += 1;
395 
396 		/* Get address/size. */
397 		start = count = 0;
398 		for (j = 0; j < addr_cells - 1; j++) {
399 			start <<= 32;
400 			start |= reg[j];
401 		}
402 		for (j = 0; j < size_cells; j++) {
403 			count <<= 32;
404 			count |= reg[addr_cells + j - 1];
405 		}
406 		reg += addr_cells - 1 + size_cells;
407 
408 		/* Calculate address range relative to VA base. */
409 		start = sc->sc_banks[bank].kva + start;
410 		end = start + count - 1;
411 
412 		debugf("reg addr bank = %d, start = %jx, end = %jx, "
413 		    "count = %jx\n", bank, start, end, count);
414 
415 		/* Use bank (CS) cell as rid. */
416 		resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start,
417 		    end, count);
418 	}
419 	rv = 0;
420 	OF_prop_free(regptr);
421 	return (rv);
422 }
423 
424 static void
425 lbc_intr(void *arg)
426 {
427 	struct lbc_softc *sc = arg;
428 	uint32_t ltesr;
429 
430 	ltesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR);
431 	sc->sc_ltesr = ltesr;
432 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ltesr);
433 	wakeup(sc->sc_dev);
434 }
435 
436 static int
437 lbc_probe(device_t dev)
438 {
439 
440 	if (!(ofw_bus_is_compatible(dev, "fsl,lbc") ||
441 	    ofw_bus_is_compatible(dev, "fsl,elbc")))
442 		return (ENXIO);
443 
444 	device_set_desc(dev, "Freescale Local Bus Controller");
445 	return (BUS_PROBE_DEFAULT);
446 }
447 
448 static int
449 lbc_attach(device_t dev)
450 {
451 	struct lbc_softc *sc;
452 	struct lbc_devinfo *di;
453 	struct rman *rm;
454 	uintmax_t offset, size;
455 	vm_paddr_t start;
456 	device_t cdev;
457 	phandle_t node, child;
458 	pcell_t *ranges, *rangesptr;
459 	int tuple_size, tuples;
460 	int par_addr_cells;
461 	int bank, error, i, j;
462 
463 	sc = device_get_softc(dev);
464 	sc->sc_dev = dev;
465 
466 	sc->sc_mrid = 0;
467 	sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid,
468 	    RF_ACTIVE);
469 	if (sc->sc_mres == NULL)
470 		return (ENXIO);
471 
472 	sc->sc_bst = rman_get_bustag(sc->sc_mres);
473 	sc->sc_bsh = rman_get_bushandle(sc->sc_mres);
474 
475 	for (bank = 0; bank < LBC_DEV_MAX; bank++) {
476 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0);
477 		bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0);
478 	}
479 
480 	/*
481 	 * Initialize configuration register:
482 	 * - enable Local Bus
483 	 * - set data buffer control signal function
484 	 * - disable parity byte select
485 	 * - set ECC parity type
486 	 * - set bus monitor timing and timer prescale
487 	 */
488 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0);
489 
490 	/*
491 	 * Initialize clock ratio register:
492 	 * - disable PLL bypass mode
493 	 * - configure LCLK delay cycles for the assertion of LALE
494 	 * - set system clock divider
495 	 */
496 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008);
497 
498 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0);
499 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0);
500 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001);
501 
502 	sc->sc_irid = 0;
503 	sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid,
504 	    RF_ACTIVE | RF_SHAREABLE);
505 	if (sc->sc_ires != NULL) {
506 		error = bus_setup_intr(dev, sc->sc_ires,
507 		    INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc,
508 		    &sc->sc_icookie);
509 		if (error) {
510 			device_printf(dev, "could not activate interrupt\n");
511 			bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid,
512 			    sc->sc_ires);
513 			sc->sc_ires = NULL;
514 		}
515 	}
516 
517 	sc->sc_ltesr = ~0;
518 
519 	rangesptr = NULL;
520 
521 	rm = &sc->sc_rman;
522 	rm->rm_type = RMAN_ARRAY;
523 	rm->rm_descr = "Local Bus Space";
524 	error = rman_init(rm);
525 	if (error)
526 		goto fail;
527 
528 	error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
529 	if (error) {
530 		rman_fini(rm);
531 		goto fail;
532 	}
533 
534 	/*
535 	 * Process 'ranges' property.
536 	 */
537 	node = ofw_bus_get_node(dev);
538 	if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
539 	    &sc->sc_size_cells)) != 0) {
540 		error = ENXIO;
541 		goto fail;
542 	}
543 
544 	par_addr_cells = fdt_parent_addr_cells(node);
545 	if (par_addr_cells > 2) {
546 		device_printf(dev, "unsupported parent #addr-cells\n");
547 		error = ERANGE;
548 		goto fail;
549 	}
550 	tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
551 	    sc->sc_size_cells);
552 
553 	tuples = OF_getencprop_alloc_multi(node, "ranges", tuple_size,
554 	    (void **)&ranges);
555 	if (tuples < 0) {
556 		device_printf(dev, "could not retrieve 'ranges' property\n");
557 		error = ENXIO;
558 		goto fail;
559 	}
560 	rangesptr = ranges;
561 
562 	debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
563 	    "tuple_size = %d, tuples = %d\n", par_addr_cells,
564 	    sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);
565 
566 	start = 0;
567 	size = 0;
568 	for (i = 0; i < tuples; i++) {
569 		/* The first cell is the bank (chip select) number. */
570 		bank = fdt_data_get(ranges, 1);
571 		if (bank < 0 || bank > LBC_DEV_MAX) {
572 			device_printf(dev, "bank out of range: %d\n", bank);
573 			error = ERANGE;
574 			goto fail;
575 		}
576 		ranges += 1;
577 
578 		/*
579 		 * Remaining cells of the child address define offset into
580 		 * this CS.
581 		 */
582 		offset = 0;
583 		for (j = 0; j < sc->sc_addr_cells - 1; j++) {
584 			offset <<= sizeof(pcell_t) * 8;
585 			offset |= *ranges;
586 			ranges++;
587 		}
588 
589 		/* Parent bus start address of this bank. */
590 		start = 0;
591 		for (j = 0; j < par_addr_cells; j++) {
592 			start <<= sizeof(pcell_t) * 8;
593 			start |= *ranges;
594 			ranges++;
595 		}
596 
597 		size = fdt_data_get((void *)ranges, sc->sc_size_cells);
598 		ranges += sc->sc_size_cells;
599 		debugf("bank = %d, start = %jx, size = %jx\n", bank,
600 		    (uintmax_t)start, size);
601 
602 		sc->sc_banks[bank].addr = start + offset;
603 		sc->sc_banks[bank].size = size;
604 
605 		/*
606 		 * Attributes for the bank.
607 		 *
608 		 * XXX Note there are no DT bindings defined for them at the
609 		 * moment, so we need to provide some defaults.
610 		 */
611 		sc->sc_banks[bank].width = 16;
612 		sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
613 		sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
614 		sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
615 		sc->sc_banks[bank].wp = 0;
616 	}
617 
618 	/*
619 	 * Initialize mem-mappings for the LBC banks (i.e. chip selects).
620 	 */
621 	error = lbc_banks_map(sc);
622 	if (error)
623 		goto fail;
624 
625 	/*
626 	 * Walk the localbus and add direct subordinates as our children.
627 	 */
628 	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
629 		di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);
630 
631 		if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
632 			free(di, M_LBC);
633 			device_printf(dev, "could not set up devinfo\n");
634 			continue;
635 		}
636 
637 		resource_list_init(&di->di_res);
638 
639 		if (fdt_lbc_reg_decode(child, sc, di)) {
640 			device_printf(dev, "could not process 'reg' "
641 			    "property\n");
642 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
643 			free(di, M_LBC);
644 			continue;
645 		}
646 
647 		fdt_lbc_fixup(child, sc, di);
648 
649 		/* Add newbus device for this FDT node */
650 		cdev = device_add_child(dev, NULL, -1);
651 		if (cdev == NULL) {
652 			device_printf(dev, "could not add child: %s\n",
653 			    di->di_ofw.obd_name);
654 			resource_list_free(&di->di_res);
655 			ofw_bus_gen_destroy_devinfo(&di->di_ofw);
656 			free(di, M_LBC);
657 			continue;
658 		}
659 		debugf("added child name='%s', node=%x\n", di->di_ofw.obd_name,
660 		    child);
661 		device_set_ivars(cdev, di);
662 	}
663 
664 	/*
665 	 * Enable the LBC.
666 	 */
667 	lbc_banks_enable(sc);
668 
669 	OF_prop_free(rangesptr);
670 	return (bus_generic_attach(dev));
671 
672 fail:
673 	OF_prop_free(rangesptr);
674 	bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres);
675 	return (error);
676 }
677 
678 static int
679 lbc_shutdown(device_t dev)
680 {
681 
682 	/* TODO */
683 	return(0);
684 }
685 
686 static struct rman *
687 lbc_get_rman(device_t bus, int type, u_int flags)
688 {
689 	struct lbc_softc *sc;
690 
691 	sc = device_get_softc(bus);
692 	switch (type) {
693 	case SYS_RES_MEMORY:
694 		return (&sc->sc_rman);
695 	default:
696 		return (NULL);
697 	}
698 }
699 
700 static struct resource *
701 lbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
702     rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
703 {
704 	struct lbc_devinfo *di;
705 	struct resource_list_entry *rle;
706 
707 	/* We only support default allocations. */
708 	if (!RMAN_IS_DEFAULT_RANGE(start, end))
709 		return (NULL);
710 
711 	if (type == SYS_RES_IRQ)
712 		return (bus_alloc_resource(bus, type, rid, start, end, count,
713 		    flags));
714 
715 	/*
716 	 * Request for the default allocation with a given rid: use resource
717 	 * list stored in the local device info.
718 	 */
719 	if ((di = device_get_ivars(child)) == NULL)
720 		return (NULL);
721 
722 	if (type == SYS_RES_IOPORT)
723 		type = SYS_RES_MEMORY;
724 
725 	/*
726 	 * XXX: We are supposed to return a value to the user, so this
727 	 * doesn't seem right.
728 	 */
729 	rid = &di->di_bank;
730 
731 	rle = resource_list_find(&di->di_res, type, *rid);
732 	if (rle == NULL) {
733 		device_printf(bus, "no default resources for "
734 		    "rid = %d, type = %d\n", *rid, type);
735 		return (NULL);
736 	}
737 	start = rle->start;
738 	count = rle->count;
739 	end = start + count - 1;
740 
741 	return (bus_generic_rman_alloc_resource(bus, child, type, rid, start,
742 	    end, count, flags));
743 }
744 
745 static int
746 lbc_print_child(device_t dev, device_t child)
747 {
748 	struct lbc_devinfo *di;
749 	struct resource_list *rl;
750 	int rv;
751 
752 	di = device_get_ivars(child);
753 	rl = &di->di_res;
754 
755 	rv = 0;
756 	rv += bus_print_child_header(dev, child);
757 	rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx");
758 	rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd");
759 	rv += bus_print_child_footer(dev, child);
760 
761 	return (rv);
762 }
763 
764 static int
765 lbc_adjust_resource(device_t dev, device_t child, int type, struct resource *r,
766     rman_res_t start, rman_res_t end)
767 {
768 	switch (type) {
769 	case SYS_RES_IOPORT:
770 		type = SYS_RES_MEMORY;
771 		/* FALLTHROUGH */
772 	case SYS_RES_MEMORY:
773 		return (bus_generic_rman_adjust_resource(dev, child, type, r,
774 		    start, end));
775 	case SYS_RES_IRQ:
776 		return (bus_adjust_resource(dev, type, r, start, end));
777 	default:
778 		return (EINVAL);
779 	}
780 }
781 
782 static int
783 lbc_release_resource(device_t dev, device_t child, int type, int rid,
784     struct resource *res)
785 {
786 	switch (type) {
787 	case SYS_RES_IOPORT:
788 		type = SYS_RES_MEMORY;
789 		/* FALLTHROUGH */
790 	case SYS_RES_MEMORY:
791 		return (bus_generic_rman_release_resource(dev, child, type,
792 		    rid, res));
793 	case SYS_RES_IRQ:
794 		return (bus_release_resource(dev, type, rid, res));
795 	default:
796 		return (EINVAL);
797 	}
798 }
799 
800 static int
801 lbc_activate_resource(device_t bus, device_t child, int type, int rid,
802     struct resource *r)
803 {
804 	switch (type) {
805 	case SYS_RES_IOPORT:
806 		type = SYS_RES_MEMORY;
807 		/* FALLTHROUGH */
808 	case SYS_RES_MEMORY:
809 		return (bus_generic_rman_activate_resource(bus, child, type,
810 		    rid, r));
811 	case SYS_RES_IRQ:
812 		return (bus_activate_resource(bus, type, rid, r));
813 	default:
814 		return (EINVAL);
815 	}
816 }
817 
818 static int
819 lbc_deactivate_resource(device_t bus, device_t child, int type, int rid,
820     struct resource *r)
821 {
822 	switch (type) {
823 	case SYS_RES_IOPORT:
824 		type = SYS_RES_MEMORY;
825 		/* FALLTHROUGH */
826 	case SYS_RES_MEMORY:
827 		return (bus_generic_rman_deactivate_resource(bus, child, type,
828 		    rid, r));
829 	case SYS_RES_IRQ:
830 		return (bus_deactivate_resource(bus, type, rid, r));
831 	default:
832 		return (EINVAL);
833 	}
834 }
835 
836 static int
837 lbc_map_resource(device_t bus, device_t child, int type, struct resource *r,
838     struct resource_map_request *argsp, struct resource_map *map)
839 {
840 	struct resource_map_request args;
841 	rman_res_t length, start;
842 	int error;
843 
844 	/* Resources must be active to be mapped. */
845 	if (!(rman_get_flags(r) & RF_ACTIVE))
846 		return (ENXIO);
847 
848 	/* Mappings are only supported on I/O and memory resources. */
849 	switch (type) {
850 	case SYS_RES_IOPORT:
851 	case SYS_RES_MEMORY:
852 		break;
853 	default:
854 		return (EINVAL);
855 	}
856 
857 	resource_init_map_request(&args);
858 	error = resource_validate_map_request(r, argsp, &args, &start, &length);
859 	if (error)
860 		return (error);
861 
862 	map->r_bustag = &bs_be_tag;
863 	map->r_bushandle = start;
864 	map->r_size = length;
865 	map->r_vaddr = NULL;
866 	return (0);
867 }
868 
869 static int
870 lbc_unmap_resource(device_t bus, device_t child, int type, struct resource *r,
871     struct resource_map *map)
872 {
873 
874 	/* Mappings are only supported on I/O and memory resources. */
875 	switch (type) {
876 	case SYS_RES_IOPORT:
877 	case SYS_RES_MEMORY:
878 		break;
879 	default:
880 		return (EINVAL);
881 	}
882 	return (0);
883 }
884 
885 static const struct ofw_bus_devinfo *
886 lbc_get_devinfo(device_t bus, device_t child)
887 {
888 	struct lbc_devinfo *di;
889 
890 	di = device_get_ivars(child);
891 	return (&di->di_ofw);
892 }
893 
894 void
895 lbc_write_reg(device_t child, u_int off, uint32_t val)
896 {
897 	device_t dev;
898 	struct lbc_softc *sc;
899 
900 	dev = device_get_parent(child);
901 
902 	if (off >= 0x1000) {
903 		device_printf(dev, "%s(%s): invalid offset %#x\n",
904 		    __func__, device_get_nameunit(child), off);
905 		return;
906 	}
907 
908 	sc = device_get_softc(dev);
909 
910 	if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) {
911 		sc->sc_ltesr ^= (val & sc->sc_ltesr);
912 		return;
913 	}
914 
915 	if (off == LBC85XX_LTEATR && (val & 1) == 0)
916 		sc->sc_ltesr = ~0u;
917 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
918 }
919 
920 uint32_t
921 lbc_read_reg(device_t child, u_int off)
922 {
923 	device_t dev;
924 	struct lbc_softc *sc;
925 	uint32_t val;
926 
927 	dev = device_get_parent(child);
928 
929 	if (off >= 0x1000) {
930 		device_printf(dev, "%s(%s): invalid offset %#x\n",
931 		    __func__, device_get_nameunit(child), off);
932 		return (~0U);
933 	}
934 
935 	sc = device_get_softc(dev);
936 
937 	if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U)
938 		val = sc->sc_ltesr;
939 	else
940 		val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off);
941 	return (val);
942 }
943