2 * Copyright (c) 2006-2008, Juniper Networks, Inc.
3 * Copyright (c) 2008 Semihalf, Rafal Czubak
4 * Copyright (c) 2009 The FreeBSD Foundation
7 * Portions of this software were developed by Semihalf
8 * under sponsorship from the FreeBSD Foundation.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
37 #include <sys/param.h>
38 #include <sys/systm.h>
40 #include <sys/kernel.h>
41 #include <sys/malloc.h>
42 #include <sys/module.h>
45 #include <machine/bus.h>
50 #include <dev/fdt/fdt_common.h>
51 #include <dev/ofw/ofw_bus.h>
52 #include <dev/ofw/ofw_bus_subr.h>
54 #include <powerpc/mpc85xx/mpc85xx.h>
56 #include "ofw_bus_if.h"
63 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \
64 printf(fmt,##args); } while (0)
66 #define debugf(fmt, args...)
70 lbc_write_reg(struct lbc_softc *sc, bus_size_t off, uint32_t val)
73 bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val);
76 static __inline uint32_t
77 lbc_read_reg(struct lbc_softc *sc, bus_size_t off)
80 return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off));
83 static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information");
85 static int lbc_probe(device_t);
86 static int lbc_attach(device_t);
87 static int lbc_shutdown(device_t);
88 static struct resource *lbc_alloc_resource(device_t, device_t, int, int *,
89 u_long, u_long, u_long, u_int);
90 static int lbc_print_child(device_t, device_t);
91 static int lbc_release_resource(device_t, device_t, int, int,
93 static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t);
96 * Bus interface definition
98 static device_method_t lbc_methods[] = {
99 /* Device interface */
100 DEVMETHOD(device_probe, lbc_probe),
101 DEVMETHOD(device_attach, lbc_attach),
102 DEVMETHOD(device_shutdown, lbc_shutdown),
105 DEVMETHOD(bus_print_child, lbc_print_child),
106 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
107 DEVMETHOD(bus_teardown_intr, NULL),
109 DEVMETHOD(bus_alloc_resource, lbc_alloc_resource),
110 DEVMETHOD(bus_release_resource, lbc_release_resource),
111 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
112 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
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),
125 static driver_t lbc_driver = {
128 sizeof(struct lbc_softc)
131 devclass_t lbc_devclass;
133 DRIVER_MODULE(lbc, fdtbus, lbc_driver, lbc_devclass, 0, 0);
136 * Calculate address mask used by OR(n) registers. Use memory region size to
137 * determine mask value. The size must be a power of two and within the range
138 * of 32KB - 4GB. Otherwise error code is returned. Value representing
139 * 4GB size can be passed as 0xffffffff.
142 lbc_address_mask(uint32_t size)
150 if (size == (1UL << n))
158 return (0xffff8000 << (n - 15));
162 lbc_banks_unmap(struct lbc_softc *sc)
166 for (i = 0; i < LBC_DEV_MAX; i++) {
167 if (sc->sc_banks[i].size == 0)
170 law_disable(OCP85XX_TGTIF_LBC, sc->sc_banks[i].pa,
171 sc->sc_banks[i].size);
172 pmap_unmapdev(sc->sc_banks[i].va, sc->sc_banks[i].size);
177 lbc_banks_map(struct lbc_softc *sc)
182 for (i = 0; i < LBC_DEV_MAX; i++) {
183 if (sc->sc_banks[i].size == 0)
186 /* Physical address start/size. */
187 start = sc->sc_banks[i].pa;
188 size = sc->sc_banks[i].size;
191 * Configure LAW for this LBC bank (CS) and map its physical
192 * memory region into KVA.
194 error = law_enable(OCP85XX_TGTIF_LBC, start, size);
198 sc->sc_banks[i].va = (vm_offset_t)pmap_mapdev(start, size);
199 if (sc->sc_banks[i].va == 0) {
208 lbc_banks_enable(struct lbc_softc *sc)
214 for (i = 0; i < LBC_DEV_MAX; i++) {
215 size = sc->sc_banks[i].size;
219 * Compute and program BR value.
222 regval |= sc->sc_banks[i].pa;
224 switch (sc->sc_banks[i].width) {
238 regval |= (sc->sc_banks[i].decc << 9);
239 regval |= (sc->sc_banks[i].wp << 8);
240 regval |= (sc->sc_banks[i].msel << 5);
241 regval |= (sc->sc_banks[i].atom << 2);
244 lbc_write_reg(sc, LBC85XX_BR(i), regval);
247 * Compute and program OR value.
250 regval |= lbc_address_mask(size);
252 switch (sc->sc_banks[i].msel) {
253 case LBCRES_MSEL_GPCM:
254 /* TODO Add flag support for option registers */
255 regval |= 0x00000ff7;
257 case LBCRES_MSEL_FCM:
258 printf("FCM mode not supported yet!");
261 case LBCRES_MSEL_UPMA:
262 case LBCRES_MSEL_UPMB:
263 case LBCRES_MSEL_UPMC:
264 printf("UPM mode not supported yet!");
268 lbc_write_reg(sc, LBC85XX_OR(i), regval);
272 * Initialize configuration register:
274 * - set data buffer control signal function
275 * - disable parity byte select
276 * - set ECC parity type
277 * - set bus monitor timing and timer prescale
279 lbc_write_reg(sc, LBC85XX_LBCR, 0);
282 * Initialize clock ratio register:
283 * - disable PLL bypass mode
284 * - configure LCLK delay cycles for the assertion of LALE
285 * - set system clock divider
287 lbc_write_reg(sc, LBC85XX_LCRR, 0x00030008);
297 fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di)
302 if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0)
306 if (sc->sc_banks[bank].size == 0)
309 /* Express width in bits. */
310 sc->sc_banks[bank].width = width * 8;
314 fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc,
315 struct lbc_devinfo *di)
317 u_long start, end, count;
318 pcell_t *reg, *regptr;
319 pcell_t addr_cells, size_cells;
320 int tuple_size, tuples;
323 if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0)
326 tuple_size = sizeof(pcell_t) * (addr_cells + size_cells);
327 tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®);
328 debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells);
329 debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size);
331 /* No 'reg' property in this node. */
335 for (i = 0; i < tuples; i++) {
337 bank = fdt_data_get((void *)reg, 1);
341 /* Get address/size. */
342 rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start,
345 resource_list_free(&di->di_res);
348 reg += addr_cells - 1 + size_cells;
350 /* Calculate address range relative to VA base. */
351 start = sc->sc_banks[bank].va + start;
352 end = start + count - 1;
354 debugf("reg addr bank = %d, start = %lx, end = %lx, "
355 "count = %lx\n", bank, start, end, count);
357 /* Use bank (CS) cell as rid. */
358 resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start,
363 free(regptr, M_OFWPROP);
368 lbc_probe(device_t dev)
371 if (!(ofw_bus_is_compatible(dev, "fsl,lbc") ||
372 ofw_bus_is_compatible(dev, "fsl,elbc")))
375 device_set_desc(dev, "Freescale Local Bus Controller");
376 return (BUS_PROBE_DEFAULT);
380 lbc_attach(device_t dev)
382 struct lbc_softc *sc;
383 struct lbc_devinfo *di;
385 u_long offset, start, size;
387 phandle_t node, child;
388 pcell_t *ranges, *rangesptr;
389 int tuple_size, tuples;
393 sc = device_get_softc(dev);
397 sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid,
399 if (sc->sc_res == NULL)
402 sc->sc_bst = rman_get_bustag(sc->sc_res);
403 sc->sc_bsh = rman_get_bushandle(sc->sc_res);
407 rm->rm_type = RMAN_ARRAY;
408 rm->rm_descr = "Local Bus Space";
411 error = rman_init(rm);
415 error = rman_manage_region(rm, rm->rm_start, rm->rm_end);
422 * Process 'ranges' property.
424 node = ofw_bus_get_node(dev);
425 if ((fdt_addrsize_cells(node, &sc->sc_addr_cells,
426 &sc->sc_size_cells)) != 0) {
431 par_addr_cells = fdt_parent_addr_cells(node);
432 if (par_addr_cells > 2) {
433 device_printf(dev, "unsupported parent #addr-cells\n");
437 tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells +
440 tuples = OF_getprop_alloc(node, "ranges", tuple_size,
443 device_printf(dev, "could not retrieve 'ranges' property\n");
449 debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, "
450 "tuple_size = %d, tuples = %d\n", par_addr_cells,
451 sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples);
455 for (i = 0; i < tuples; i++) {
457 /* The first cell is the bank (chip select) number. */
458 bank = fdt_data_get((void *)ranges, 1);
459 if (bank < 0 || bank > LBC_DEV_MAX) {
460 device_printf(dev, "bank out of range: %d\n", bank);
467 * Remaining cells of the child address define offset into
470 offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1);
471 ranges += sc->sc_addr_cells - 1;
473 /* Parent bus start address of this bank. */
474 start = fdt_data_get((void *)ranges, par_addr_cells);
475 ranges += par_addr_cells;
477 size = fdt_data_get((void *)ranges, sc->sc_size_cells);
478 ranges += sc->sc_size_cells;
479 debugf("bank = %d, start = %lx, size = %lx\n", bank,
482 sc->sc_banks[bank].pa = start + offset;
483 sc->sc_banks[bank].size = size;
486 * Attributes for the bank.
488 * XXX Note there are no DT bindings defined for them at the
489 * moment, so we need to provide some defaults.
491 sc->sc_banks[bank].width = 16;
492 sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM;
493 sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED;
494 sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED;
495 sc->sc_banks[bank].wp = 0;
499 * Initialize mem-mappings for the LBC banks (i.e. chip selects).
501 error = lbc_banks_map(sc);
506 * Walk the localbus and add direct subordinates as our children.
508 for (child = OF_child(node); child != 0; child = OF_peer(child)) {
510 di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO);
512 if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) {
514 device_printf(dev, "could not set up devinfo\n");
518 resource_list_init(&di->di_res);
520 if (fdt_lbc_reg_decode(child, sc, di)) {
521 device_printf(dev, "could not process 'reg' "
523 ofw_bus_gen_destroy_devinfo(&di->di_ofw);
528 fdt_lbc_fixup(child, sc, di);
530 /* Add newbus device for this FDT node */
531 cdev = device_add_child(dev, NULL, -1);
533 device_printf(dev, "could not add child: %s\n",
534 di->di_ofw.obd_name);
535 resource_list_free(&di->di_res);
536 ofw_bus_gen_destroy_devinfo(&di->di_ofw);
540 debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name,
542 device_set_ivars(cdev, di);
548 lbc_banks_enable(sc);
550 free(rangesptr, M_OFWPROP);
551 return (bus_generic_attach(dev));
554 free(rangesptr, M_OFWPROP);
555 bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res);
560 lbc_shutdown(device_t dev)
567 static struct resource *
568 lbc_alloc_resource(device_t bus, device_t child, int type, int *rid,
569 u_long start, u_long end, u_long count, u_int flags)
571 struct lbc_softc *sc;
572 struct lbc_devinfo *di;
573 struct resource_list_entry *rle;
574 struct resource *res;
578 /* We only support default allocations. */
579 if (start != 0ul || end != ~0ul)
582 sc = device_get_softc(bus);
583 if (type == SYS_RES_IRQ)
584 return (bus_alloc_resource(bus, type, rid, start, end, count,
588 * Request for the default allocation with a given rid: use resource
589 * list stored in the local device info.
591 if ((di = device_get_ivars(child)) == NULL)
594 if (type == SYS_RES_IOPORT)
595 type = SYS_RES_MEMORY;
599 rle = resource_list_find(&di->di_res, type, *rid);
601 device_printf(bus, "no default resources for "
602 "rid = %d, type = %d\n", *rid, type);
607 end = start + count - 1;
609 sc = device_get_softc(bus);
611 needactivate = flags & RF_ACTIVE;
616 res = rman_reserve_resource(rm, start, end, count, flags, child);
618 device_printf(bus, "failed to reserve resource %#lx - %#lx "
619 "(%#lx)\n", start, end, count);
623 rman_set_rid(res, *rid);
624 rman_set_bustag(res, &bs_be_tag);
625 rman_set_bushandle(res, rman_get_start(res));
628 if (bus_activate_resource(child, type, *rid, res)) {
629 device_printf(child, "resource activation failed\n");
630 rman_release_resource(res);
638 lbc_print_child(device_t dev, device_t child)
640 struct lbc_devinfo *di;
641 struct resource_list *rl;
644 di = device_get_ivars(child);
648 rv += bus_print_child_header(dev, child);
649 rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
650 rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
651 rv += bus_print_child_footer(dev, child);
657 lbc_release_resource(device_t dev, device_t child, int type, int rid,
658 struct resource *res)
662 if (rman_get_flags(res) & RF_ACTIVE) {
663 err = bus_deactivate_resource(child, type, rid, res);
668 return (rman_release_resource(res));
671 static const struct ofw_bus_devinfo *
672 lbc_get_devinfo(device_t bus, device_t child)
674 struct lbc_devinfo *di;
676 di = device_get_ivars(child);
677 return (&di->di_ofw);