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 348bc8506eSJustin Hibbits #include "opt_platform.h" 358bc8506eSJustin Hibbits 3608077f58SMarcel Moolenaar #include <sys/cdefs.h> 3708077f58SMarcel Moolenaar __FBSDID("$FreeBSD$"); 3808077f58SMarcel Moolenaar 3908077f58SMarcel Moolenaar #include <sys/param.h> 4008077f58SMarcel Moolenaar #include <sys/systm.h> 4108077f58SMarcel Moolenaar #include <sys/ktr.h> 4208077f58SMarcel Moolenaar #include <sys/kernel.h> 4308077f58SMarcel Moolenaar #include <sys/malloc.h> 4408077f58SMarcel Moolenaar #include <sys/module.h> 4508077f58SMarcel Moolenaar #include <sys/bus.h> 4608077f58SMarcel Moolenaar #include <sys/rman.h> 4708077f58SMarcel Moolenaar #include <machine/bus.h> 4808077f58SMarcel Moolenaar 4908077f58SMarcel Moolenaar #include <vm/vm.h> 5008077f58SMarcel Moolenaar #include <vm/pmap.h> 5108077f58SMarcel Moolenaar 52d1d3233eSRafal Jaworowski #include <dev/fdt/fdt_common.h> 53d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 54d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 55d1d3233eSRafal Jaworowski 5625c22eb4SRafal Jaworowski #include <powerpc/mpc85xx/mpc85xx.h> 5708077f58SMarcel Moolenaar 58d1d3233eSRafal Jaworowski #include "ofw_bus_if.h" 59d1d3233eSRafal Jaworowski #include "lbc.h" 6008077f58SMarcel Moolenaar 61d1d3233eSRafal Jaworowski #ifdef DEBUG 62d1d3233eSRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 63d1d3233eSRafal Jaworowski printf(fmt,##args); } while (0) 64d1d3233eSRafal Jaworowski #else 65d1d3233eSRafal Jaworowski #define debugf(fmt, args...) 66d1d3233eSRafal Jaworowski #endif 6708077f58SMarcel Moolenaar 68d1d3233eSRafal Jaworowski static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); 69d1d3233eSRafal Jaworowski 70d1d3233eSRafal Jaworowski static int lbc_probe(device_t); 71d1d3233eSRafal Jaworowski static int lbc_attach(device_t); 72d1d3233eSRafal Jaworowski static int lbc_shutdown(device_t); 738bc8506eSJustin Hibbits static int lbc_activate_resource(device_t bus __unused, device_t child __unused, 748bc8506eSJustin Hibbits int type, int rid __unused, struct resource *r); 758bc8506eSJustin Hibbits static int lbc_deactivate_resource(device_t bus __unused, 768bc8506eSJustin Hibbits device_t child __unused, int type __unused, int rid __unused, 778bc8506eSJustin Hibbits struct resource *r); 78d1d3233eSRafal Jaworowski static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 792dd1bdf1SJustin Hibbits rman_res_t, rman_res_t, rman_res_t, u_int); 80d1d3233eSRafal Jaworowski static int lbc_print_child(device_t, device_t); 81d1d3233eSRafal Jaworowski static int lbc_release_resource(device_t, device_t, int, int, 82d1d3233eSRafal Jaworowski struct resource *); 83d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t); 84d1d3233eSRafal Jaworowski 85d1d3233eSRafal Jaworowski /* 86d1d3233eSRafal Jaworowski * Bus interface definition 87d1d3233eSRafal Jaworowski */ 88d1d3233eSRafal Jaworowski static device_method_t lbc_methods[] = { 89d1d3233eSRafal Jaworowski /* Device interface */ 90d1d3233eSRafal Jaworowski DEVMETHOD(device_probe, lbc_probe), 91d1d3233eSRafal Jaworowski DEVMETHOD(device_attach, lbc_attach), 92d1d3233eSRafal Jaworowski DEVMETHOD(device_shutdown, lbc_shutdown), 93d1d3233eSRafal Jaworowski 94d1d3233eSRafal Jaworowski /* Bus interface */ 95d1d3233eSRafal Jaworowski DEVMETHOD(bus_print_child, lbc_print_child), 96d1d3233eSRafal Jaworowski DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 97d1d3233eSRafal Jaworowski DEVMETHOD(bus_teardown_intr, NULL), 98d1d3233eSRafal Jaworowski 99d1d3233eSRafal Jaworowski DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 100d1d3233eSRafal Jaworowski DEVMETHOD(bus_release_resource, lbc_release_resource), 1018bc8506eSJustin Hibbits DEVMETHOD(bus_activate_resource, lbc_activate_resource), 1028bc8506eSJustin Hibbits DEVMETHOD(bus_deactivate_resource, lbc_deactivate_resource), 103d1d3233eSRafal Jaworowski 104d1d3233eSRafal Jaworowski /* OFW bus interface */ 105d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo), 106d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 107d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 108d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 109d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 110d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 111d1d3233eSRafal Jaworowski 112d1d3233eSRafal Jaworowski { 0, 0 } 113d1d3233eSRafal Jaworowski }; 114d1d3233eSRafal Jaworowski 115d1d3233eSRafal Jaworowski static driver_t lbc_driver = { 116d1d3233eSRafal Jaworowski "lbc", 117d1d3233eSRafal Jaworowski lbc_methods, 118d1d3233eSRafal Jaworowski sizeof(struct lbc_softc) 119d1d3233eSRafal Jaworowski }; 120d1d3233eSRafal Jaworowski 121d1d3233eSRafal Jaworowski devclass_t lbc_devclass; 122d1d3233eSRafal Jaworowski 12312cb797eSJustin Hibbits EARLY_DRIVER_MODULE(lbc, ofwbus, lbc_driver, lbc_devclass, 12412cb797eSJustin Hibbits 0, 0, BUS_PASS_BUS); 125d1d3233eSRafal Jaworowski 12625c22eb4SRafal Jaworowski /* 12725c22eb4SRafal Jaworowski * Calculate address mask used by OR(n) registers. Use memory region size to 12825c22eb4SRafal Jaworowski * determine mask value. The size must be a power of two and within the range 12925c22eb4SRafal Jaworowski * of 32KB - 4GB. Otherwise error code is returned. Value representing 13025c22eb4SRafal Jaworowski * 4GB size can be passed as 0xffffffff. 13125c22eb4SRafal Jaworowski */ 13225c22eb4SRafal Jaworowski static uint32_t 13325c22eb4SRafal Jaworowski lbc_address_mask(uint32_t size) 13425c22eb4SRafal Jaworowski { 13525c22eb4SRafal Jaworowski int n = 15; 13625c22eb4SRafal Jaworowski 137295be330SJustin Hibbits if (size == ~0) 13825c22eb4SRafal Jaworowski return (0); 13925c22eb4SRafal Jaworowski 14025c22eb4SRafal Jaworowski while (n < 32) { 141295be330SJustin Hibbits if (size == (1U << n)) 14225c22eb4SRafal Jaworowski break; 14325c22eb4SRafal Jaworowski n++; 14425c22eb4SRafal Jaworowski } 14525c22eb4SRafal Jaworowski 14625c22eb4SRafal Jaworowski if (n == 32) 14725c22eb4SRafal Jaworowski return (EINVAL); 14825c22eb4SRafal Jaworowski 14925c22eb4SRafal Jaworowski return (0xffff8000 << (n - 15)); 15025c22eb4SRafal Jaworowski } 15125c22eb4SRafal Jaworowski 152d1d3233eSRafal Jaworowski static void 153d1d3233eSRafal Jaworowski lbc_banks_unmap(struct lbc_softc *sc) 15408077f58SMarcel Moolenaar { 155f6703dd2SMarcel Moolenaar int r; 15608077f58SMarcel Moolenaar 157f6703dd2SMarcel Moolenaar r = 0; 158f6703dd2SMarcel Moolenaar while (r < LBC_DEV_MAX) { 159f6703dd2SMarcel Moolenaar if (sc->sc_range[r].size == 0) 160f6703dd2SMarcel Moolenaar return; 16125c22eb4SRafal Jaworowski 162f6703dd2SMarcel Moolenaar pmap_unmapdev(sc->sc_range[r].kva, sc->sc_range[r].size); 163f6703dd2SMarcel Moolenaar law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, 164f6703dd2SMarcel Moolenaar sc->sc_range[r].size); 165f6703dd2SMarcel Moolenaar r++; 16608077f58SMarcel Moolenaar } 16708077f58SMarcel Moolenaar } 16808077f58SMarcel Moolenaar 16908077f58SMarcel Moolenaar static int 170d1d3233eSRafal Jaworowski lbc_banks_map(struct lbc_softc *sc) 17125c22eb4SRafal Jaworowski { 172f6703dd2SMarcel Moolenaar vm_paddr_t end, start; 173f6703dd2SMarcel Moolenaar vm_size_t size; 174f6703dd2SMarcel Moolenaar u_int i, r, ranges, s; 175f6703dd2SMarcel Moolenaar int error; 17625c22eb4SRafal Jaworowski 177f6703dd2SMarcel Moolenaar bzero(sc->sc_range, sizeof(sc->sc_range)); 17825c22eb4SRafal Jaworowski 17925c22eb4SRafal Jaworowski /* 180f6703dd2SMarcel Moolenaar * Determine number of discontiguous address ranges to program. 18125c22eb4SRafal Jaworowski */ 182f6703dd2SMarcel Moolenaar ranges = 0; 183f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 184f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 185f6703dd2SMarcel Moolenaar if (size == 0) 186f6703dd2SMarcel Moolenaar continue; 187f6703dd2SMarcel Moolenaar 188f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 189f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 190f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 191f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 192f6703dd2SMarcel Moolenaar if (start > 0 && end == start - 1) { 193f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 194f6703dd2SMarcel Moolenaar break; 195f6703dd2SMarcel Moolenaar } 196f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 197f6703dd2SMarcel Moolenaar end = start - 1 + size; 198f6703dd2SMarcel Moolenaar if (sc->sc_range[r].addr > 0 && 199f6703dd2SMarcel Moolenaar end == sc->sc_range[r].addr - 1) { 200f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 201f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 202f6703dd2SMarcel Moolenaar break; 203f6703dd2SMarcel Moolenaar } 204f6703dd2SMarcel Moolenaar } 205f6703dd2SMarcel Moolenaar if (r == ranges) { 206f6703dd2SMarcel Moolenaar /* New range; add using insertion sort */ 207f6703dd2SMarcel Moolenaar r = 0; 208f6703dd2SMarcel Moolenaar while (r < ranges && sc->sc_range[r].addr < start) 209f6703dd2SMarcel Moolenaar r++; 210f6703dd2SMarcel Moolenaar for (s = ranges; s > r; s--) 211f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s-1]; 212f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 213f6703dd2SMarcel Moolenaar sc->sc_range[r].size = size; 214f6703dd2SMarcel Moolenaar ranges++; 215f6703dd2SMarcel Moolenaar } 216f6703dd2SMarcel Moolenaar } 217f6703dd2SMarcel Moolenaar 218f6703dd2SMarcel Moolenaar /* 219f6703dd2SMarcel Moolenaar * Ranges are sorted so quickly go over the list to merge ranges 220f6703dd2SMarcel Moolenaar * that grew toward each other while building the ranges. 221f6703dd2SMarcel Moolenaar */ 222f6703dd2SMarcel Moolenaar r = 0; 223f6703dd2SMarcel Moolenaar while (r < ranges - 1) { 224f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr + sc->sc_range[r].size; 225f6703dd2SMarcel Moolenaar if (end != sc->sc_range[r+1].addr) { 226f6703dd2SMarcel Moolenaar r++; 227f6703dd2SMarcel Moolenaar continue; 228f6703dd2SMarcel Moolenaar } 229f6703dd2SMarcel Moolenaar sc->sc_range[r].size += sc->sc_range[r+1].size; 230f6703dd2SMarcel Moolenaar for (s = r + 1; s < ranges - 1; s++) 231f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s+1]; 232f6703dd2SMarcel Moolenaar bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); 233f6703dd2SMarcel Moolenaar ranges--; 234f6703dd2SMarcel Moolenaar } 235f6703dd2SMarcel Moolenaar 236f6703dd2SMarcel Moolenaar /* 237f6703dd2SMarcel Moolenaar * Configure LAW for the LBC ranges and map the physical memory 238f6703dd2SMarcel Moolenaar * range into KVA. 239f6703dd2SMarcel Moolenaar */ 240f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 241f6703dd2SMarcel Moolenaar start = sc->sc_range[r].addr; 242f6703dd2SMarcel Moolenaar size = sc->sc_range[r].size; 24325c22eb4SRafal Jaworowski error = law_enable(OCP85XX_TGTIF_LBC, start, size); 24425c22eb4SRafal Jaworowski if (error) 24525c22eb4SRafal Jaworowski return (error); 246f6703dd2SMarcel Moolenaar sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); 247f6703dd2SMarcel Moolenaar } 24825c22eb4SRafal Jaworowski 249f6703dd2SMarcel Moolenaar /* XXX: need something better here? */ 250f6703dd2SMarcel Moolenaar if (ranges == 0) 251f6703dd2SMarcel Moolenaar return (EINVAL); 252f6703dd2SMarcel Moolenaar 253f6703dd2SMarcel Moolenaar /* Assign KVA to banks based on the enclosing range. */ 254f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 255f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 256f6703dd2SMarcel Moolenaar if (size == 0) 257f6703dd2SMarcel Moolenaar continue; 258f6703dd2SMarcel Moolenaar 259f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 260f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 261f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 262f6703dd2SMarcel Moolenaar if (start >= sc->sc_range[r].addr && 263f6703dd2SMarcel Moolenaar start - 1 + size <= end) 264f6703dd2SMarcel Moolenaar break; 265f6703dd2SMarcel Moolenaar } 266f6703dd2SMarcel Moolenaar if (r < ranges) { 267f6703dd2SMarcel Moolenaar sc->sc_banks[i].kva = sc->sc_range[r].kva + 268f6703dd2SMarcel Moolenaar (start - sc->sc_range[r].addr); 26925c22eb4SRafal Jaworowski } 270d1d3233eSRafal Jaworowski } 271f6703dd2SMarcel Moolenaar 272d1d3233eSRafal Jaworowski return (0); 273d1d3233eSRafal Jaworowski } 27425c22eb4SRafal Jaworowski 275d1d3233eSRafal Jaworowski static int 276d1d3233eSRafal Jaworowski lbc_banks_enable(struct lbc_softc *sc) 277d1d3233eSRafal Jaworowski { 278295be330SJustin Hibbits uint32_t size; 279d1d3233eSRafal Jaworowski uint32_t regval; 280d1d3233eSRafal Jaworowski int error, i; 281d1d3233eSRafal Jaworowski 282d1d3233eSRafal Jaworowski for (i = 0; i < LBC_DEV_MAX; i++) { 283d1d3233eSRafal Jaworowski size = sc->sc_banks[i].size; 28423fbc06bSMarcel Moolenaar if (size == 0) 285d1d3233eSRafal Jaworowski continue; 286f6703dd2SMarcel Moolenaar 28725c22eb4SRafal Jaworowski /* 288d1d3233eSRafal Jaworowski * Compute and program BR value. 28925c22eb4SRafal Jaworowski */ 290f6703dd2SMarcel Moolenaar regval = sc->sc_banks[i].addr; 291d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].width) { 29225c22eb4SRafal Jaworowski case 8: 293d1d3233eSRafal Jaworowski regval |= (1 << 11); 29425c22eb4SRafal Jaworowski break; 29525c22eb4SRafal Jaworowski case 16: 296d1d3233eSRafal Jaworowski regval |= (2 << 11); 29725c22eb4SRafal Jaworowski break; 29825c22eb4SRafal Jaworowski case 32: 299d1d3233eSRafal Jaworowski regval |= (3 << 11); 30025c22eb4SRafal Jaworowski break; 30125c22eb4SRafal Jaworowski default: 30225c22eb4SRafal Jaworowski error = EINVAL; 30325c22eb4SRafal Jaworowski goto fail; 30425c22eb4SRafal Jaworowski } 305d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].decc << 9); 306d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].wp << 8); 307d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].msel << 5); 308d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].atom << 2); 309d1d3233eSRafal Jaworowski regval |= 1; 310f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 311f6703dd2SMarcel Moolenaar LBC85XX_BR(i), regval); 31225c22eb4SRafal Jaworowski 31325c22eb4SRafal Jaworowski /* 314d1d3233eSRafal Jaworowski * Compute and program OR value. 31525c22eb4SRafal Jaworowski */ 316f6703dd2SMarcel Moolenaar regval = lbc_address_mask(size); 317d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].msel) { 31825c22eb4SRafal Jaworowski case LBCRES_MSEL_GPCM: 31925c22eb4SRafal Jaworowski /* TODO Add flag support for option registers */ 320f6703dd2SMarcel Moolenaar regval |= 0x0ff7; 32125c22eb4SRafal Jaworowski break; 32225c22eb4SRafal Jaworowski case LBCRES_MSEL_FCM: 323f6703dd2SMarcel Moolenaar /* TODO Add flag support for options register */ 324f6703dd2SMarcel Moolenaar regval |= 0x0796; 325f6703dd2SMarcel Moolenaar break; 32625c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMA: 32725c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMB: 32825c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMC: 32925c22eb4SRafal Jaworowski printf("UPM mode not supported yet!"); 33025c22eb4SRafal Jaworowski error = ENOSYS; 33125c22eb4SRafal Jaworowski goto fail; 33225c22eb4SRafal Jaworowski } 333f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 334f6703dd2SMarcel Moolenaar LBC85XX_OR(i), regval); 335d1d3233eSRafal Jaworowski } 33625c22eb4SRafal Jaworowski 33725c22eb4SRafal Jaworowski return (0); 338d1d3233eSRafal Jaworowski 33925c22eb4SRafal Jaworowski fail: 340d1d3233eSRafal Jaworowski lbc_banks_unmap(sc); 34125c22eb4SRafal Jaworowski return (error); 342d1d3233eSRafal Jaworowski } 343d1d3233eSRafal Jaworowski 344d1d3233eSRafal Jaworowski static void 345d1d3233eSRafal Jaworowski fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di) 346d1d3233eSRafal Jaworowski { 347d1d3233eSRafal Jaworowski pcell_t width; 348d1d3233eSRafal Jaworowski int bank; 349d1d3233eSRafal Jaworowski 350d1d3233eSRafal Jaworowski if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0) 351d1d3233eSRafal Jaworowski return; 352d1d3233eSRafal Jaworowski 353d1d3233eSRafal Jaworowski bank = di->di_bank; 354d1d3233eSRafal Jaworowski if (sc->sc_banks[bank].size == 0) 355d1d3233eSRafal Jaworowski return; 356d1d3233eSRafal Jaworowski 357d1d3233eSRafal Jaworowski /* Express width in bits. */ 358d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = width * 8; 359d1d3233eSRafal Jaworowski } 360d1d3233eSRafal Jaworowski 361d1d3233eSRafal Jaworowski static int 362d1d3233eSRafal Jaworowski fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, 363d1d3233eSRafal Jaworowski struct lbc_devinfo *di) 364d1d3233eSRafal Jaworowski { 365d1d3233eSRafal Jaworowski u_long start, end, count; 366d1d3233eSRafal Jaworowski pcell_t *reg, *regptr; 367d1d3233eSRafal Jaworowski pcell_t addr_cells, size_cells; 368d1d3233eSRafal Jaworowski int tuple_size, tuples; 369d1d3233eSRafal Jaworowski int i, rv, bank; 370d1d3233eSRafal Jaworowski 371d1d3233eSRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 372d1d3233eSRafal Jaworowski return (ENXIO); 373d1d3233eSRafal Jaworowski 374d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 375d1d3233eSRafal Jaworowski tuples = OF_getprop_alloc(node, "reg", tuple_size, (void **)®); 376d1d3233eSRafal Jaworowski debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 377d1d3233eSRafal Jaworowski debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 378d1d3233eSRafal Jaworowski if (tuples <= 0) 379d1d3233eSRafal Jaworowski /* No 'reg' property in this node. */ 380d1d3233eSRafal Jaworowski return (0); 381d1d3233eSRafal Jaworowski 382d1d3233eSRafal Jaworowski regptr = reg; 383d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 384d1d3233eSRafal Jaworowski 385d1d3233eSRafal Jaworowski bank = fdt_data_get((void *)reg, 1); 386d1d3233eSRafal Jaworowski di->di_bank = bank; 387d1d3233eSRafal Jaworowski reg += 1; 388d1d3233eSRafal Jaworowski 389d1d3233eSRafal Jaworowski /* Get address/size. */ 390d1d3233eSRafal Jaworowski rv = fdt_data_to_res(reg, addr_cells - 1, size_cells, &start, 391d1d3233eSRafal Jaworowski &count); 392d1d3233eSRafal Jaworowski if (rv != 0) { 393d1d3233eSRafal Jaworowski resource_list_free(&di->di_res); 394d1d3233eSRafal Jaworowski goto out; 395d1d3233eSRafal Jaworowski } 396d1d3233eSRafal Jaworowski reg += addr_cells - 1 + size_cells; 397d1d3233eSRafal Jaworowski 398d1d3233eSRafal Jaworowski /* Calculate address range relative to VA base. */ 399f6703dd2SMarcel Moolenaar start = sc->sc_banks[bank].kva + start; 400d1d3233eSRafal Jaworowski end = start + count - 1; 401d1d3233eSRafal Jaworowski 402d1d3233eSRafal Jaworowski debugf("reg addr bank = %d, start = %lx, end = %lx, " 403d1d3233eSRafal Jaworowski "count = %lx\n", bank, start, end, count); 404d1d3233eSRafal Jaworowski 405d1d3233eSRafal Jaworowski /* Use bank (CS) cell as rid. */ 406d1d3233eSRafal Jaworowski resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start, 407d1d3233eSRafal Jaworowski end, count); 408d1d3233eSRafal Jaworowski } 409d1d3233eSRafal Jaworowski rv = 0; 410d1d3233eSRafal Jaworowski out: 411d1d3233eSRafal Jaworowski free(regptr, M_OFWPROP); 412d1d3233eSRafal Jaworowski return (rv); 41325c22eb4SRafal Jaworowski } 41425c22eb4SRafal Jaworowski 41523fbc06bSMarcel Moolenaar static void 41623fbc06bSMarcel Moolenaar lbc_intr(void *arg) 41723fbc06bSMarcel Moolenaar { 41823fbc06bSMarcel Moolenaar struct lbc_softc *sc = arg; 41923fbc06bSMarcel Moolenaar uint32_t ltesr; 42023fbc06bSMarcel Moolenaar 42123fbc06bSMarcel Moolenaar ltesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR); 42223fbc06bSMarcel Moolenaar sc->sc_ltesr = ltesr; 42323fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ltesr); 42423fbc06bSMarcel Moolenaar wakeup(sc->sc_dev); 42523fbc06bSMarcel Moolenaar } 42623fbc06bSMarcel Moolenaar 42725c22eb4SRafal Jaworowski static int 42808077f58SMarcel Moolenaar lbc_probe(device_t dev) 42908077f58SMarcel Moolenaar { 43008077f58SMarcel Moolenaar 431d1d3233eSRafal Jaworowski if (!(ofw_bus_is_compatible(dev, "fsl,lbc") || 432d1d3233eSRafal Jaworowski ofw_bus_is_compatible(dev, "fsl,elbc"))) 43308077f58SMarcel Moolenaar return (ENXIO); 43408077f58SMarcel Moolenaar 435d1d3233eSRafal Jaworowski device_set_desc(dev, "Freescale Local Bus Controller"); 43608077f58SMarcel Moolenaar return (BUS_PROBE_DEFAULT); 43708077f58SMarcel Moolenaar } 43808077f58SMarcel Moolenaar 43908077f58SMarcel Moolenaar static int 44008077f58SMarcel Moolenaar lbc_attach(device_t dev) 44108077f58SMarcel Moolenaar { 44208077f58SMarcel Moolenaar struct lbc_softc *sc; 443d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 44408077f58SMarcel Moolenaar struct rman *rm; 445d1d3233eSRafal Jaworowski u_long offset, start, size; 446d1d3233eSRafal Jaworowski device_t cdev; 447d1d3233eSRafal Jaworowski phandle_t node, child; 448d1d3233eSRafal Jaworowski pcell_t *ranges, *rangesptr; 449d1d3233eSRafal Jaworowski int tuple_size, tuples; 450d1d3233eSRafal Jaworowski int par_addr_cells; 451d1d3233eSRafal Jaworowski int bank, error, i; 45208077f58SMarcel Moolenaar 45308077f58SMarcel Moolenaar sc = device_get_softc(dev); 45408077f58SMarcel Moolenaar sc->sc_dev = dev; 45508077f58SMarcel Moolenaar 45623fbc06bSMarcel Moolenaar sc->sc_mrid = 0; 45723fbc06bSMarcel Moolenaar sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid, 45808077f58SMarcel Moolenaar RF_ACTIVE); 45923fbc06bSMarcel Moolenaar if (sc->sc_mres == NULL) 46008077f58SMarcel Moolenaar return (ENXIO); 46108077f58SMarcel Moolenaar 46223fbc06bSMarcel Moolenaar sc->sc_bst = rman_get_bustag(sc->sc_mres); 46323fbc06bSMarcel Moolenaar sc->sc_bsh = rman_get_bushandle(sc->sc_mres); 46423fbc06bSMarcel Moolenaar 46523fbc06bSMarcel Moolenaar for (bank = 0; bank < LBC_DEV_MAX; bank++) { 46623fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0); 46723fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0); 46823fbc06bSMarcel Moolenaar } 46923fbc06bSMarcel Moolenaar 47023fbc06bSMarcel Moolenaar /* 47123fbc06bSMarcel Moolenaar * Initialize configuration register: 47223fbc06bSMarcel Moolenaar * - enable Local Bus 47323fbc06bSMarcel Moolenaar * - set data buffer control signal function 47423fbc06bSMarcel Moolenaar * - disable parity byte select 47523fbc06bSMarcel Moolenaar * - set ECC parity type 47623fbc06bSMarcel Moolenaar * - set bus monitor timing and timer prescale 47723fbc06bSMarcel Moolenaar */ 47823fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); 47923fbc06bSMarcel Moolenaar 48023fbc06bSMarcel Moolenaar /* 48123fbc06bSMarcel Moolenaar * Initialize clock ratio register: 48223fbc06bSMarcel Moolenaar * - disable PLL bypass mode 48323fbc06bSMarcel Moolenaar * - configure LCLK delay cycles for the assertion of LALE 48423fbc06bSMarcel Moolenaar * - set system clock divider 48523fbc06bSMarcel Moolenaar */ 48623fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); 48723fbc06bSMarcel Moolenaar 48823fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0); 48923fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0); 49023fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001); 49123fbc06bSMarcel Moolenaar 49223fbc06bSMarcel Moolenaar sc->sc_irid = 0; 49323fbc06bSMarcel Moolenaar sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 49423fbc06bSMarcel Moolenaar RF_ACTIVE | RF_SHAREABLE); 49523fbc06bSMarcel Moolenaar if (sc->sc_ires != NULL) { 49623fbc06bSMarcel Moolenaar error = bus_setup_intr(dev, sc->sc_ires, 49723fbc06bSMarcel Moolenaar INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc, 49823fbc06bSMarcel Moolenaar &sc->sc_icookie); 49923fbc06bSMarcel Moolenaar if (error) { 50023fbc06bSMarcel Moolenaar device_printf(dev, "could not activate interrupt\n"); 50123fbc06bSMarcel Moolenaar bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 50223fbc06bSMarcel Moolenaar sc->sc_ires); 50323fbc06bSMarcel Moolenaar sc->sc_ires = NULL; 50423fbc06bSMarcel Moolenaar } 50523fbc06bSMarcel Moolenaar } 50623fbc06bSMarcel Moolenaar 50723fbc06bSMarcel Moolenaar sc->sc_ltesr = ~0; 50823fbc06bSMarcel Moolenaar 509d1d3233eSRafal Jaworowski rangesptr = NULL; 51008077f58SMarcel Moolenaar 51108077f58SMarcel Moolenaar rm = &sc->sc_rman; 51208077f58SMarcel Moolenaar rm->rm_type = RMAN_ARRAY; 513d1d3233eSRafal Jaworowski rm->rm_descr = "Local Bus Space"; 51408077f58SMarcel Moolenaar error = rman_init(rm); 51508077f58SMarcel Moolenaar if (error) 51608077f58SMarcel Moolenaar goto fail; 51708077f58SMarcel Moolenaar 51808077f58SMarcel Moolenaar error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 51908077f58SMarcel Moolenaar if (error) { 52008077f58SMarcel Moolenaar rman_fini(rm); 52108077f58SMarcel Moolenaar goto fail; 52208077f58SMarcel Moolenaar } 52308077f58SMarcel Moolenaar 52425c22eb4SRafal Jaworowski /* 525d1d3233eSRafal Jaworowski * Process 'ranges' property. 52625c22eb4SRafal Jaworowski */ 527d1d3233eSRafal Jaworowski node = ofw_bus_get_node(dev); 528d1d3233eSRafal Jaworowski if ((fdt_addrsize_cells(node, &sc->sc_addr_cells, 529d1d3233eSRafal Jaworowski &sc->sc_size_cells)) != 0) { 53025c22eb4SRafal Jaworowski error = ENXIO; 53125c22eb4SRafal Jaworowski goto fail; 53225c22eb4SRafal Jaworowski } 53308077f58SMarcel Moolenaar 534d1d3233eSRafal Jaworowski par_addr_cells = fdt_parent_addr_cells(node); 535d1d3233eSRafal Jaworowski if (par_addr_cells > 2) { 536d1d3233eSRafal Jaworowski device_printf(dev, "unsupported parent #addr-cells\n"); 537d1d3233eSRafal Jaworowski error = ERANGE; 538d1d3233eSRafal Jaworowski goto fail; 539d1d3233eSRafal Jaworowski } 540d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells + 541d1d3233eSRafal Jaworowski sc->sc_size_cells); 542d1d3233eSRafal Jaworowski 543d1d3233eSRafal Jaworowski tuples = OF_getprop_alloc(node, "ranges", tuple_size, 544d1d3233eSRafal Jaworowski (void **)&ranges); 545d1d3233eSRafal Jaworowski if (tuples < 0) { 546d1d3233eSRafal Jaworowski device_printf(dev, "could not retrieve 'ranges' property\n"); 547d1d3233eSRafal Jaworowski error = ENXIO; 548d1d3233eSRafal Jaworowski goto fail; 549d1d3233eSRafal Jaworowski } 550d1d3233eSRafal Jaworowski rangesptr = ranges; 551d1d3233eSRafal Jaworowski 552d1d3233eSRafal Jaworowski debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, " 553d1d3233eSRafal Jaworowski "tuple_size = %d, tuples = %d\n", par_addr_cells, 554d1d3233eSRafal Jaworowski sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples); 555d1d3233eSRafal Jaworowski 556d1d3233eSRafal Jaworowski start = 0; 557d1d3233eSRafal Jaworowski size = 0; 558d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 559d1d3233eSRafal Jaworowski 560d1d3233eSRafal Jaworowski /* The first cell is the bank (chip select) number. */ 561d1d3233eSRafal Jaworowski bank = fdt_data_get((void *)ranges, 1); 562d1d3233eSRafal Jaworowski if (bank < 0 || bank > LBC_DEV_MAX) { 563d1d3233eSRafal Jaworowski device_printf(dev, "bank out of range: %d\n", bank); 564d1d3233eSRafal Jaworowski error = ERANGE; 565d1d3233eSRafal Jaworowski goto fail; 566d1d3233eSRafal Jaworowski } 567d1d3233eSRafal Jaworowski ranges += 1; 568d1d3233eSRafal Jaworowski 569d1d3233eSRafal Jaworowski /* 570d1d3233eSRafal Jaworowski * Remaining cells of the child address define offset into 571d1d3233eSRafal Jaworowski * this CS. 572d1d3233eSRafal Jaworowski */ 573d1d3233eSRafal Jaworowski offset = fdt_data_get((void *)ranges, sc->sc_addr_cells - 1); 574d1d3233eSRafal Jaworowski ranges += sc->sc_addr_cells - 1; 575d1d3233eSRafal Jaworowski 576d1d3233eSRafal Jaworowski /* Parent bus start address of this bank. */ 577d1d3233eSRafal Jaworowski start = fdt_data_get((void *)ranges, par_addr_cells); 578d1d3233eSRafal Jaworowski ranges += par_addr_cells; 579d1d3233eSRafal Jaworowski 580d1d3233eSRafal Jaworowski size = fdt_data_get((void *)ranges, sc->sc_size_cells); 581d1d3233eSRafal Jaworowski ranges += sc->sc_size_cells; 582d1d3233eSRafal Jaworowski debugf("bank = %d, start = %lx, size = %lx\n", bank, 583d1d3233eSRafal Jaworowski start, size); 584d1d3233eSRafal Jaworowski 585f6703dd2SMarcel Moolenaar sc->sc_banks[bank].addr = start + offset; 586d1d3233eSRafal Jaworowski sc->sc_banks[bank].size = size; 587d1d3233eSRafal Jaworowski 588d1d3233eSRafal Jaworowski /* 589d1d3233eSRafal Jaworowski * Attributes for the bank. 590d1d3233eSRafal Jaworowski * 591d1d3233eSRafal Jaworowski * XXX Note there are no DT bindings defined for them at the 592d1d3233eSRafal Jaworowski * moment, so we need to provide some defaults. 593d1d3233eSRafal Jaworowski */ 594d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = 16; 595d1d3233eSRafal Jaworowski sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM; 596d1d3233eSRafal Jaworowski sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED; 597d1d3233eSRafal Jaworowski sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED; 598d1d3233eSRafal Jaworowski sc->sc_banks[bank].wp = 0; 599d1d3233eSRafal Jaworowski } 600d1d3233eSRafal Jaworowski 601d1d3233eSRafal Jaworowski /* 602d1d3233eSRafal Jaworowski * Initialize mem-mappings for the LBC banks (i.e. chip selects). 603d1d3233eSRafal Jaworowski */ 604d1d3233eSRafal Jaworowski error = lbc_banks_map(sc); 605d1d3233eSRafal Jaworowski if (error) 606d1d3233eSRafal Jaworowski goto fail; 607d1d3233eSRafal Jaworowski 608d1d3233eSRafal Jaworowski /* 609d1d3233eSRafal Jaworowski * Walk the localbus and add direct subordinates as our children. 610d1d3233eSRafal Jaworowski */ 611d1d3233eSRafal Jaworowski for (child = OF_child(node); child != 0; child = OF_peer(child)) { 612d1d3233eSRafal Jaworowski 613d1d3233eSRafal Jaworowski di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO); 614d1d3233eSRafal Jaworowski 615d1d3233eSRafal Jaworowski if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) { 616d1d3233eSRafal Jaworowski free(di, M_LBC); 617d1d3233eSRafal Jaworowski device_printf(dev, "could not set up devinfo\n"); 618d1d3233eSRafal Jaworowski continue; 619d1d3233eSRafal Jaworowski } 620d1d3233eSRafal Jaworowski 621d1d3233eSRafal Jaworowski resource_list_init(&di->di_res); 622d1d3233eSRafal Jaworowski 623d1d3233eSRafal Jaworowski if (fdt_lbc_reg_decode(child, sc, di)) { 624d1d3233eSRafal Jaworowski device_printf(dev, "could not process 'reg' " 625d1d3233eSRafal Jaworowski "property\n"); 626d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 627d1d3233eSRafal Jaworowski free(di, M_LBC); 628d1d3233eSRafal Jaworowski continue; 629d1d3233eSRafal Jaworowski } 630d1d3233eSRafal Jaworowski 631d1d3233eSRafal Jaworowski fdt_lbc_fixup(child, sc, di); 632d1d3233eSRafal Jaworowski 633d1d3233eSRafal Jaworowski /* Add newbus device for this FDT node */ 634d1d3233eSRafal Jaworowski cdev = device_add_child(dev, NULL, -1); 635d1d3233eSRafal Jaworowski if (cdev == NULL) { 636d1d3233eSRafal Jaworowski device_printf(dev, "could not add child: %s\n", 637d1d3233eSRafal Jaworowski di->di_ofw.obd_name); 638d1d3233eSRafal Jaworowski resource_list_free(&di->di_res); 639d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 640d1d3233eSRafal Jaworowski free(di, M_LBC); 641d1d3233eSRafal Jaworowski continue; 642d1d3233eSRafal Jaworowski } 643d1d3233eSRafal Jaworowski debugf("added child name='%s', node=%p\n", di->di_ofw.obd_name, 644d1d3233eSRafal Jaworowski (void *)child); 645d1d3233eSRafal Jaworowski device_set_ivars(cdev, di); 646d1d3233eSRafal Jaworowski } 647d1d3233eSRafal Jaworowski 648d1d3233eSRafal Jaworowski /* 649d1d3233eSRafal Jaworowski * Enable the LBC. 650d1d3233eSRafal Jaworowski */ 651d1d3233eSRafal Jaworowski lbc_banks_enable(sc); 652d1d3233eSRafal Jaworowski 653d1d3233eSRafal Jaworowski free(rangesptr, M_OFWPROP); 65408077f58SMarcel Moolenaar return (bus_generic_attach(dev)); 65508077f58SMarcel Moolenaar 65608077f58SMarcel Moolenaar fail: 657d1d3233eSRafal Jaworowski free(rangesptr, M_OFWPROP); 65823fbc06bSMarcel Moolenaar bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); 65908077f58SMarcel Moolenaar return (error); 66008077f58SMarcel Moolenaar } 66108077f58SMarcel Moolenaar 66208077f58SMarcel Moolenaar static int 66308077f58SMarcel Moolenaar lbc_shutdown(device_t dev) 66408077f58SMarcel Moolenaar { 66508077f58SMarcel Moolenaar 66608077f58SMarcel Moolenaar /* TODO */ 66708077f58SMarcel Moolenaar return(0); 66808077f58SMarcel Moolenaar } 66908077f58SMarcel Moolenaar 67008077f58SMarcel Moolenaar static struct resource * 671d1d3233eSRafal Jaworowski lbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 6722dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 67308077f58SMarcel Moolenaar { 67408077f58SMarcel Moolenaar struct lbc_softc *sc; 675d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 676d1d3233eSRafal Jaworowski struct resource_list_entry *rle; 677d1d3233eSRafal Jaworowski struct resource *res; 67808077f58SMarcel Moolenaar struct rman *rm; 679d1d3233eSRafal Jaworowski int needactivate; 68008077f58SMarcel Moolenaar 68108077f58SMarcel Moolenaar /* We only support default allocations. */ 682f7dc5935SJustin Hibbits if (!RMAN_IS_DEFAULT_RANGE(start, end)) 68308077f58SMarcel Moolenaar return (NULL); 68408077f58SMarcel Moolenaar 685d1d3233eSRafal Jaworowski sc = device_get_softc(bus); 68608077f58SMarcel Moolenaar if (type == SYS_RES_IRQ) 687d1d3233eSRafal Jaworowski return (bus_alloc_resource(bus, type, rid, start, end, count, 68808077f58SMarcel Moolenaar flags)); 68908077f58SMarcel Moolenaar 690d1d3233eSRafal Jaworowski /* 691d1d3233eSRafal Jaworowski * Request for the default allocation with a given rid: use resource 692d1d3233eSRafal Jaworowski * list stored in the local device info. 693d1d3233eSRafal Jaworowski */ 694d1d3233eSRafal Jaworowski if ((di = device_get_ivars(child)) == NULL) 695d1d3233eSRafal Jaworowski return (NULL); 696d1d3233eSRafal Jaworowski 697d1d3233eSRafal Jaworowski if (type == SYS_RES_IOPORT) 698d1d3233eSRafal Jaworowski type = SYS_RES_MEMORY; 699d1d3233eSRafal Jaworowski 700d1d3233eSRafal Jaworowski rid = &di->di_bank; 701d1d3233eSRafal Jaworowski 702d1d3233eSRafal Jaworowski rle = resource_list_find(&di->di_res, type, *rid); 703d1d3233eSRafal Jaworowski if (rle == NULL) { 704d1d3233eSRafal Jaworowski device_printf(bus, "no default resources for " 705d1d3233eSRafal Jaworowski "rid = %d, type = %d\n", *rid, type); 70625c22eb4SRafal Jaworowski return (NULL); 70725c22eb4SRafal Jaworowski } 708d1d3233eSRafal Jaworowski start = rle->start; 709d1d3233eSRafal Jaworowski count = rle->count; 710d1d3233eSRafal Jaworowski end = start + count - 1; 71125c22eb4SRafal Jaworowski 712d1d3233eSRafal Jaworowski sc = device_get_softc(bus); 713d1d3233eSRafal Jaworowski 714d1d3233eSRafal Jaworowski needactivate = flags & RF_ACTIVE; 715d1d3233eSRafal Jaworowski flags &= ~RF_ACTIVE; 71608077f58SMarcel Moolenaar 71708077f58SMarcel Moolenaar rm = &sc->sc_rman; 718d1d3233eSRafal Jaworowski 719d1d3233eSRafal Jaworowski res = rman_reserve_resource(rm, start, end, count, flags, child); 720d1d3233eSRafal Jaworowski if (res == NULL) { 721da1b038aSJustin Hibbits device_printf(bus, "failed to reserve resource %#jx - %#jx " 722da1b038aSJustin Hibbits "(%#jx)\n", start, end, count); 723d1d3233eSRafal Jaworowski return (NULL); 72408077f58SMarcel Moolenaar } 725d1d3233eSRafal Jaworowski 726d1d3233eSRafal Jaworowski rman_set_rid(res, *rid); 727d1d3233eSRafal Jaworowski rman_set_bustag(res, &bs_be_tag); 728d1d3233eSRafal Jaworowski rman_set_bushandle(res, rman_get_start(res)); 729d1d3233eSRafal Jaworowski 730d1d3233eSRafal Jaworowski if (needactivate) 731d1d3233eSRafal Jaworowski if (bus_activate_resource(child, type, *rid, res)) { 732d1d3233eSRafal Jaworowski device_printf(child, "resource activation failed\n"); 733d1d3233eSRafal Jaworowski rman_release_resource(res); 734d1d3233eSRafal Jaworowski return (NULL); 735d1d3233eSRafal Jaworowski } 736d1d3233eSRafal Jaworowski 737d1d3233eSRafal Jaworowski return (res); 73808077f58SMarcel Moolenaar } 73908077f58SMarcel Moolenaar 74008077f58SMarcel Moolenaar static int 74108077f58SMarcel Moolenaar lbc_print_child(device_t dev, device_t child) 74208077f58SMarcel Moolenaar { 743d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 744d1d3233eSRafal Jaworowski struct resource_list *rl; 745d1d3233eSRafal Jaworowski int rv; 74608077f58SMarcel Moolenaar 747d1d3233eSRafal Jaworowski di = device_get_ivars(child); 748d1d3233eSRafal Jaworowski rl = &di->di_res; 74908077f58SMarcel Moolenaar 750d1d3233eSRafal Jaworowski rv = 0; 751d1d3233eSRafal Jaworowski rv += bus_print_child_header(dev, child); 752da1b038aSJustin Hibbits rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 753da1b038aSJustin Hibbits rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 754d1d3233eSRafal Jaworowski rv += bus_print_child_footer(dev, child); 75508077f58SMarcel Moolenaar 756d1d3233eSRafal Jaworowski return (rv); 75708077f58SMarcel Moolenaar } 75808077f58SMarcel Moolenaar 75908077f58SMarcel Moolenaar static int 76008077f58SMarcel Moolenaar lbc_release_resource(device_t dev, device_t child, int type, int rid, 76108077f58SMarcel Moolenaar struct resource *res) 76208077f58SMarcel Moolenaar { 763d1d3233eSRafal Jaworowski int err; 764d1d3233eSRafal Jaworowski 765d1d3233eSRafal Jaworowski if (rman_get_flags(res) & RF_ACTIVE) { 766d1d3233eSRafal Jaworowski err = bus_deactivate_resource(child, type, rid, res); 767d1d3233eSRafal Jaworowski if (err) 768d1d3233eSRafal Jaworowski return (err); 769d1d3233eSRafal Jaworowski } 77008077f58SMarcel Moolenaar 77108077f58SMarcel Moolenaar return (rman_release_resource(res)); 77208077f58SMarcel Moolenaar } 77308077f58SMarcel Moolenaar 7748bc8506eSJustin Hibbits static int 7758bc8506eSJustin Hibbits lbc_activate_resource(device_t bus __unused, device_t child __unused, 7768bc8506eSJustin Hibbits int type __unused, int rid __unused, struct resource *r) 7778bc8506eSJustin Hibbits { 7788bc8506eSJustin Hibbits 7798bc8506eSJustin Hibbits /* Child resources were already mapped, just activate. */ 7808bc8506eSJustin Hibbits return (rman_activate_resource(r)); 7818bc8506eSJustin Hibbits } 7828bc8506eSJustin Hibbits 7838bc8506eSJustin Hibbits static int 7848bc8506eSJustin Hibbits lbc_deactivate_resource(device_t bus __unused, device_t child __unused, 7858bc8506eSJustin Hibbits int type __unused, int rid __unused, struct resource *r) 7868bc8506eSJustin Hibbits { 7878bc8506eSJustin Hibbits 7888bc8506eSJustin Hibbits return (rman_deactivate_resource(r)); 7898bc8506eSJustin Hibbits } 7908bc8506eSJustin Hibbits 791d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo * 792d1d3233eSRafal Jaworowski lbc_get_devinfo(device_t bus, device_t child) 79308077f58SMarcel Moolenaar { 794d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 79508077f58SMarcel Moolenaar 796d1d3233eSRafal Jaworowski di = device_get_ivars(child); 797d1d3233eSRafal Jaworowski return (&di->di_ofw); 79808077f58SMarcel Moolenaar } 799f6703dd2SMarcel Moolenaar 800f6703dd2SMarcel Moolenaar void 801f6703dd2SMarcel Moolenaar lbc_write_reg(device_t child, u_int off, uint32_t val) 802f6703dd2SMarcel Moolenaar { 80323fbc06bSMarcel Moolenaar device_t dev; 804f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 805f6703dd2SMarcel Moolenaar 80623fbc06bSMarcel Moolenaar dev = device_get_parent(child); 80723fbc06bSMarcel Moolenaar 80823fbc06bSMarcel Moolenaar if (off >= 0x1000) { 80923fbc06bSMarcel Moolenaar device_printf(dev, "%s(%s): invalid offset %#x\n", 81023fbc06bSMarcel Moolenaar __func__, device_get_nameunit(child), off); 81123fbc06bSMarcel Moolenaar return; 81223fbc06bSMarcel Moolenaar } 81323fbc06bSMarcel Moolenaar 81423fbc06bSMarcel Moolenaar sc = device_get_softc(dev); 81523fbc06bSMarcel Moolenaar 81623fbc06bSMarcel Moolenaar if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) { 81723fbc06bSMarcel Moolenaar sc->sc_ltesr ^= (val & sc->sc_ltesr); 81823fbc06bSMarcel Moolenaar return; 81923fbc06bSMarcel Moolenaar } 82023fbc06bSMarcel Moolenaar 82123fbc06bSMarcel Moolenaar if (off == LBC85XX_LTEATR && (val & 1) == 0) 82223fbc06bSMarcel Moolenaar sc->sc_ltesr = ~0u; 823f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 824f6703dd2SMarcel Moolenaar } 825f6703dd2SMarcel Moolenaar 826f6703dd2SMarcel Moolenaar uint32_t 827f6703dd2SMarcel Moolenaar lbc_read_reg(device_t child, u_int off) 828f6703dd2SMarcel Moolenaar { 82923fbc06bSMarcel Moolenaar device_t dev; 830f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 83123fbc06bSMarcel Moolenaar uint32_t val; 832f6703dd2SMarcel Moolenaar 83323fbc06bSMarcel Moolenaar dev = device_get_parent(child); 83423fbc06bSMarcel Moolenaar 83523fbc06bSMarcel Moolenaar if (off >= 0x1000) { 83623fbc06bSMarcel Moolenaar device_printf(dev, "%s(%s): invalid offset %#x\n", 83723fbc06bSMarcel Moolenaar __func__, device_get_nameunit(child), off); 83823fbc06bSMarcel Moolenaar return (~0U); 83923fbc06bSMarcel Moolenaar } 84023fbc06bSMarcel Moolenaar 84123fbc06bSMarcel Moolenaar sc = device_get_softc(dev); 84223fbc06bSMarcel Moolenaar 84323fbc06bSMarcel Moolenaar if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U) 84423fbc06bSMarcel Moolenaar val = sc->sc_ltesr; 84523fbc06bSMarcel Moolenaar else 84623fbc06bSMarcel Moolenaar val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); 84723fbc06bSMarcel Moolenaar return (val); 848f6703dd2SMarcel Moolenaar } 849