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