108077f58SMarcel Moolenaar /*- 208077f58SMarcel Moolenaar * Copyright (c) 2006-2008, Juniper Networks, Inc. 325c22eb4SRafal Jaworowski * Copyright (c) 2008 Semihalf, Rafal Czubak 4d1d3233eSRafal Jaworowski * Copyright (c) 2009 The FreeBSD Foundation 508077f58SMarcel Moolenaar * All rights reserved. 608077f58SMarcel Moolenaar * 7d1d3233eSRafal Jaworowski * Portions of this software were developed by Semihalf 8d1d3233eSRafal Jaworowski * under sponsorship from the FreeBSD Foundation. 9d1d3233eSRafal Jaworowski * 1008077f58SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 1108077f58SMarcel Moolenaar * modification, are permitted provided that the following conditions 1208077f58SMarcel Moolenaar * are met: 1308077f58SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1408077f58SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1508077f58SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1608077f58SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1708077f58SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 1808077f58SMarcel Moolenaar * 3. The name of the author may not be used to endorse or promote products 1908077f58SMarcel Moolenaar * derived from this software without specific prior written permission. 2008077f58SMarcel Moolenaar * 2108077f58SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2208077f58SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2308077f58SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2408077f58SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2508077f58SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2608077f58SMarcel Moolenaar * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2708077f58SMarcel Moolenaar * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2808077f58SMarcel Moolenaar * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2908077f58SMarcel Moolenaar * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3008077f58SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3108077f58SMarcel Moolenaar * SUCH DAMAGE. 3208077f58SMarcel Moolenaar */ 3308077f58SMarcel Moolenaar 3408077f58SMarcel Moolenaar #include <sys/cdefs.h> 3508077f58SMarcel Moolenaar __FBSDID("$FreeBSD$"); 3608077f58SMarcel Moolenaar 3708077f58SMarcel Moolenaar #include <sys/param.h> 3808077f58SMarcel Moolenaar #include <sys/systm.h> 3908077f58SMarcel Moolenaar #include <sys/ktr.h> 4008077f58SMarcel Moolenaar #include <sys/kernel.h> 4108077f58SMarcel Moolenaar #include <sys/malloc.h> 4208077f58SMarcel Moolenaar #include <sys/module.h> 4308077f58SMarcel Moolenaar #include <sys/bus.h> 4408077f58SMarcel Moolenaar #include <sys/rman.h> 4508077f58SMarcel Moolenaar #include <machine/bus.h> 4608077f58SMarcel Moolenaar 4708077f58SMarcel Moolenaar #include <vm/vm.h> 4808077f58SMarcel Moolenaar #include <vm/pmap.h> 4908077f58SMarcel Moolenaar 50d1d3233eSRafal Jaworowski #include <dev/fdt/fdt_common.h> 51d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 52d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 53d1d3233eSRafal Jaworowski 5425c22eb4SRafal Jaworowski #include <powerpc/mpc85xx/mpc85xx.h> 5508077f58SMarcel Moolenaar 56d1d3233eSRafal Jaworowski #include "ofw_bus_if.h" 57d1d3233eSRafal Jaworowski #include "lbc.h" 5808077f58SMarcel Moolenaar 59d1d3233eSRafal Jaworowski #ifdef DEBUG 60d1d3233eSRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 61d1d3233eSRafal Jaworowski printf(fmt,##args); } while (0) 62d1d3233eSRafal Jaworowski #else 63d1d3233eSRafal Jaworowski #define debugf(fmt, args...) 64d1d3233eSRafal Jaworowski #endif 6508077f58SMarcel Moolenaar 66d1d3233eSRafal Jaworowski static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); 67d1d3233eSRafal Jaworowski 68d1d3233eSRafal Jaworowski static int lbc_probe(device_t); 69d1d3233eSRafal Jaworowski static int lbc_attach(device_t); 70d1d3233eSRafal Jaworowski static int lbc_shutdown(device_t); 71d1d3233eSRafal Jaworowski static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 72d1d3233eSRafal Jaworowski u_long, u_long, u_long, u_int); 73d1d3233eSRafal Jaworowski static int lbc_print_child(device_t, device_t); 74d1d3233eSRafal Jaworowski static int lbc_release_resource(device_t, device_t, int, int, 75d1d3233eSRafal Jaworowski struct resource *); 76d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t); 77d1d3233eSRafal Jaworowski 78d1d3233eSRafal Jaworowski /* 79d1d3233eSRafal Jaworowski * Bus interface definition 80d1d3233eSRafal Jaworowski */ 81d1d3233eSRafal Jaworowski static device_method_t lbc_methods[] = { 82d1d3233eSRafal Jaworowski /* Device interface */ 83d1d3233eSRafal Jaworowski DEVMETHOD(device_probe, lbc_probe), 84d1d3233eSRafal Jaworowski DEVMETHOD(device_attach, lbc_attach), 85d1d3233eSRafal Jaworowski DEVMETHOD(device_shutdown, lbc_shutdown), 86d1d3233eSRafal Jaworowski 87d1d3233eSRafal Jaworowski /* Bus interface */ 88d1d3233eSRafal Jaworowski DEVMETHOD(bus_print_child, lbc_print_child), 89d1d3233eSRafal Jaworowski DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 90d1d3233eSRafal Jaworowski DEVMETHOD(bus_teardown_intr, NULL), 91d1d3233eSRafal Jaworowski 92d1d3233eSRafal Jaworowski DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 93d1d3233eSRafal Jaworowski DEVMETHOD(bus_release_resource, lbc_release_resource), 94d1d3233eSRafal Jaworowski DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 95d1d3233eSRafal Jaworowski DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 96d1d3233eSRafal Jaworowski 97d1d3233eSRafal Jaworowski /* OFW bus interface */ 98d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo), 99d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 100d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 101d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 102d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 103d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 104d1d3233eSRafal Jaworowski 105d1d3233eSRafal Jaworowski { 0, 0 } 106d1d3233eSRafal Jaworowski }; 107d1d3233eSRafal Jaworowski 108d1d3233eSRafal Jaworowski static driver_t lbc_driver = { 109d1d3233eSRafal Jaworowski "lbc", 110d1d3233eSRafal Jaworowski lbc_methods, 111d1d3233eSRafal Jaworowski sizeof(struct lbc_softc) 112d1d3233eSRafal Jaworowski }; 113d1d3233eSRafal Jaworowski 114d1d3233eSRafal Jaworowski devclass_t lbc_devclass; 115d1d3233eSRafal Jaworowski 116d1d3233eSRafal Jaworowski DRIVER_MODULE(lbc, fdtbus, lbc_driver, lbc_devclass, 0, 0); 117d1d3233eSRafal Jaworowski 11825c22eb4SRafal Jaworowski /* 11925c22eb4SRafal Jaworowski * Calculate address mask used by OR(n) registers. Use memory region size to 12025c22eb4SRafal Jaworowski * determine mask value. The size must be a power of two and within the range 12125c22eb4SRafal Jaworowski * of 32KB - 4GB. Otherwise error code is returned. Value representing 12225c22eb4SRafal Jaworowski * 4GB size can be passed as 0xffffffff. 12325c22eb4SRafal Jaworowski */ 12425c22eb4SRafal Jaworowski static uint32_t 12525c22eb4SRafal Jaworowski lbc_address_mask(uint32_t size) 12625c22eb4SRafal Jaworowski { 12725c22eb4SRafal Jaworowski int n = 15; 12825c22eb4SRafal Jaworowski 12925c22eb4SRafal Jaworowski if (size == ~0UL) 13025c22eb4SRafal Jaworowski return (0); 13125c22eb4SRafal Jaworowski 13225c22eb4SRafal Jaworowski while (n < 32) { 13325c22eb4SRafal Jaworowski if (size == (1UL << n)) 13425c22eb4SRafal Jaworowski break; 13525c22eb4SRafal Jaworowski n++; 13625c22eb4SRafal Jaworowski } 13725c22eb4SRafal Jaworowski 13825c22eb4SRafal Jaworowski if (n == 32) 13925c22eb4SRafal Jaworowski return (EINVAL); 14025c22eb4SRafal Jaworowski 14125c22eb4SRafal Jaworowski return (0xffff8000 << (n - 15)); 14225c22eb4SRafal Jaworowski } 14325c22eb4SRafal Jaworowski 144d1d3233eSRafal Jaworowski static void 145d1d3233eSRafal Jaworowski lbc_banks_unmap(struct lbc_softc *sc) 14608077f58SMarcel Moolenaar { 147f6703dd2SMarcel Moolenaar int r; 14808077f58SMarcel Moolenaar 149f6703dd2SMarcel Moolenaar r = 0; 150f6703dd2SMarcel Moolenaar while (r < LBC_DEV_MAX) { 151f6703dd2SMarcel Moolenaar if (sc->sc_range[r].size == 0) 152f6703dd2SMarcel Moolenaar return; 15325c22eb4SRafal Jaworowski 154f6703dd2SMarcel Moolenaar pmap_unmapdev(sc->sc_range[r].kva, sc->sc_range[r].size); 155f6703dd2SMarcel Moolenaar law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, 156f6703dd2SMarcel Moolenaar sc->sc_range[r].size); 157f6703dd2SMarcel Moolenaar r++; 15808077f58SMarcel Moolenaar } 15908077f58SMarcel Moolenaar } 16008077f58SMarcel Moolenaar 16108077f58SMarcel Moolenaar static int 162d1d3233eSRafal Jaworowski lbc_banks_map(struct lbc_softc *sc) 16325c22eb4SRafal Jaworowski { 164f6703dd2SMarcel Moolenaar vm_paddr_t end, start; 165f6703dd2SMarcel Moolenaar vm_size_t size; 166f6703dd2SMarcel Moolenaar u_int i, r, ranges, s; 167f6703dd2SMarcel Moolenaar int error; 16825c22eb4SRafal Jaworowski 169f6703dd2SMarcel Moolenaar bzero(sc->sc_range, sizeof(sc->sc_range)); 17025c22eb4SRafal Jaworowski 17125c22eb4SRafal Jaworowski /* 172f6703dd2SMarcel Moolenaar * Determine number of discontiguous address ranges to program. 17325c22eb4SRafal Jaworowski */ 174f6703dd2SMarcel Moolenaar ranges = 0; 175f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 176f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 177f6703dd2SMarcel Moolenaar if (size == 0) 178f6703dd2SMarcel Moolenaar continue; 179f6703dd2SMarcel Moolenaar 180f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 181f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 182f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 183f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 184f6703dd2SMarcel Moolenaar if (start > 0 && end == start - 1) { 185f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 186f6703dd2SMarcel Moolenaar break; 187f6703dd2SMarcel Moolenaar } 188f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 189f6703dd2SMarcel Moolenaar end = start - 1 + size; 190f6703dd2SMarcel Moolenaar if (sc->sc_range[r].addr > 0 && 191f6703dd2SMarcel Moolenaar end == sc->sc_range[r].addr - 1) { 192f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 193f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 194f6703dd2SMarcel Moolenaar break; 195f6703dd2SMarcel Moolenaar } 196f6703dd2SMarcel Moolenaar } 197f6703dd2SMarcel Moolenaar if (r == ranges) { 198f6703dd2SMarcel Moolenaar /* New range; add using insertion sort */ 199f6703dd2SMarcel Moolenaar r = 0; 200f6703dd2SMarcel Moolenaar while (r < ranges && sc->sc_range[r].addr < start) 201f6703dd2SMarcel Moolenaar r++; 202f6703dd2SMarcel Moolenaar for (s = ranges; s > r; s--) 203f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s-1]; 204f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 205f6703dd2SMarcel Moolenaar sc->sc_range[r].size = size; 206f6703dd2SMarcel Moolenaar ranges++; 207f6703dd2SMarcel Moolenaar } 208f6703dd2SMarcel Moolenaar } 209f6703dd2SMarcel Moolenaar 210f6703dd2SMarcel Moolenaar /* 211f6703dd2SMarcel Moolenaar * Ranges are sorted so quickly go over the list to merge ranges 212f6703dd2SMarcel Moolenaar * that grew toward each other while building the ranges. 213f6703dd2SMarcel Moolenaar */ 214f6703dd2SMarcel Moolenaar r = 0; 215f6703dd2SMarcel Moolenaar while (r < ranges - 1) { 216f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr + sc->sc_range[r].size; 217f6703dd2SMarcel Moolenaar if (end != sc->sc_range[r+1].addr) { 218f6703dd2SMarcel Moolenaar r++; 219f6703dd2SMarcel Moolenaar continue; 220f6703dd2SMarcel Moolenaar } 221f6703dd2SMarcel Moolenaar sc->sc_range[r].size += sc->sc_range[r+1].size; 222f6703dd2SMarcel Moolenaar for (s = r + 1; s < ranges - 1; s++) 223f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s+1]; 224f6703dd2SMarcel Moolenaar bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); 225f6703dd2SMarcel Moolenaar ranges--; 226f6703dd2SMarcel Moolenaar } 227f6703dd2SMarcel Moolenaar 228f6703dd2SMarcel Moolenaar /* 229f6703dd2SMarcel Moolenaar * Configure LAW for the LBC ranges and map the physical memory 230f6703dd2SMarcel Moolenaar * range into KVA. 231f6703dd2SMarcel Moolenaar */ 232f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 233f6703dd2SMarcel Moolenaar start = sc->sc_range[r].addr; 234f6703dd2SMarcel Moolenaar size = sc->sc_range[r].size; 23525c22eb4SRafal Jaworowski error = law_enable(OCP85XX_TGTIF_LBC, start, size); 23625c22eb4SRafal Jaworowski if (error) 23725c22eb4SRafal Jaworowski return (error); 238f6703dd2SMarcel Moolenaar sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); 239f6703dd2SMarcel Moolenaar } 24025c22eb4SRafal Jaworowski 241f6703dd2SMarcel Moolenaar /* XXX: need something better here? */ 242f6703dd2SMarcel Moolenaar if (ranges == 0) 243f6703dd2SMarcel Moolenaar return (EINVAL); 244f6703dd2SMarcel Moolenaar 245f6703dd2SMarcel Moolenaar /* Assign KVA to banks based on the enclosing range. */ 246f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 247f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 248f6703dd2SMarcel Moolenaar if (size == 0) 249f6703dd2SMarcel Moolenaar continue; 250f6703dd2SMarcel Moolenaar 251f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 252f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 253f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 254f6703dd2SMarcel Moolenaar if (start >= sc->sc_range[r].addr && 255f6703dd2SMarcel Moolenaar start - 1 + size <= end) 256f6703dd2SMarcel Moolenaar break; 257f6703dd2SMarcel Moolenaar } 258f6703dd2SMarcel Moolenaar if (r < ranges) { 259f6703dd2SMarcel Moolenaar sc->sc_banks[i].kva = sc->sc_range[r].kva + 260f6703dd2SMarcel Moolenaar (start - sc->sc_range[r].addr); 26125c22eb4SRafal Jaworowski } 262d1d3233eSRafal Jaworowski } 263f6703dd2SMarcel Moolenaar 264d1d3233eSRafal Jaworowski return (0); 265d1d3233eSRafal Jaworowski } 26625c22eb4SRafal Jaworowski 267d1d3233eSRafal Jaworowski static int 268d1d3233eSRafal Jaworowski lbc_banks_enable(struct lbc_softc *sc) 269d1d3233eSRafal Jaworowski { 270d1d3233eSRafal Jaworowski u_long size; 271d1d3233eSRafal Jaworowski uint32_t regval; 272d1d3233eSRafal Jaworowski int error, i; 273d1d3233eSRafal Jaworowski 274d1d3233eSRafal Jaworowski for (i = 0; i < LBC_DEV_MAX; i++) { 275d1d3233eSRafal Jaworowski size = sc->sc_banks[i].size; 276f6703dd2SMarcel Moolenaar if (size == 0) { 277f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 278f6703dd2SMarcel Moolenaar LBC85XX_BR(i), 0); 279f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 280f6703dd2SMarcel Moolenaar LBC85XX_OR(i), 0); 281d1d3233eSRafal Jaworowski continue; 282f6703dd2SMarcel Moolenaar } 283f6703dd2SMarcel Moolenaar 28425c22eb4SRafal Jaworowski /* 285d1d3233eSRafal Jaworowski * Compute and program BR value. 28625c22eb4SRafal Jaworowski */ 287f6703dd2SMarcel Moolenaar regval = sc->sc_banks[i].addr; 288d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].width) { 28925c22eb4SRafal Jaworowski case 8: 290d1d3233eSRafal Jaworowski regval |= (1 << 11); 29125c22eb4SRafal Jaworowski break; 29225c22eb4SRafal Jaworowski case 16: 293d1d3233eSRafal Jaworowski regval |= (2 << 11); 29425c22eb4SRafal Jaworowski break; 29525c22eb4SRafal Jaworowski case 32: 296d1d3233eSRafal Jaworowski regval |= (3 << 11); 29725c22eb4SRafal Jaworowski break; 29825c22eb4SRafal Jaworowski default: 29925c22eb4SRafal Jaworowski error = EINVAL; 30025c22eb4SRafal Jaworowski goto fail; 30125c22eb4SRafal Jaworowski } 302d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].decc << 9); 303d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].wp << 8); 304d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].msel << 5); 305d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].atom << 2); 306d1d3233eSRafal Jaworowski regval |= 1; 307f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 308f6703dd2SMarcel Moolenaar LBC85XX_BR(i), regval); 30925c22eb4SRafal Jaworowski 31025c22eb4SRafal Jaworowski /* 311d1d3233eSRafal Jaworowski * Compute and program OR value. 31225c22eb4SRafal Jaworowski */ 313f6703dd2SMarcel Moolenaar regval = lbc_address_mask(size); 314d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].msel) { 31525c22eb4SRafal Jaworowski case LBCRES_MSEL_GPCM: 31625c22eb4SRafal Jaworowski /* TODO Add flag support for option registers */ 317f6703dd2SMarcel Moolenaar regval |= 0x0ff7; 31825c22eb4SRafal Jaworowski break; 31925c22eb4SRafal Jaworowski case LBCRES_MSEL_FCM: 320f6703dd2SMarcel Moolenaar /* TODO Add flag support for options register */ 321f6703dd2SMarcel Moolenaar regval |= 0x0796; 322f6703dd2SMarcel Moolenaar break; 32325c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMA: 32425c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMB: 32525c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMC: 32625c22eb4SRafal Jaworowski printf("UPM mode not supported yet!"); 32725c22eb4SRafal Jaworowski error = ENOSYS; 32825c22eb4SRafal Jaworowski goto fail; 32925c22eb4SRafal Jaworowski } 330f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 331f6703dd2SMarcel Moolenaar LBC85XX_OR(i), regval); 332d1d3233eSRafal Jaworowski } 33325c22eb4SRafal Jaworowski 334d1d3233eSRafal Jaworowski /* 335d1d3233eSRafal Jaworowski * Initialize configuration register: 336d1d3233eSRafal Jaworowski * - enable Local Bus 337d1d3233eSRafal Jaworowski * - set data buffer control signal function 338d1d3233eSRafal Jaworowski * - disable parity byte select 339d1d3233eSRafal Jaworowski * - set ECC parity type 340d1d3233eSRafal Jaworowski * - set bus monitor timing and timer prescale 341d1d3233eSRafal Jaworowski */ 342f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); 343d1d3233eSRafal Jaworowski 344d1d3233eSRafal Jaworowski /* 345d1d3233eSRafal Jaworowski * Initialize clock ratio register: 346d1d3233eSRafal Jaworowski * - disable PLL bypass mode 347d1d3233eSRafal Jaworowski * - configure LCLK delay cycles for the assertion of LALE 348d1d3233eSRafal Jaworowski * - set system clock divider 349d1d3233eSRafal Jaworowski */ 350f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); 35125c22eb4SRafal Jaworowski return (0); 352d1d3233eSRafal Jaworowski 35325c22eb4SRafal Jaworowski fail: 354d1d3233eSRafal Jaworowski lbc_banks_unmap(sc); 35525c22eb4SRafal Jaworowski return (error); 356d1d3233eSRafal Jaworowski } 357d1d3233eSRafal Jaworowski 358d1d3233eSRafal Jaworowski static void 359d1d3233eSRafal Jaworowski fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di) 360d1d3233eSRafal Jaworowski { 361d1d3233eSRafal Jaworowski pcell_t width; 362d1d3233eSRafal Jaworowski int bank; 363d1d3233eSRafal Jaworowski 364d1d3233eSRafal Jaworowski if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0) 365d1d3233eSRafal Jaworowski return; 366d1d3233eSRafal Jaworowski 367d1d3233eSRafal Jaworowski bank = di->di_bank; 368d1d3233eSRafal Jaworowski if (sc->sc_banks[bank].size == 0) 369d1d3233eSRafal Jaworowski return; 370d1d3233eSRafal Jaworowski 371d1d3233eSRafal Jaworowski /* Express width in bits. */ 372d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = width * 8; 373d1d3233eSRafal Jaworowski } 374d1d3233eSRafal Jaworowski 375d1d3233eSRafal Jaworowski static int 376d1d3233eSRafal Jaworowski fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, 377d1d3233eSRafal Jaworowski struct lbc_devinfo *di) 378d1d3233eSRafal Jaworowski { 379d1d3233eSRafal Jaworowski u_long start, end, count; 380d1d3233eSRafal Jaworowski pcell_t *reg, *regptr; 381d1d3233eSRafal Jaworowski pcell_t addr_cells, size_cells; 382d1d3233eSRafal Jaworowski int tuple_size, tuples; 383d1d3233eSRafal Jaworowski int i, rv, bank; 384d1d3233eSRafal Jaworowski 385d1d3233eSRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 386d1d3233eSRafal Jaworowski return (ENXIO); 387d1d3233eSRafal Jaworowski 388d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 389d1d3233eSRafal Jaworowski tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 390d1d3233eSRafal Jaworowski debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 391d1d3233eSRafal Jaworowski debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 392d1d3233eSRafal Jaworowski if (tuples <= 0) 393d1d3233eSRafal Jaworowski /* No 'reg' property in this node. */ 394d1d3233eSRafal Jaworowski return (0); 395d1d3233eSRafal Jaworowski 396d1d3233eSRafal Jaworowski regptr = reg; 397d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 398d1d3233eSRafal Jaworowski 399d1d3233eSRafal Jaworowski bank = fdt_data_get((void *)reg, 1); 400d1d3233eSRafal Jaworowski di->di_bank = bank; 401d1d3233eSRafal Jaworowski reg += 1; 402d1d3233eSRafal Jaworowski 403d1d3233eSRafal Jaworowski /* Get address/size. */ 404d1d3233eSRafal Jaworowski rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start, 405d1d3233eSRafal Jaworowski &count); 406d1d3233eSRafal Jaworowski if (rv != 0) { 407d1d3233eSRafal Jaworowski resource_list_free(&di->di_res); 408d1d3233eSRafal Jaworowski goto out; 409d1d3233eSRafal Jaworowski } 410d1d3233eSRafal Jaworowski reg += addr_cells - 1 + size_cells; 411d1d3233eSRafal Jaworowski 412d1d3233eSRafal Jaworowski /* Calculate address range relative to VA base. */ 413f6703dd2SMarcel Moolenaar start = sc->sc_banks[bank].kva + start; 414d1d3233eSRafal Jaworowski end = start + count - 1; 415d1d3233eSRafal Jaworowski 416d1d3233eSRafal Jaworowski debugf("reg addr bank = %d, start = %lx, end = %lx, " 417d1d3233eSRafal Jaworowski "count = %lx\n", bank, start, end, count); 418d1d3233eSRafal Jaworowski 419d1d3233eSRafal Jaworowski /* Use bank (CS) cell as rid. */ 420d1d3233eSRafal Jaworowski resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start, 421d1d3233eSRafal Jaworowski end, count); 422d1d3233eSRafal Jaworowski } 423d1d3233eSRafal Jaworowski rv = 0; 424d1d3233eSRafal Jaworowski out: 425d1d3233eSRafal Jaworowski free(regptr, M_OFWPROP); 426d1d3233eSRafal Jaworowski return (rv); 42725c22eb4SRafal Jaworowski } 42825c22eb4SRafal Jaworowski 42925c22eb4SRafal Jaworowski static int 43008077f58SMarcel Moolenaar lbc_probe(device_t dev) 43108077f58SMarcel Moolenaar { 43208077f58SMarcel Moolenaar 433d1d3233eSRafal Jaworowski if (!(ofw_bus_is_compatible(dev, "fsl,lbc") || 434d1d3233eSRafal Jaworowski ofw_bus_is_compatible(dev, "fsl,elbc"))) 43508077f58SMarcel Moolenaar return (ENXIO); 43608077f58SMarcel Moolenaar 437d1d3233eSRafal Jaworowski device_set_desc(dev, "Freescale Local Bus Controller"); 43808077f58SMarcel Moolenaar return (BUS_PROBE_DEFAULT); 43908077f58SMarcel Moolenaar } 44008077f58SMarcel Moolenaar 44108077f58SMarcel Moolenaar static int 44208077f58SMarcel Moolenaar lbc_attach(device_t dev) 44308077f58SMarcel Moolenaar { 44408077f58SMarcel Moolenaar struct lbc_softc *sc; 445d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 44608077f58SMarcel Moolenaar struct rman *rm; 447d1d3233eSRafal Jaworowski u_long offset, start, size; 448d1d3233eSRafal Jaworowski device_t cdev; 449d1d3233eSRafal Jaworowski phandle_t node, child; 450d1d3233eSRafal Jaworowski pcell_t *ranges, *rangesptr; 451d1d3233eSRafal Jaworowski int tuple_size, tuples; 452d1d3233eSRafal Jaworowski int par_addr_cells; 453d1d3233eSRafal Jaworowski int bank, error, i; 45408077f58SMarcel Moolenaar 45508077f58SMarcel Moolenaar sc = device_get_softc(dev); 45608077f58SMarcel Moolenaar sc->sc_dev = dev; 45708077f58SMarcel Moolenaar 45808077f58SMarcel Moolenaar sc->sc_rid = 0; 45908077f58SMarcel Moolenaar sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_rid, 46008077f58SMarcel Moolenaar RF_ACTIVE); 46108077f58SMarcel Moolenaar if (sc->sc_res == NULL) 46208077f58SMarcel Moolenaar return (ENXIO); 46308077f58SMarcel Moolenaar 46408077f58SMarcel Moolenaar sc->sc_bst = rman_get_bustag(sc->sc_res); 46508077f58SMarcel Moolenaar sc->sc_bsh = rman_get_bushandle(sc->sc_res); 466d1d3233eSRafal Jaworowski rangesptr = NULL; 46708077f58SMarcel Moolenaar 46808077f58SMarcel Moolenaar rm = &sc->sc_rman; 46908077f58SMarcel Moolenaar rm->rm_type = RMAN_ARRAY; 470d1d3233eSRafal Jaworowski rm->rm_descr = "Local Bus Space"; 47125c22eb4SRafal Jaworowski rm->rm_start = 0UL; 47225c22eb4SRafal Jaworowski rm->rm_end = ~0UL; 47308077f58SMarcel Moolenaar error = rman_init(rm); 47408077f58SMarcel Moolenaar if (error) 47508077f58SMarcel Moolenaar goto fail; 47608077f58SMarcel Moolenaar 47708077f58SMarcel Moolenaar error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 47808077f58SMarcel Moolenaar if (error) { 47908077f58SMarcel Moolenaar rman_fini(rm); 48008077f58SMarcel Moolenaar goto fail; 48108077f58SMarcel Moolenaar } 48208077f58SMarcel Moolenaar 48325c22eb4SRafal Jaworowski /* 484d1d3233eSRafal Jaworowski * Process 'ranges' property. 48525c22eb4SRafal Jaworowski */ 486d1d3233eSRafal Jaworowski node = ofw_bus_get_node(dev); 487d1d3233eSRafal Jaworowski if ((fdt_addrsize_cells(node, &sc->sc_addr_cells, 488d1d3233eSRafal Jaworowski &sc->sc_size_cells)) != 0) { 48925c22eb4SRafal Jaworowski error = ENXIO; 49025c22eb4SRafal Jaworowski goto fail; 49125c22eb4SRafal Jaworowski } 49208077f58SMarcel Moolenaar 493d1d3233eSRafal Jaworowski par_addr_cells = fdt_parent_addr_cells(node); 494d1d3233eSRafal Jaworowski if (par_addr_cells > 2) { 495d1d3233eSRafal Jaworowski device_printf(dev, "unsupported parent #addr-cells\n"); 496d1d3233eSRafal Jaworowski error = ERANGE; 497d1d3233eSRafal Jaworowski goto fail; 498d1d3233eSRafal Jaworowski } 499d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells + 500d1d3233eSRafal Jaworowski sc->sc_size_cells); 501d1d3233eSRafal Jaworowski 502d1d3233eSRafal Jaworowski tuples = OF_getprop_alloc(node, "ranges", tuple_size, 503d1d3233eSRafal Jaworowski (void **)&ranges); 504d1d3233eSRafal Jaworowski if (tuples < 0) { 505d1d3233eSRafal Jaworowski device_printf(dev, "could not retrieve 'ranges' property\n"); 506d1d3233eSRafal Jaworowski error = ENXIO; 507d1d3233eSRafal Jaworowski goto fail; 508d1d3233eSRafal Jaworowski } 509d1d3233eSRafal Jaworowski rangesptr = ranges; 510d1d3233eSRafal Jaworowski 511d1d3233eSRafal Jaworowski debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, " 512d1d3233eSRafal Jaworowski "tuple_size = %d, tuples = %d\n", par_addr_cells, 513d1d3233eSRafal Jaworowski sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples); 514d1d3233eSRafal Jaworowski 515d1d3233eSRafal Jaworowski start = 0; 516d1d3233eSRafal Jaworowski size = 0; 517d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 518d1d3233eSRafal Jaworowski 519d1d3233eSRafal Jaworowski /* The first cell is the bank (chip select) number. */ 520d1d3233eSRafal Jaworowski bank = fdt_data_get((void *)ranges, 1); 521d1d3233eSRafal Jaworowski if (bank < 0 || bank > LBC_DEV_MAX) { 522d1d3233eSRafal Jaworowski device_printf(dev, "bank out of range: %d\n", bank); 523d1d3233eSRafal Jaworowski error = ERANGE; 524d1d3233eSRafal Jaworowski goto fail; 525d1d3233eSRafal Jaworowski } 526d1d3233eSRafal Jaworowski ranges += 1; 527d1d3233eSRafal Jaworowski 528d1d3233eSRafal Jaworowski /* 529d1d3233eSRafal Jaworowski * Remaining cells of the child address define offset into 530d1d3233eSRafal Jaworowski * this CS. 531d1d3233eSRafal Jaworowski */ 532d1d3233eSRafal Jaworowski offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1); 533d1d3233eSRafal Jaworowski ranges += sc->sc_addr_cells - 1; 534d1d3233eSRafal Jaworowski 535d1d3233eSRafal Jaworowski /* Parent bus start address of this bank. */ 536d1d3233eSRafal Jaworowski start = fdt_data_get((void *)ranges, par_addr_cells); 537d1d3233eSRafal Jaworowski ranges += par_addr_cells; 538d1d3233eSRafal Jaworowski 539d1d3233eSRafal Jaworowski size = fdt_data_get((void *)ranges, sc->sc_size_cells); 540d1d3233eSRafal Jaworowski ranges += sc->sc_size_cells; 541d1d3233eSRafal Jaworowski debugf("bank = %d, start = %lx, size = %lx\n", bank, 542d1d3233eSRafal Jaworowski start, size); 543d1d3233eSRafal Jaworowski 544f6703dd2SMarcel Moolenaar sc->sc_banks[bank].addr = start + offset; 545d1d3233eSRafal Jaworowski sc->sc_banks[bank].size = size; 546d1d3233eSRafal Jaworowski 547d1d3233eSRafal Jaworowski /* 548d1d3233eSRafal Jaworowski * Attributes for the bank. 549d1d3233eSRafal Jaworowski * 550d1d3233eSRafal Jaworowski * XXX Note there are no DT bindings defined for them at the 551d1d3233eSRafal Jaworowski * moment, so we need to provide some defaults. 552d1d3233eSRafal Jaworowski */ 553d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = 16; 554d1d3233eSRafal Jaworowski sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM; 555d1d3233eSRafal Jaworowski sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED; 556d1d3233eSRafal Jaworowski sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED; 557d1d3233eSRafal Jaworowski sc->sc_banks[bank].wp = 0; 558d1d3233eSRafal Jaworowski } 559d1d3233eSRafal Jaworowski 560d1d3233eSRafal Jaworowski /* 561d1d3233eSRafal Jaworowski * Initialize mem-mappings for the LBC banks (i.e. chip selects). 562d1d3233eSRafal Jaworowski */ 563d1d3233eSRafal Jaworowski error = lbc_banks_map(sc); 564d1d3233eSRafal Jaworowski if (error) 565d1d3233eSRafal Jaworowski goto fail; 566d1d3233eSRafal Jaworowski 567d1d3233eSRafal Jaworowski /* 568d1d3233eSRafal Jaworowski * Walk the localbus and add direct subordinates as our children. 569d1d3233eSRafal Jaworowski */ 570d1d3233eSRafal Jaworowski for (child = OF_child(node); child != 0; child = OF_peer(child)) { 571d1d3233eSRafal Jaworowski 572d1d3233eSRafal Jaworowski di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO); 573d1d3233eSRafal Jaworowski 574d1d3233eSRafal Jaworowski if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) { 575d1d3233eSRafal Jaworowski free(di, M_LBC); 576d1d3233eSRafal Jaworowski device_printf(dev, "could not set up devinfo\n"); 577d1d3233eSRafal Jaworowski continue; 578d1d3233eSRafal Jaworowski } 579d1d3233eSRafal Jaworowski 580d1d3233eSRafal Jaworowski resource_list_init(&di->di_res); 581d1d3233eSRafal Jaworowski 582d1d3233eSRafal Jaworowski if (fdt_lbc_reg_decode(child, sc, di)) { 583d1d3233eSRafal Jaworowski device_printf(dev, "could not process 'reg' " 584d1d3233eSRafal Jaworowski "property\n"); 585d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 586d1d3233eSRafal Jaworowski free(di, M_LBC); 587d1d3233eSRafal Jaworowski continue; 588d1d3233eSRafal Jaworowski } 589d1d3233eSRafal Jaworowski 590d1d3233eSRafal Jaworowski fdt_lbc_fixup(child, sc, di); 591d1d3233eSRafal Jaworowski 592d1d3233eSRafal Jaworowski /* Add newbus device for this FDT node */ 593d1d3233eSRafal Jaworowski cdev = device_add_child(dev, NULL, -1); 594d1d3233eSRafal Jaworowski if (cdev == NULL) { 595d1d3233eSRafal Jaworowski device_printf(dev, "could not add child: %s\n", 596d1d3233eSRafal Jaworowski di->di_ofw.obd_name); 597d1d3233eSRafal Jaworowski resource_list_free(&di->di_res); 598d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 599d1d3233eSRafal Jaworowski free(di, M_LBC); 600d1d3233eSRafal Jaworowski continue; 601d1d3233eSRafal Jaworowski } 602d1d3233eSRafal Jaworowski debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name, 603d1d3233eSRafal Jaworowski (void *)child); 604d1d3233eSRafal Jaworowski device_set_ivars(cdev, di); 605d1d3233eSRafal Jaworowski } 606d1d3233eSRafal Jaworowski 607d1d3233eSRafal Jaworowski /* 608d1d3233eSRafal Jaworowski * Enable the LBC. 609d1d3233eSRafal Jaworowski */ 610d1d3233eSRafal Jaworowski lbc_banks_enable(sc); 611d1d3233eSRafal Jaworowski 612d1d3233eSRafal Jaworowski free(rangesptr, M_OFWPROP); 61308077f58SMarcel Moolenaar return (bus_generic_attach(dev)); 61408077f58SMarcel Moolenaar 61508077f58SMarcel Moolenaar fail: 616d1d3233eSRafal Jaworowski free(rangesptr, M_OFWPROP); 61708077f58SMarcel Moolenaar bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rid, sc->sc_res); 61808077f58SMarcel Moolenaar return (error); 61908077f58SMarcel Moolenaar } 62008077f58SMarcel Moolenaar 62108077f58SMarcel Moolenaar static int 62208077f58SMarcel Moolenaar lbc_shutdown(device_t dev) 62308077f58SMarcel Moolenaar { 62408077f58SMarcel Moolenaar 62508077f58SMarcel Moolenaar /* TODO */ 62608077f58SMarcel Moolenaar return(0); 62708077f58SMarcel Moolenaar } 62808077f58SMarcel Moolenaar 62908077f58SMarcel Moolenaar static struct resource * 630d1d3233eSRafal Jaworowski lbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 63108077f58SMarcel Moolenaar u_long start, u_long end, u_long count, u_int flags) 63208077f58SMarcel Moolenaar { 63308077f58SMarcel Moolenaar struct lbc_softc *sc; 634d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 635d1d3233eSRafal Jaworowski struct resource_list_entry *rle; 636d1d3233eSRafal Jaworowski struct resource *res; 63708077f58SMarcel Moolenaar struct rman *rm; 638d1d3233eSRafal Jaworowski int needactivate; 63908077f58SMarcel Moolenaar 64008077f58SMarcel Moolenaar /* We only support default allocations. */ 64108077f58SMarcel Moolenaar if (start != 0ul || end != ~0ul) 64208077f58SMarcel Moolenaar return (NULL); 64308077f58SMarcel Moolenaar 644d1d3233eSRafal Jaworowski sc = device_get_softc(bus); 64508077f58SMarcel Moolenaar if (type == SYS_RES_IRQ) 646d1d3233eSRafal Jaworowski return (bus_alloc_resource(bus, type, rid, start, end, count, 64708077f58SMarcel Moolenaar flags)); 64808077f58SMarcel Moolenaar 649d1d3233eSRafal Jaworowski /* 650d1d3233eSRafal Jaworowski * Request for the default allocation with a given rid: use resource 651d1d3233eSRafal Jaworowski * list stored in the local device info. 652d1d3233eSRafal Jaworowski */ 653d1d3233eSRafal Jaworowski if ((di = device_get_ivars(child)) == NULL) 654d1d3233eSRafal Jaworowski return (NULL); 655d1d3233eSRafal Jaworowski 656d1d3233eSRafal Jaworowski if (type == SYS_RES_IOPORT) 657d1d3233eSRafal Jaworowski type = SYS_RES_MEMORY; 658d1d3233eSRafal Jaworowski 659d1d3233eSRafal Jaworowski rid = &di->di_bank; 660d1d3233eSRafal Jaworowski 661d1d3233eSRafal Jaworowski rle = resource_list_find(&di->di_res, type, *rid); 662d1d3233eSRafal Jaworowski if (rle == NULL) { 663d1d3233eSRafal Jaworowski device_printf(bus, "no default resources for " 664d1d3233eSRafal Jaworowski "rid = %d, type = %d\n", *rid, type); 66525c22eb4SRafal Jaworowski return (NULL); 66625c22eb4SRafal Jaworowski } 667d1d3233eSRafal Jaworowski start = rle->start; 668d1d3233eSRafal Jaworowski count = rle->count; 669d1d3233eSRafal Jaworowski end = start + count - 1; 67025c22eb4SRafal Jaworowski 671d1d3233eSRafal Jaworowski sc = device_get_softc(bus); 672d1d3233eSRafal Jaworowski 673d1d3233eSRafal Jaworowski needactivate = flags & RF_ACTIVE; 674d1d3233eSRafal Jaworowski flags &= ~RF_ACTIVE; 67508077f58SMarcel Moolenaar 67608077f58SMarcel Moolenaar rm = &sc->sc_rman; 677d1d3233eSRafal Jaworowski 678d1d3233eSRafal Jaworowski res = rman_reserve_resource(rm, start, end, count, flags, child); 679d1d3233eSRafal Jaworowski if (res == NULL) { 680d1d3233eSRafal Jaworowski device_printf(bus, "failed to reserve resource %#lx - %#lx " 681d1d3233eSRafal Jaworowski "(%#lx)\n", start, end, count); 682d1d3233eSRafal Jaworowski return (NULL); 68308077f58SMarcel Moolenaar } 684d1d3233eSRafal Jaworowski 685d1d3233eSRafal Jaworowski rman_set_rid(res, *rid); 686d1d3233eSRafal Jaworowski rman_set_bustag(res, &bs_be_tag); 687d1d3233eSRafal Jaworowski rman_set_bushandle(res, rman_get_start(res)); 688d1d3233eSRafal Jaworowski 689d1d3233eSRafal Jaworowski if (needactivate) 690d1d3233eSRafal Jaworowski if (bus_activate_resource(child, type, *rid, res)) { 691d1d3233eSRafal Jaworowski device_printf(child, "resource activation failed\n"); 692d1d3233eSRafal Jaworowski rman_release_resource(res); 693d1d3233eSRafal Jaworowski return (NULL); 694d1d3233eSRafal Jaworowski } 695d1d3233eSRafal Jaworowski 696d1d3233eSRafal Jaworowski return (res); 69708077f58SMarcel Moolenaar } 69808077f58SMarcel Moolenaar 69908077f58SMarcel Moolenaar static int 70008077f58SMarcel Moolenaar lbc_print_child(device_t dev, device_t child) 70108077f58SMarcel Moolenaar { 702d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 703d1d3233eSRafal Jaworowski struct resource_list *rl; 704d1d3233eSRafal Jaworowski int rv; 70508077f58SMarcel Moolenaar 706d1d3233eSRafal Jaworowski di = device_get_ivars(child); 707d1d3233eSRafal Jaworowski rl = &di->di_res; 70808077f58SMarcel Moolenaar 709d1d3233eSRafal Jaworowski rv = 0; 710d1d3233eSRafal Jaworowski rv += bus_print_child_header(dev, child); 711d1d3233eSRafal Jaworowski rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 712d1d3233eSRafal Jaworowski rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 713d1d3233eSRafal Jaworowski rv += bus_print_child_footer(dev, child); 71408077f58SMarcel Moolenaar 715d1d3233eSRafal Jaworowski return (rv); 71608077f58SMarcel Moolenaar } 71708077f58SMarcel Moolenaar 71808077f58SMarcel Moolenaar static int 71908077f58SMarcel Moolenaar lbc_release_resource(device_t dev, device_t child, int type, int rid, 72008077f58SMarcel Moolenaar struct resource *res) 72108077f58SMarcel Moolenaar { 722d1d3233eSRafal Jaworowski int err; 723d1d3233eSRafal Jaworowski 724d1d3233eSRafal Jaworowski if (rman_get_flags(res) & RF_ACTIVE) { 725d1d3233eSRafal Jaworowski err = bus_deactivate_resource(child, type, rid, res); 726d1d3233eSRafal Jaworowski if (err) 727d1d3233eSRafal Jaworowski return (err); 728d1d3233eSRafal Jaworowski } 72908077f58SMarcel Moolenaar 73008077f58SMarcel Moolenaar return (rman_release_resource(res)); 73108077f58SMarcel Moolenaar } 73208077f58SMarcel Moolenaar 733d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo * 734d1d3233eSRafal Jaworowski lbc_get_devinfo(device_t bus, device_t child) 73508077f58SMarcel Moolenaar { 736d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 73708077f58SMarcel Moolenaar 738d1d3233eSRafal Jaworowski di = device_get_ivars(child); 739d1d3233eSRafal Jaworowski return (&di->di_ofw); 74008077f58SMarcel Moolenaar } 741f6703dd2SMarcel Moolenaar 742f6703dd2SMarcel Moolenaar void 743f6703dd2SMarcel Moolenaar lbc_write_reg(device_t child, u_int off, uint32_t val) 744f6703dd2SMarcel Moolenaar { 745f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 746f6703dd2SMarcel Moolenaar 747f6703dd2SMarcel Moolenaar sc = device_get_softc(device_get_parent(child)); 748f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 749f6703dd2SMarcel Moolenaar } 750f6703dd2SMarcel Moolenaar 751f6703dd2SMarcel Moolenaar uint32_t 752f6703dd2SMarcel Moolenaar lbc_read_reg(device_t child, u_int off) 753f6703dd2SMarcel Moolenaar { 754f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 755f6703dd2SMarcel Moolenaar 756f6703dd2SMarcel Moolenaar sc = device_get_softc(device_get_parent(child)); 757f6703dd2SMarcel Moolenaar return (bus_space_read_4(sc->sc_bst, sc->sc_bsh, off)); 758f6703dd2SMarcel Moolenaar } 759