108077f58SMarcel Moolenaar /*- 271e3c308SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 371e3c308SPedro F. Giffuni * 408077f58SMarcel Moolenaar * Copyright (c) 2006-2008, Juniper Networks, Inc. 525c22eb4SRafal Jaworowski * Copyright (c) 2008 Semihalf, Rafal Czubak 6d1d3233eSRafal Jaworowski * Copyright (c) 2009 The FreeBSD Foundation 708077f58SMarcel Moolenaar * All rights reserved. 808077f58SMarcel Moolenaar * 9d1d3233eSRafal Jaworowski * Portions of this software were developed by Semihalf 10d1d3233eSRafal Jaworowski * under sponsorship from the FreeBSD Foundation. 11d1d3233eSRafal Jaworowski * 1208077f58SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 1308077f58SMarcel Moolenaar * modification, are permitted provided that the following conditions 1408077f58SMarcel Moolenaar * are met: 1508077f58SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1608077f58SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1708077f58SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1808077f58SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1908077f58SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 2008077f58SMarcel Moolenaar * 3. The name of the author may not be used to endorse or promote products 2108077f58SMarcel Moolenaar * derived from this software without specific prior written permission. 2208077f58SMarcel Moolenaar * 2308077f58SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2408077f58SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2508077f58SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2608077f58SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2708077f58SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2808077f58SMarcel Moolenaar * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2908077f58SMarcel Moolenaar * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 3008077f58SMarcel Moolenaar * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 3108077f58SMarcel Moolenaar * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3208077f58SMarcel Moolenaar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3308077f58SMarcel Moolenaar * SUCH DAMAGE. 3408077f58SMarcel Moolenaar */ 3508077f58SMarcel Moolenaar 368bc8506eSJustin Hibbits #include "opt_platform.h" 378bc8506eSJustin Hibbits 3808077f58SMarcel Moolenaar #include <sys/param.h> 3908077f58SMarcel Moolenaar #include <sys/systm.h> 4008077f58SMarcel Moolenaar #include <sys/ktr.h> 4108077f58SMarcel Moolenaar #include <sys/kernel.h> 4208077f58SMarcel Moolenaar #include <sys/malloc.h> 4308077f58SMarcel Moolenaar #include <sys/module.h> 4408077f58SMarcel Moolenaar #include <sys/bus.h> 4508077f58SMarcel Moolenaar #include <sys/rman.h> 4608077f58SMarcel Moolenaar #include <machine/bus.h> 4708077f58SMarcel Moolenaar 4808077f58SMarcel Moolenaar #include <vm/vm.h> 4908077f58SMarcel Moolenaar #include <vm/pmap.h> 5008077f58SMarcel Moolenaar 51d1d3233eSRafal Jaworowski #include <dev/fdt/fdt_common.h> 52d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus.h> 53d1d3233eSRafal Jaworowski #include <dev/ofw/ofw_bus_subr.h> 54d1d3233eSRafal Jaworowski 5525c22eb4SRafal Jaworowski #include <powerpc/mpc85xx/mpc85xx.h> 5608077f58SMarcel Moolenaar 57d1d3233eSRafal Jaworowski #include "ofw_bus_if.h" 58d1d3233eSRafal Jaworowski #include "lbc.h" 5908077f58SMarcel Moolenaar 60d1d3233eSRafal Jaworowski #ifdef DEBUG 61d1d3233eSRafal Jaworowski #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 62d1d3233eSRafal Jaworowski printf(fmt,##args); } while (0) 63d1d3233eSRafal Jaworowski #else 64d1d3233eSRafal Jaworowski #define debugf(fmt, args...) 65d1d3233eSRafal Jaworowski #endif 6608077f58SMarcel Moolenaar 67d1d3233eSRafal Jaworowski static MALLOC_DEFINE(M_LBC, "localbus", "localbus devices information"); 68d1d3233eSRafal Jaworowski 69d1d3233eSRafal Jaworowski static int lbc_probe(device_t); 70d1d3233eSRafal Jaworowski static int lbc_attach(device_t); 71d1d3233eSRafal Jaworowski static int lbc_shutdown(device_t); 72*d77f2092SJohn Baldwin static int lbc_map_resource(device_t, device_t, struct resource *, 735a7e717fSJohn Baldwin struct resource_map_request *, struct resource_map *); 74*d77f2092SJohn Baldwin static int lbc_unmap_resource(device_t, device_t, struct resource *, 755a7e717fSJohn Baldwin struct resource_map *map); 765a7e717fSJohn Baldwin static int lbc_activate_resource(device_t bus, device_t child, 775a7e717fSJohn Baldwin int type, int rid, struct resource *r); 785a7e717fSJohn Baldwin static int lbc_deactivate_resource(device_t bus, 795a7e717fSJohn Baldwin device_t child, int type __unused, int rid, 808bc8506eSJustin Hibbits struct resource *r); 815a7e717fSJohn Baldwin static struct rman *lbc_get_rman(device_t, int, u_int); 82d1d3233eSRafal Jaworowski static struct resource *lbc_alloc_resource(device_t, device_t, int, int *, 832dd1bdf1SJustin Hibbits rman_res_t, rman_res_t, rman_res_t, u_int); 84fef01f04SJohn Baldwin static int lbc_adjust_resource(device_t, device_t, struct resource *, 855a7e717fSJohn Baldwin rman_res_t, rman_res_t); 86d1d3233eSRafal Jaworowski static int lbc_print_child(device_t, device_t); 87d1d3233eSRafal Jaworowski static int lbc_release_resource(device_t, device_t, int, int, 88d1d3233eSRafal Jaworowski struct resource *); 89d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo *lbc_get_devinfo(device_t, device_t); 90d1d3233eSRafal Jaworowski 91d1d3233eSRafal Jaworowski /* 92d1d3233eSRafal Jaworowski * Bus interface definition 93d1d3233eSRafal Jaworowski */ 94d1d3233eSRafal Jaworowski static device_method_t lbc_methods[] = { 95d1d3233eSRafal Jaworowski /* Device interface */ 96d1d3233eSRafal Jaworowski DEVMETHOD(device_probe, lbc_probe), 97d1d3233eSRafal Jaworowski DEVMETHOD(device_attach, lbc_attach), 98d1d3233eSRafal Jaworowski DEVMETHOD(device_shutdown, lbc_shutdown), 99d1d3233eSRafal Jaworowski 100d1d3233eSRafal Jaworowski /* Bus interface */ 101d1d3233eSRafal Jaworowski DEVMETHOD(bus_print_child, lbc_print_child), 102d1d3233eSRafal Jaworowski DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 103d1d3233eSRafal Jaworowski DEVMETHOD(bus_teardown_intr, NULL), 104d1d3233eSRafal Jaworowski 1055a7e717fSJohn Baldwin DEVMETHOD(bus_get_rman, lbc_get_rman), 106d1d3233eSRafal Jaworowski DEVMETHOD(bus_alloc_resource, lbc_alloc_resource), 1075a7e717fSJohn Baldwin DEVMETHOD(bus_adjust_resource, lbc_adjust_resource), 108d1d3233eSRafal Jaworowski DEVMETHOD(bus_release_resource, lbc_release_resource), 1098bc8506eSJustin Hibbits DEVMETHOD(bus_activate_resource, lbc_activate_resource), 1108bc8506eSJustin Hibbits DEVMETHOD(bus_deactivate_resource, lbc_deactivate_resource), 1115a7e717fSJohn Baldwin DEVMETHOD(bus_map_resource, lbc_map_resource), 1125a7e717fSJohn Baldwin DEVMETHOD(bus_unmap_resource, lbc_unmap_resource), 113d1d3233eSRafal Jaworowski 114d1d3233eSRafal Jaworowski /* OFW bus interface */ 115d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_devinfo, lbc_get_devinfo), 116d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 117d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 118d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 119d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 120d1d3233eSRafal Jaworowski DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 121d1d3233eSRafal Jaworowski { 0, 0 } 122d1d3233eSRafal Jaworowski }; 123d1d3233eSRafal Jaworowski 124d1d3233eSRafal Jaworowski static driver_t lbc_driver = { 125d1d3233eSRafal Jaworowski "lbc", 126d1d3233eSRafal Jaworowski lbc_methods, 127d1d3233eSRafal Jaworowski sizeof(struct lbc_softc) 128d1d3233eSRafal Jaworowski }; 129d1d3233eSRafal Jaworowski 1305d7d6129SJohn Baldwin EARLY_DRIVER_MODULE(lbc, ofwbus, lbc_driver, 0, 0, BUS_PASS_BUS); 131d1d3233eSRafal Jaworowski 13225c22eb4SRafal Jaworowski /* 13325c22eb4SRafal Jaworowski * Calculate address mask used by OR(n) registers. Use memory region size to 13425c22eb4SRafal Jaworowski * determine mask value. The size must be a power of two and within the range 13525c22eb4SRafal Jaworowski * of 32KB - 4GB. Otherwise error code is returned. Value representing 13625c22eb4SRafal Jaworowski * 4GB size can be passed as 0xffffffff. 13725c22eb4SRafal Jaworowski */ 13825c22eb4SRafal Jaworowski static uint32_t 13925c22eb4SRafal Jaworowski lbc_address_mask(uint32_t size) 14025c22eb4SRafal Jaworowski { 14125c22eb4SRafal Jaworowski int n = 15; 14225c22eb4SRafal Jaworowski 143295be330SJustin Hibbits if (size == ~0) 14425c22eb4SRafal Jaworowski return (0); 14525c22eb4SRafal Jaworowski 14625c22eb4SRafal Jaworowski while (n < 32) { 147295be330SJustin Hibbits if (size == (1U << n)) 14825c22eb4SRafal Jaworowski break; 14925c22eb4SRafal Jaworowski n++; 15025c22eb4SRafal Jaworowski } 15125c22eb4SRafal Jaworowski 15225c22eb4SRafal Jaworowski if (n == 32) 15325c22eb4SRafal Jaworowski return (EINVAL); 15425c22eb4SRafal Jaworowski 15525c22eb4SRafal Jaworowski return (0xffff8000 << (n - 15)); 15625c22eb4SRafal Jaworowski } 15725c22eb4SRafal Jaworowski 158d1d3233eSRafal Jaworowski static void 159d1d3233eSRafal Jaworowski lbc_banks_unmap(struct lbc_softc *sc) 16008077f58SMarcel Moolenaar { 161f6703dd2SMarcel Moolenaar int r; 16208077f58SMarcel Moolenaar 163f6703dd2SMarcel Moolenaar r = 0; 164f6703dd2SMarcel Moolenaar while (r < LBC_DEV_MAX) { 165f6703dd2SMarcel Moolenaar if (sc->sc_range[r].size == 0) 166f6703dd2SMarcel Moolenaar return; 16725c22eb4SRafal Jaworowski 1687ae99f80SJohn Baldwin pmap_unmapdev((void *)sc->sc_range[r].kva, 1697ae99f80SJohn Baldwin sc->sc_range[r].size); 170f6703dd2SMarcel Moolenaar law_disable(OCP85XX_TGTIF_LBC, sc->sc_range[r].addr, 171f6703dd2SMarcel Moolenaar sc->sc_range[r].size); 172f6703dd2SMarcel Moolenaar r++; 17308077f58SMarcel Moolenaar } 17408077f58SMarcel Moolenaar } 17508077f58SMarcel Moolenaar 17608077f58SMarcel Moolenaar static int 177d1d3233eSRafal Jaworowski lbc_banks_map(struct lbc_softc *sc) 17825c22eb4SRafal Jaworowski { 179f6703dd2SMarcel Moolenaar vm_paddr_t end, start; 180f6703dd2SMarcel Moolenaar vm_size_t size; 181f6703dd2SMarcel Moolenaar u_int i, r, ranges, s; 182f6703dd2SMarcel Moolenaar int error; 18325c22eb4SRafal Jaworowski 184f6703dd2SMarcel Moolenaar bzero(sc->sc_range, sizeof(sc->sc_range)); 18525c22eb4SRafal Jaworowski 18625c22eb4SRafal Jaworowski /* 187f6703dd2SMarcel Moolenaar * Determine number of discontiguous address ranges to program. 18825c22eb4SRafal Jaworowski */ 189f6703dd2SMarcel Moolenaar ranges = 0; 190f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 191f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 192f6703dd2SMarcel Moolenaar if (size == 0) 193f6703dd2SMarcel Moolenaar continue; 194f6703dd2SMarcel Moolenaar 195f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 196f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 197f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 198f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 199f6703dd2SMarcel Moolenaar if (start > 0 && end == start - 1) { 200f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 201f6703dd2SMarcel Moolenaar break; 202f6703dd2SMarcel Moolenaar } 203f6703dd2SMarcel Moolenaar /* Avoid wrap-around bugs. */ 204f6703dd2SMarcel Moolenaar end = start - 1 + size; 205f6703dd2SMarcel Moolenaar if (sc->sc_range[r].addr > 0 && 206f6703dd2SMarcel Moolenaar end == sc->sc_range[r].addr - 1) { 207f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 208f6703dd2SMarcel Moolenaar sc->sc_range[r].size += size; 209f6703dd2SMarcel Moolenaar break; 210f6703dd2SMarcel Moolenaar } 211f6703dd2SMarcel Moolenaar } 212f6703dd2SMarcel Moolenaar if (r == ranges) { 213f6703dd2SMarcel Moolenaar /* New range; add using insertion sort */ 214f6703dd2SMarcel Moolenaar r = 0; 215f6703dd2SMarcel Moolenaar while (r < ranges && sc->sc_range[r].addr < start) 216f6703dd2SMarcel Moolenaar r++; 217f6703dd2SMarcel Moolenaar for (s = ranges; s > r; s--) 218f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s-1]; 219f6703dd2SMarcel Moolenaar sc->sc_range[r].addr = start; 220f6703dd2SMarcel Moolenaar sc->sc_range[r].size = size; 221f6703dd2SMarcel Moolenaar ranges++; 222f6703dd2SMarcel Moolenaar } 223f6703dd2SMarcel Moolenaar } 224f6703dd2SMarcel Moolenaar 225f6703dd2SMarcel Moolenaar /* 226f6703dd2SMarcel Moolenaar * Ranges are sorted so quickly go over the list to merge ranges 227f6703dd2SMarcel Moolenaar * that grew toward each other while building the ranges. 228f6703dd2SMarcel Moolenaar */ 229f6703dd2SMarcel Moolenaar r = 0; 230f6703dd2SMarcel Moolenaar while (r < ranges - 1) { 231f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr + sc->sc_range[r].size; 232f6703dd2SMarcel Moolenaar if (end != sc->sc_range[r+1].addr) { 233f6703dd2SMarcel Moolenaar r++; 234f6703dd2SMarcel Moolenaar continue; 235f6703dd2SMarcel Moolenaar } 236f6703dd2SMarcel Moolenaar sc->sc_range[r].size += sc->sc_range[r+1].size; 237f6703dd2SMarcel Moolenaar for (s = r + 1; s < ranges - 1; s++) 238f6703dd2SMarcel Moolenaar sc->sc_range[s] = sc->sc_range[s+1]; 239f6703dd2SMarcel Moolenaar bzero(&sc->sc_range[s], sizeof(sc->sc_range[s])); 240f6703dd2SMarcel Moolenaar ranges--; 241f6703dd2SMarcel Moolenaar } 242f6703dd2SMarcel Moolenaar 243f6703dd2SMarcel Moolenaar /* 244f6703dd2SMarcel Moolenaar * Configure LAW for the LBC ranges and map the physical memory 245f6703dd2SMarcel Moolenaar * range into KVA. 246f6703dd2SMarcel Moolenaar */ 247f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 248f6703dd2SMarcel Moolenaar start = sc->sc_range[r].addr; 249f6703dd2SMarcel Moolenaar size = sc->sc_range[r].size; 25025c22eb4SRafal Jaworowski error = law_enable(OCP85XX_TGTIF_LBC, start, size); 25125c22eb4SRafal Jaworowski if (error) 25225c22eb4SRafal Jaworowski return (error); 253f6703dd2SMarcel Moolenaar sc->sc_range[r].kva = (vm_offset_t)pmap_mapdev(start, size); 254f6703dd2SMarcel Moolenaar } 25525c22eb4SRafal Jaworowski 256f6703dd2SMarcel Moolenaar /* XXX: need something better here? */ 257f6703dd2SMarcel Moolenaar if (ranges == 0) 258f6703dd2SMarcel Moolenaar return (EINVAL); 259f6703dd2SMarcel Moolenaar 260f6703dd2SMarcel Moolenaar /* Assign KVA to banks based on the enclosing range. */ 261f6703dd2SMarcel Moolenaar for (i = 0; i < LBC_DEV_MAX; i++) { 262f6703dd2SMarcel Moolenaar size = sc->sc_banks[i].size; 263f6703dd2SMarcel Moolenaar if (size == 0) 264f6703dd2SMarcel Moolenaar continue; 265f6703dd2SMarcel Moolenaar 266f6703dd2SMarcel Moolenaar start = sc->sc_banks[i].addr; 267f6703dd2SMarcel Moolenaar for (r = 0; r < ranges; r++) { 268f6703dd2SMarcel Moolenaar end = sc->sc_range[r].addr - 1 + sc->sc_range[r].size; 269f6703dd2SMarcel Moolenaar if (start >= sc->sc_range[r].addr && 270f6703dd2SMarcel Moolenaar start - 1 + size <= end) 271f6703dd2SMarcel Moolenaar break; 272f6703dd2SMarcel Moolenaar } 273f6703dd2SMarcel Moolenaar if (r < ranges) { 274f6703dd2SMarcel Moolenaar sc->sc_banks[i].kva = sc->sc_range[r].kva + 275f6703dd2SMarcel Moolenaar (start - sc->sc_range[r].addr); 27625c22eb4SRafal Jaworowski } 277d1d3233eSRafal Jaworowski } 278f6703dd2SMarcel Moolenaar 279d1d3233eSRafal Jaworowski return (0); 280d1d3233eSRafal Jaworowski } 28125c22eb4SRafal Jaworowski 282d1d3233eSRafal Jaworowski static int 283d1d3233eSRafal Jaworowski lbc_banks_enable(struct lbc_softc *sc) 284d1d3233eSRafal Jaworowski { 285295be330SJustin Hibbits uint32_t size; 286d1d3233eSRafal Jaworowski uint32_t regval; 287d1d3233eSRafal Jaworowski int error, i; 288d1d3233eSRafal Jaworowski 289d1d3233eSRafal Jaworowski for (i = 0; i < LBC_DEV_MAX; i++) { 290d1d3233eSRafal Jaworowski size = sc->sc_banks[i].size; 29123fbc06bSMarcel Moolenaar if (size == 0) 292d1d3233eSRafal Jaworowski continue; 293f6703dd2SMarcel Moolenaar 29425c22eb4SRafal Jaworowski /* 295d1d3233eSRafal Jaworowski * Compute and program BR value. 29625c22eb4SRafal Jaworowski */ 297f6703dd2SMarcel Moolenaar regval = sc->sc_banks[i].addr; 298d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].width) { 29925c22eb4SRafal Jaworowski case 8: 300d1d3233eSRafal Jaworowski regval |= (1 << 11); 30125c22eb4SRafal Jaworowski break; 30225c22eb4SRafal Jaworowski case 16: 303d1d3233eSRafal Jaworowski regval |= (2 << 11); 30425c22eb4SRafal Jaworowski break; 30525c22eb4SRafal Jaworowski case 32: 306d1d3233eSRafal Jaworowski regval |= (3 << 11); 30725c22eb4SRafal Jaworowski break; 30825c22eb4SRafal Jaworowski default: 30925c22eb4SRafal Jaworowski error = EINVAL; 31025c22eb4SRafal Jaworowski goto fail; 31125c22eb4SRafal Jaworowski } 312d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].decc << 9); 313d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].wp << 8); 314d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].msel << 5); 315d1d3233eSRafal Jaworowski regval |= (sc->sc_banks[i].atom << 2); 316d1d3233eSRafal Jaworowski regval |= 1; 317f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 318f6703dd2SMarcel Moolenaar LBC85XX_BR(i), regval); 31925c22eb4SRafal Jaworowski 32025c22eb4SRafal Jaworowski /* 321d1d3233eSRafal Jaworowski * Compute and program OR value. 32225c22eb4SRafal Jaworowski */ 323f6703dd2SMarcel Moolenaar regval = lbc_address_mask(size); 324d1d3233eSRafal Jaworowski switch (sc->sc_banks[i].msel) { 32525c22eb4SRafal Jaworowski case LBCRES_MSEL_GPCM: 32625c22eb4SRafal Jaworowski /* TODO Add flag support for option registers */ 327f6703dd2SMarcel Moolenaar regval |= 0x0ff7; 32825c22eb4SRafal Jaworowski break; 32925c22eb4SRafal Jaworowski case LBCRES_MSEL_FCM: 330f6703dd2SMarcel Moolenaar /* TODO Add flag support for options register */ 331f6703dd2SMarcel Moolenaar regval |= 0x0796; 332f6703dd2SMarcel Moolenaar break; 33325c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMA: 33425c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMB: 33525c22eb4SRafal Jaworowski case LBCRES_MSEL_UPMC: 33625c22eb4SRafal Jaworowski printf("UPM mode not supported yet!"); 33725c22eb4SRafal Jaworowski error = ENOSYS; 33825c22eb4SRafal Jaworowski goto fail; 33925c22eb4SRafal Jaworowski } 340f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, 341f6703dd2SMarcel Moolenaar LBC85XX_OR(i), regval); 342d1d3233eSRafal Jaworowski } 34325c22eb4SRafal Jaworowski 34425c22eb4SRafal Jaworowski return (0); 345d1d3233eSRafal Jaworowski 34625c22eb4SRafal Jaworowski fail: 347d1d3233eSRafal Jaworowski lbc_banks_unmap(sc); 34825c22eb4SRafal Jaworowski return (error); 349d1d3233eSRafal Jaworowski } 350d1d3233eSRafal Jaworowski 351d1d3233eSRafal Jaworowski static void 352d1d3233eSRafal Jaworowski fdt_lbc_fixup(phandle_t node, struct lbc_softc *sc, struct lbc_devinfo *di) 353d1d3233eSRafal Jaworowski { 354d1d3233eSRafal Jaworowski pcell_t width; 355d1d3233eSRafal Jaworowski int bank; 356d1d3233eSRafal Jaworowski 357d1d3233eSRafal Jaworowski if (OF_getprop(node, "bank-width", (void *)&width, sizeof(width)) <= 0) 358d1d3233eSRafal Jaworowski return; 359d1d3233eSRafal Jaworowski 360d1d3233eSRafal Jaworowski bank = di->di_bank; 361d1d3233eSRafal Jaworowski if (sc->sc_banks[bank].size == 0) 362d1d3233eSRafal Jaworowski return; 363d1d3233eSRafal Jaworowski 364d1d3233eSRafal Jaworowski /* Express width in bits. */ 365d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = width * 8; 366d1d3233eSRafal Jaworowski } 367d1d3233eSRafal Jaworowski 368d1d3233eSRafal Jaworowski static int 369d1d3233eSRafal Jaworowski fdt_lbc_reg_decode(phandle_t node, struct lbc_softc *sc, 370d1d3233eSRafal Jaworowski struct lbc_devinfo *di) 371d1d3233eSRafal Jaworowski { 37283d9b89cSJustin Hibbits rman_res_t start, end, count; 373d1d3233eSRafal Jaworowski pcell_t *reg, *regptr; 374d1d3233eSRafal Jaworowski pcell_t addr_cells, size_cells; 375d1d3233eSRafal Jaworowski int tuple_size, tuples; 37683d9b89cSJustin Hibbits int i, j, rv, bank; 377d1d3233eSRafal Jaworowski 378d1d3233eSRafal Jaworowski if (fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells) != 0) 379d1d3233eSRafal Jaworowski return (ENXIO); 380d1d3233eSRafal Jaworowski 381d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (addr_cells + size_cells); 382f7604b1bSOleksandr Tymoshenko tuples = OF_getencprop_alloc_multi(node, "reg", tuple_size, 383f7604b1bSOleksandr Tymoshenko (void **)®); 384d1d3233eSRafal Jaworowski debugf("addr_cells = %d, size_cells = %d\n", addr_cells, size_cells); 385d1d3233eSRafal Jaworowski debugf("tuples = %d, tuple size = %d\n", tuples, tuple_size); 386d1d3233eSRafal Jaworowski if (tuples <= 0) 387d1d3233eSRafal Jaworowski /* No 'reg' property in this node. */ 388d1d3233eSRafal Jaworowski return (0); 389d1d3233eSRafal Jaworowski 390d1d3233eSRafal Jaworowski regptr = reg; 391d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 392d1d3233eSRafal Jaworowski bank = fdt_data_get((void *)reg, 1); 393d1d3233eSRafal Jaworowski di->di_bank = bank; 394d1d3233eSRafal Jaworowski reg += 1; 395d1d3233eSRafal Jaworowski 396d1d3233eSRafal Jaworowski /* Get address/size. */ 39783d9b89cSJustin Hibbits start = count = 0; 3987d7671dbSJustin Hibbits for (j = 0; j < addr_cells - 1; j++) { 39983d9b89cSJustin Hibbits start <<= 32; 40083d9b89cSJustin Hibbits start |= reg[j]; 40183d9b89cSJustin Hibbits } 40283d9b89cSJustin Hibbits for (j = 0; j < size_cells; j++) { 40383d9b89cSJustin Hibbits count <<= 32; 404a80e3de3SJustin Hibbits count |= reg[addr_cells + j - 1]; 405d1d3233eSRafal Jaworowski } 406d1d3233eSRafal Jaworowski reg += addr_cells - 1 + size_cells; 407d1d3233eSRafal Jaworowski 408d1d3233eSRafal Jaworowski /* Calculate address range relative to VA base. */ 409f6703dd2SMarcel Moolenaar start = sc->sc_banks[bank].kva + start; 410d1d3233eSRafal Jaworowski end = start + count - 1; 411d1d3233eSRafal Jaworowski 41283d9b89cSJustin Hibbits debugf("reg addr bank = %d, start = %jx, end = %jx, " 41383d9b89cSJustin Hibbits "count = %jx\n", bank, start, end, count); 414d1d3233eSRafal Jaworowski 415d1d3233eSRafal Jaworowski /* Use bank (CS) cell as rid. */ 416d1d3233eSRafal Jaworowski resource_list_add(&di->di_res, SYS_RES_MEMORY, bank, start, 417d1d3233eSRafal Jaworowski end, count); 418d1d3233eSRafal Jaworowski } 419d1d3233eSRafal Jaworowski rv = 0; 4200cc376c1SOleksandr Tymoshenko OF_prop_free(regptr); 421d1d3233eSRafal Jaworowski return (rv); 42225c22eb4SRafal Jaworowski } 42325c22eb4SRafal Jaworowski 42423fbc06bSMarcel Moolenaar static void 42523fbc06bSMarcel Moolenaar lbc_intr(void *arg) 42623fbc06bSMarcel Moolenaar { 42723fbc06bSMarcel Moolenaar struct lbc_softc *sc = arg; 42823fbc06bSMarcel Moolenaar uint32_t ltesr; 42923fbc06bSMarcel Moolenaar 43023fbc06bSMarcel Moolenaar ltesr = bus_space_read_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR); 43123fbc06bSMarcel Moolenaar sc->sc_ltesr = ltesr; 43223fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ltesr); 43323fbc06bSMarcel Moolenaar wakeup(sc->sc_dev); 43423fbc06bSMarcel Moolenaar } 43523fbc06bSMarcel Moolenaar 43625c22eb4SRafal Jaworowski static int 43708077f58SMarcel Moolenaar lbc_probe(device_t dev) 43808077f58SMarcel Moolenaar { 43908077f58SMarcel Moolenaar 440d1d3233eSRafal Jaworowski if (!(ofw_bus_is_compatible(dev, "fsl,lbc") || 441d1d3233eSRafal Jaworowski ofw_bus_is_compatible(dev, "fsl,elbc"))) 44208077f58SMarcel Moolenaar return (ENXIO); 44308077f58SMarcel Moolenaar 444d1d3233eSRafal Jaworowski device_set_desc(dev, "Freescale Local Bus Controller"); 44508077f58SMarcel Moolenaar return (BUS_PROBE_DEFAULT); 44608077f58SMarcel Moolenaar } 44708077f58SMarcel Moolenaar 44808077f58SMarcel Moolenaar static int 44908077f58SMarcel Moolenaar lbc_attach(device_t dev) 45008077f58SMarcel Moolenaar { 45108077f58SMarcel Moolenaar struct lbc_softc *sc; 452d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 45308077f58SMarcel Moolenaar struct rman *rm; 45483d9b89cSJustin Hibbits uintmax_t offset, size; 45583d9b89cSJustin Hibbits vm_paddr_t start; 456d1d3233eSRafal Jaworowski device_t cdev; 457d1d3233eSRafal Jaworowski phandle_t node, child; 458d1d3233eSRafal Jaworowski pcell_t *ranges, *rangesptr; 459d1d3233eSRafal Jaworowski int tuple_size, tuples; 460d1d3233eSRafal Jaworowski int par_addr_cells; 46183d9b89cSJustin Hibbits int bank, error, i, j; 46208077f58SMarcel Moolenaar 46308077f58SMarcel Moolenaar sc = device_get_softc(dev); 46408077f58SMarcel Moolenaar sc->sc_dev = dev; 46508077f58SMarcel Moolenaar 46623fbc06bSMarcel Moolenaar sc->sc_mrid = 0; 46723fbc06bSMarcel Moolenaar sc->sc_mres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->sc_mrid, 46808077f58SMarcel Moolenaar RF_ACTIVE); 46923fbc06bSMarcel Moolenaar if (sc->sc_mres == NULL) 47008077f58SMarcel Moolenaar return (ENXIO); 47108077f58SMarcel Moolenaar 47223fbc06bSMarcel Moolenaar sc->sc_bst = rman_get_bustag(sc->sc_mres); 47323fbc06bSMarcel Moolenaar sc->sc_bsh = rman_get_bushandle(sc->sc_mres); 47423fbc06bSMarcel Moolenaar 47523fbc06bSMarcel Moolenaar for (bank = 0; bank < LBC_DEV_MAX; bank++) { 47623fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_BR(bank), 0); 47723fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_OR(bank), 0); 47823fbc06bSMarcel Moolenaar } 47923fbc06bSMarcel Moolenaar 48023fbc06bSMarcel Moolenaar /* 48123fbc06bSMarcel Moolenaar * Initialize configuration register: 48223fbc06bSMarcel Moolenaar * - enable Local Bus 48323fbc06bSMarcel Moolenaar * - set data buffer control signal function 48423fbc06bSMarcel Moolenaar * - disable parity byte select 48523fbc06bSMarcel Moolenaar * - set ECC parity type 48623fbc06bSMarcel Moolenaar * - set bus monitor timing and timer prescale 48723fbc06bSMarcel Moolenaar */ 48823fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LBCR, 0); 48923fbc06bSMarcel Moolenaar 49023fbc06bSMarcel Moolenaar /* 49123fbc06bSMarcel Moolenaar * Initialize clock ratio register: 49223fbc06bSMarcel Moolenaar * - disable PLL bypass mode 49323fbc06bSMarcel Moolenaar * - configure LCLK delay cycles for the assertion of LALE 49423fbc06bSMarcel Moolenaar * - set system clock divider 49523fbc06bSMarcel Moolenaar */ 49623fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LCRR, 0x00030008); 49723fbc06bSMarcel Moolenaar 49823fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEDR, 0); 49923fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTESR, ~0); 50023fbc06bSMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, LBC85XX_LTEIR, 0x64080001); 50123fbc06bSMarcel Moolenaar 50223fbc06bSMarcel Moolenaar sc->sc_irid = 0; 50323fbc06bSMarcel Moolenaar sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->sc_irid, 50423fbc06bSMarcel Moolenaar RF_ACTIVE | RF_SHAREABLE); 50523fbc06bSMarcel Moolenaar if (sc->sc_ires != NULL) { 50623fbc06bSMarcel Moolenaar error = bus_setup_intr(dev, sc->sc_ires, 50723fbc06bSMarcel Moolenaar INTR_TYPE_MISC | INTR_MPSAFE, NULL, lbc_intr, sc, 50823fbc06bSMarcel Moolenaar &sc->sc_icookie); 50923fbc06bSMarcel Moolenaar if (error) { 51023fbc06bSMarcel Moolenaar device_printf(dev, "could not activate interrupt\n"); 51123fbc06bSMarcel Moolenaar bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, 51223fbc06bSMarcel Moolenaar sc->sc_ires); 51323fbc06bSMarcel Moolenaar sc->sc_ires = NULL; 51423fbc06bSMarcel Moolenaar } 51523fbc06bSMarcel Moolenaar } 51623fbc06bSMarcel Moolenaar 51723fbc06bSMarcel Moolenaar sc->sc_ltesr = ~0; 51823fbc06bSMarcel Moolenaar 519d1d3233eSRafal Jaworowski rangesptr = NULL; 52008077f58SMarcel Moolenaar 52108077f58SMarcel Moolenaar rm = &sc->sc_rman; 52208077f58SMarcel Moolenaar rm->rm_type = RMAN_ARRAY; 523d1d3233eSRafal Jaworowski rm->rm_descr = "Local Bus Space"; 52408077f58SMarcel Moolenaar error = rman_init(rm); 52508077f58SMarcel Moolenaar if (error) 52608077f58SMarcel Moolenaar goto fail; 52708077f58SMarcel Moolenaar 52808077f58SMarcel Moolenaar error = rman_manage_region(rm, rm->rm_start, rm->rm_end); 52908077f58SMarcel Moolenaar if (error) { 53008077f58SMarcel Moolenaar rman_fini(rm); 53108077f58SMarcel Moolenaar goto fail; 53208077f58SMarcel Moolenaar } 53308077f58SMarcel Moolenaar 53425c22eb4SRafal Jaworowski /* 535d1d3233eSRafal Jaworowski * Process 'ranges' property. 53625c22eb4SRafal Jaworowski */ 537d1d3233eSRafal Jaworowski node = ofw_bus_get_node(dev); 538d1d3233eSRafal Jaworowski if ((fdt_addrsize_cells(node, &sc->sc_addr_cells, 539d1d3233eSRafal Jaworowski &sc->sc_size_cells)) != 0) { 54025c22eb4SRafal Jaworowski error = ENXIO; 54125c22eb4SRafal Jaworowski goto fail; 54225c22eb4SRafal Jaworowski } 54308077f58SMarcel Moolenaar 544d1d3233eSRafal Jaworowski par_addr_cells = fdt_parent_addr_cells(node); 545d1d3233eSRafal Jaworowski if (par_addr_cells > 2) { 546d1d3233eSRafal Jaworowski device_printf(dev, "unsupported parent #addr-cells\n"); 547d1d3233eSRafal Jaworowski error = ERANGE; 548d1d3233eSRafal Jaworowski goto fail; 549d1d3233eSRafal Jaworowski } 550d1d3233eSRafal Jaworowski tuple_size = sizeof(pcell_t) * (sc->sc_addr_cells + par_addr_cells + 551d1d3233eSRafal Jaworowski sc->sc_size_cells); 552d1d3233eSRafal Jaworowski 553f7604b1bSOleksandr Tymoshenko tuples = OF_getencprop_alloc_multi(node, "ranges", tuple_size, 554d1d3233eSRafal Jaworowski (void **)&ranges); 555d1d3233eSRafal Jaworowski if (tuples < 0) { 556d1d3233eSRafal Jaworowski device_printf(dev, "could not retrieve 'ranges' property\n"); 557d1d3233eSRafal Jaworowski error = ENXIO; 558d1d3233eSRafal Jaworowski goto fail; 559d1d3233eSRafal Jaworowski } 560d1d3233eSRafal Jaworowski rangesptr = ranges; 561d1d3233eSRafal Jaworowski 562d1d3233eSRafal Jaworowski debugf("par addr_cells = %d, addr_cells = %d, size_cells = %d, " 563d1d3233eSRafal Jaworowski "tuple_size = %d, tuples = %d\n", par_addr_cells, 564d1d3233eSRafal Jaworowski sc->sc_addr_cells, sc->sc_size_cells, tuple_size, tuples); 565d1d3233eSRafal Jaworowski 566d1d3233eSRafal Jaworowski start = 0; 567d1d3233eSRafal Jaworowski size = 0; 568d1d3233eSRafal Jaworowski for (i = 0; i < tuples; i++) { 569d1d3233eSRafal Jaworowski /* The first cell is the bank (chip select) number. */ 57083d9b89cSJustin Hibbits bank = fdt_data_get(ranges, 1); 571d1d3233eSRafal Jaworowski if (bank < 0 || bank > LBC_DEV_MAX) { 572d1d3233eSRafal Jaworowski device_printf(dev, "bank out of range: %d\n", bank); 573d1d3233eSRafal Jaworowski error = ERANGE; 574d1d3233eSRafal Jaworowski goto fail; 575d1d3233eSRafal Jaworowski } 576d1d3233eSRafal Jaworowski ranges += 1; 577d1d3233eSRafal Jaworowski 578d1d3233eSRafal Jaworowski /* 579d1d3233eSRafal Jaworowski * Remaining cells of the child address define offset into 580d1d3233eSRafal Jaworowski * this CS. 581d1d3233eSRafal Jaworowski */ 58283d9b89cSJustin Hibbits offset = 0; 58383d9b89cSJustin Hibbits for (j = 0; j < sc->sc_addr_cells - 1; j++) { 58483d9b89cSJustin Hibbits offset <<= sizeof(pcell_t) * 8; 58583d9b89cSJustin Hibbits offset |= *ranges; 58683d9b89cSJustin Hibbits ranges++; 58783d9b89cSJustin Hibbits } 588d1d3233eSRafal Jaworowski 589d1d3233eSRafal Jaworowski /* Parent bus start address of this bank. */ 59083d9b89cSJustin Hibbits start = 0; 59183d9b89cSJustin Hibbits for (j = 0; j < par_addr_cells; j++) { 59283d9b89cSJustin Hibbits start <<= sizeof(pcell_t) * 8; 59383d9b89cSJustin Hibbits start |= *ranges; 59483d9b89cSJustin Hibbits ranges++; 59583d9b89cSJustin Hibbits } 596d1d3233eSRafal Jaworowski 597d1d3233eSRafal Jaworowski size = fdt_data_get((void *)ranges, sc->sc_size_cells); 598d1d3233eSRafal Jaworowski ranges += sc->sc_size_cells; 59983d9b89cSJustin Hibbits debugf("bank = %d, start = %jx, size = %jx\n", bank, 60083d9b89cSJustin Hibbits (uintmax_t)start, size); 601d1d3233eSRafal Jaworowski 602f6703dd2SMarcel Moolenaar sc->sc_banks[bank].addr = start + offset; 603d1d3233eSRafal Jaworowski sc->sc_banks[bank].size = size; 604d1d3233eSRafal Jaworowski 605d1d3233eSRafal Jaworowski /* 606d1d3233eSRafal Jaworowski * Attributes for the bank. 607d1d3233eSRafal Jaworowski * 608d1d3233eSRafal Jaworowski * XXX Note there are no DT bindings defined for them at the 609d1d3233eSRafal Jaworowski * moment, so we need to provide some defaults. 610d1d3233eSRafal Jaworowski */ 611d1d3233eSRafal Jaworowski sc->sc_banks[bank].width = 16; 612d1d3233eSRafal Jaworowski sc->sc_banks[bank].msel = LBCRES_MSEL_GPCM; 613d1d3233eSRafal Jaworowski sc->sc_banks[bank].decc = LBCRES_DECC_DISABLED; 614d1d3233eSRafal Jaworowski sc->sc_banks[bank].atom = LBCRES_ATOM_DISABLED; 615d1d3233eSRafal Jaworowski sc->sc_banks[bank].wp = 0; 616d1d3233eSRafal Jaworowski } 617d1d3233eSRafal Jaworowski 618d1d3233eSRafal Jaworowski /* 619d1d3233eSRafal Jaworowski * Initialize mem-mappings for the LBC banks (i.e. chip selects). 620d1d3233eSRafal Jaworowski */ 621d1d3233eSRafal Jaworowski error = lbc_banks_map(sc); 622d1d3233eSRafal Jaworowski if (error) 623d1d3233eSRafal Jaworowski goto fail; 624d1d3233eSRafal Jaworowski 625d1d3233eSRafal Jaworowski /* 626d1d3233eSRafal Jaworowski * Walk the localbus and add direct subordinates as our children. 627d1d3233eSRafal Jaworowski */ 628d1d3233eSRafal Jaworowski for (child = OF_child(node); child != 0; child = OF_peer(child)) { 629d1d3233eSRafal Jaworowski di = malloc(sizeof(*di), M_LBC, M_WAITOK | M_ZERO); 630d1d3233eSRafal Jaworowski 631d1d3233eSRafal Jaworowski if (ofw_bus_gen_setup_devinfo(&di->di_ofw, child) != 0) { 632d1d3233eSRafal Jaworowski free(di, M_LBC); 633d1d3233eSRafal Jaworowski device_printf(dev, "could not set up devinfo\n"); 634d1d3233eSRafal Jaworowski continue; 635d1d3233eSRafal Jaworowski } 636d1d3233eSRafal Jaworowski 637d1d3233eSRafal Jaworowski resource_list_init(&di->di_res); 638d1d3233eSRafal Jaworowski 639d1d3233eSRafal Jaworowski if (fdt_lbc_reg_decode(child, sc, di)) { 640d1d3233eSRafal Jaworowski device_printf(dev, "could not process 'reg' " 641d1d3233eSRafal Jaworowski "property\n"); 642d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 643d1d3233eSRafal Jaworowski free(di, M_LBC); 644d1d3233eSRafal Jaworowski continue; 645d1d3233eSRafal Jaworowski } 646d1d3233eSRafal Jaworowski 647d1d3233eSRafal Jaworowski fdt_lbc_fixup(child, sc, di); 648d1d3233eSRafal Jaworowski 649d1d3233eSRafal Jaworowski /* Add newbus device for this FDT node */ 650d1d3233eSRafal Jaworowski cdev = device_add_child(dev, NULL, -1); 651d1d3233eSRafal Jaworowski if (cdev == NULL) { 652d1d3233eSRafal Jaworowski device_printf(dev, "could not add child: %s\n", 653d1d3233eSRafal Jaworowski di->di_ofw.obd_name); 654d1d3233eSRafal Jaworowski resource_list_free(&di->di_res); 655d1d3233eSRafal Jaworowski ofw_bus_gen_destroy_devinfo(&di->di_ofw); 656d1d3233eSRafal Jaworowski free(di, M_LBC); 657d1d3233eSRafal Jaworowski continue; 658d1d3233eSRafal Jaworowski } 6598c6037c4SJustin Hibbits debugf("added child name='%s', node=%x\n", di->di_ofw.obd_name, 6608c6037c4SJustin Hibbits child); 661d1d3233eSRafal Jaworowski device_set_ivars(cdev, di); 662d1d3233eSRafal Jaworowski } 663d1d3233eSRafal Jaworowski 664d1d3233eSRafal Jaworowski /* 665d1d3233eSRafal Jaworowski * Enable the LBC. 666d1d3233eSRafal Jaworowski */ 667d1d3233eSRafal Jaworowski lbc_banks_enable(sc); 668d1d3233eSRafal Jaworowski 6690cc376c1SOleksandr Tymoshenko OF_prop_free(rangesptr); 67008077f58SMarcel Moolenaar return (bus_generic_attach(dev)); 67108077f58SMarcel Moolenaar 67208077f58SMarcel Moolenaar fail: 6730cc376c1SOleksandr Tymoshenko OF_prop_free(rangesptr); 67423fbc06bSMarcel Moolenaar bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mrid, sc->sc_mres); 67508077f58SMarcel Moolenaar return (error); 67608077f58SMarcel Moolenaar } 67708077f58SMarcel Moolenaar 67808077f58SMarcel Moolenaar static int 67908077f58SMarcel Moolenaar lbc_shutdown(device_t dev) 68008077f58SMarcel Moolenaar { 68108077f58SMarcel Moolenaar 68208077f58SMarcel Moolenaar /* TODO */ 68308077f58SMarcel Moolenaar return(0); 68408077f58SMarcel Moolenaar } 68508077f58SMarcel Moolenaar 6865a7e717fSJohn Baldwin static struct rman * 6875a7e717fSJohn Baldwin lbc_get_rman(device_t bus, int type, u_int flags) 6885a7e717fSJohn Baldwin { 6895a7e717fSJohn Baldwin struct lbc_softc *sc; 6905a7e717fSJohn Baldwin 6915a7e717fSJohn Baldwin sc = device_get_softc(bus); 6925a7e717fSJohn Baldwin switch (type) { 6935a7e717fSJohn Baldwin case SYS_RES_MEMORY: 6945a7e717fSJohn Baldwin return (&sc->sc_rman); 6955a7e717fSJohn Baldwin default: 6965a7e717fSJohn Baldwin return (NULL); 6975a7e717fSJohn Baldwin } 6985a7e717fSJohn Baldwin } 6995a7e717fSJohn Baldwin 70008077f58SMarcel Moolenaar static struct resource * 701d1d3233eSRafal Jaworowski lbc_alloc_resource(device_t bus, device_t child, int type, int *rid, 7022dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 70308077f58SMarcel Moolenaar { 704d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 705d1d3233eSRafal Jaworowski struct resource_list_entry *rle; 70608077f58SMarcel Moolenaar 70708077f58SMarcel Moolenaar /* We only support default allocations. */ 708f7dc5935SJustin Hibbits if (!RMAN_IS_DEFAULT_RANGE(start, end)) 70908077f58SMarcel Moolenaar return (NULL); 71008077f58SMarcel Moolenaar 71108077f58SMarcel Moolenaar if (type == SYS_RES_IRQ) 712d1d3233eSRafal Jaworowski return (bus_alloc_resource(bus, type, rid, start, end, count, 71308077f58SMarcel Moolenaar flags)); 71408077f58SMarcel Moolenaar 715d1d3233eSRafal Jaworowski /* 716d1d3233eSRafal Jaworowski * Request for the default allocation with a given rid: use resource 717d1d3233eSRafal Jaworowski * list stored in the local device info. 718d1d3233eSRafal Jaworowski */ 719d1d3233eSRafal Jaworowski if ((di = device_get_ivars(child)) == NULL) 720d1d3233eSRafal Jaworowski return (NULL); 721d1d3233eSRafal Jaworowski 722d1d3233eSRafal Jaworowski if (type == SYS_RES_IOPORT) 723d1d3233eSRafal Jaworowski type = SYS_RES_MEMORY; 724d1d3233eSRafal Jaworowski 7255a7e717fSJohn Baldwin /* 7265a7e717fSJohn Baldwin * XXX: We are supposed to return a value to the user, so this 7275a7e717fSJohn Baldwin * doesn't seem right. 7285a7e717fSJohn Baldwin */ 729d1d3233eSRafal Jaworowski rid = &di->di_bank; 730d1d3233eSRafal Jaworowski 731d1d3233eSRafal Jaworowski rle = resource_list_find(&di->di_res, type, *rid); 732d1d3233eSRafal Jaworowski if (rle == NULL) { 733d1d3233eSRafal Jaworowski device_printf(bus, "no default resources for " 734d1d3233eSRafal Jaworowski "rid = %d, type = %d\n", *rid, type); 73525c22eb4SRafal Jaworowski return (NULL); 73625c22eb4SRafal Jaworowski } 737d1d3233eSRafal Jaworowski start = rle->start; 738d1d3233eSRafal Jaworowski count = rle->count; 739d1d3233eSRafal Jaworowski end = start + count - 1; 74025c22eb4SRafal Jaworowski 7415a7e717fSJohn Baldwin return (bus_generic_rman_alloc_resource(bus, child, type, rid, start, 7425a7e717fSJohn Baldwin end, count, flags)); 74308077f58SMarcel Moolenaar } 74408077f58SMarcel Moolenaar 74508077f58SMarcel Moolenaar static int 74608077f58SMarcel Moolenaar lbc_print_child(device_t dev, device_t child) 74708077f58SMarcel Moolenaar { 748d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 749d1d3233eSRafal Jaworowski struct resource_list *rl; 750d1d3233eSRafal Jaworowski int rv; 75108077f58SMarcel Moolenaar 752d1d3233eSRafal Jaworowski di = device_get_ivars(child); 753d1d3233eSRafal Jaworowski rl = &di->di_res; 75408077f58SMarcel Moolenaar 755d1d3233eSRafal Jaworowski rv = 0; 756d1d3233eSRafal Jaworowski rv += bus_print_child_header(dev, child); 757da1b038aSJustin Hibbits rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 758da1b038aSJustin Hibbits rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%jd"); 759d1d3233eSRafal Jaworowski rv += bus_print_child_footer(dev, child); 76008077f58SMarcel Moolenaar 761d1d3233eSRafal Jaworowski return (rv); 76208077f58SMarcel Moolenaar } 76308077f58SMarcel Moolenaar 76408077f58SMarcel Moolenaar static int 765fef01f04SJohn Baldwin lbc_adjust_resource(device_t dev, device_t child, struct resource *r, 7665a7e717fSJohn Baldwin rman_res_t start, rman_res_t end) 7675a7e717fSJohn Baldwin { 768fef01f04SJohn Baldwin switch (rman_get_type(r)) { 7695a7e717fSJohn Baldwin case SYS_RES_MEMORY: 770fef01f04SJohn Baldwin return (bus_generic_rman_adjust_resource(dev, child, r, start, 77168a3ff04SJohn Baldwin end)); 772fef01f04SJohn Baldwin case SYS_RES_IRQ: 773fef01f04SJohn Baldwin return (bus_generic_adjust_resource(dev, child, r, start, end)); 7745a7e717fSJohn Baldwin default: 7755a7e717fSJohn Baldwin return (EINVAL); 7765a7e717fSJohn Baldwin } 7775a7e717fSJohn Baldwin } 7785a7e717fSJohn Baldwin 7795a7e717fSJohn Baldwin static int 78008077f58SMarcel Moolenaar lbc_release_resource(device_t dev, device_t child, int type, int rid, 78108077f58SMarcel Moolenaar struct resource *res) 78208077f58SMarcel Moolenaar { 7835a7e717fSJohn Baldwin switch (type) { 7845a7e717fSJohn Baldwin case SYS_RES_IOPORT: 7855a7e717fSJohn Baldwin type = SYS_RES_MEMORY; 7865a7e717fSJohn Baldwin /* FALLTHROUGH */ 7875a7e717fSJohn Baldwin case SYS_RES_MEMORY: 7885a7e717fSJohn Baldwin return (bus_generic_rman_release_resource(dev, child, type, 7895a7e717fSJohn Baldwin rid, res)); 7905a7e717fSJohn Baldwin case SYS_RES_IRQ: 791cd9d26edSJohn Baldwin return (bus_generic_release_resource(dev, child, type, rid, res)); 7925a7e717fSJohn Baldwin default: 7935a7e717fSJohn Baldwin return (EINVAL); 794d1d3233eSRafal Jaworowski } 79508077f58SMarcel Moolenaar } 79608077f58SMarcel Moolenaar 7978bc8506eSJustin Hibbits static int 7985a7e717fSJohn Baldwin lbc_activate_resource(device_t bus, device_t child, int type, int rid, 7995a7e717fSJohn Baldwin struct resource *r) 8008bc8506eSJustin Hibbits { 8015a7e717fSJohn Baldwin switch (type) { 8025a7e717fSJohn Baldwin case SYS_RES_IOPORT: 8035a7e717fSJohn Baldwin type = SYS_RES_MEMORY; 8045a7e717fSJohn Baldwin /* FALLTHROUGH */ 8055a7e717fSJohn Baldwin case SYS_RES_MEMORY: 8065a7e717fSJohn Baldwin return (bus_generic_rman_activate_resource(bus, child, type, 8075a7e717fSJohn Baldwin rid, r)); 8085a7e717fSJohn Baldwin case SYS_RES_IRQ: 809cd9d26edSJohn Baldwin return (bus_generic_activate_resource(bus, child, type, rid, r)); 8105a7e717fSJohn Baldwin default: 8115a7e717fSJohn Baldwin return (EINVAL); 8125a7e717fSJohn Baldwin } 8138bc8506eSJustin Hibbits } 8148bc8506eSJustin Hibbits 8158bc8506eSJustin Hibbits static int 8165a7e717fSJohn Baldwin lbc_deactivate_resource(device_t bus, device_t child, int type, int rid, 8175a7e717fSJohn Baldwin struct resource *r) 8185a7e717fSJohn Baldwin { 8195a7e717fSJohn Baldwin switch (type) { 8205a7e717fSJohn Baldwin case SYS_RES_IOPORT: 8215a7e717fSJohn Baldwin type = SYS_RES_MEMORY; 8225a7e717fSJohn Baldwin /* FALLTHROUGH */ 8235a7e717fSJohn Baldwin case SYS_RES_MEMORY: 8245a7e717fSJohn Baldwin return (bus_generic_rman_deactivate_resource(bus, child, type, 8255a7e717fSJohn Baldwin rid, r)); 8265a7e717fSJohn Baldwin case SYS_RES_IRQ: 827cd9d26edSJohn Baldwin return (bus_generic_deactivate_resource(bus, child, type, rid, r)); 8285a7e717fSJohn Baldwin default: 8295a7e717fSJohn Baldwin return (EINVAL); 8305a7e717fSJohn Baldwin } 8315a7e717fSJohn Baldwin } 8325a7e717fSJohn Baldwin 8335a7e717fSJohn Baldwin static int 834*d77f2092SJohn Baldwin lbc_map_resource(device_t bus, device_t child, struct resource *r, 8355a7e717fSJohn Baldwin struct resource_map_request *argsp, struct resource_map *map) 8365a7e717fSJohn Baldwin { 8375a7e717fSJohn Baldwin struct resource_map_request args; 8385a7e717fSJohn Baldwin rman_res_t length, start; 8395a7e717fSJohn Baldwin int error; 8405a7e717fSJohn Baldwin 8415a7e717fSJohn Baldwin /* Resources must be active to be mapped. */ 8425a7e717fSJohn Baldwin if (!(rman_get_flags(r) & RF_ACTIVE)) 8435a7e717fSJohn Baldwin return (ENXIO); 8445a7e717fSJohn Baldwin 8455a7e717fSJohn Baldwin /* Mappings are only supported on I/O and memory resources. */ 846*d77f2092SJohn Baldwin switch (rman_get_type(r)) { 8475a7e717fSJohn Baldwin case SYS_RES_IOPORT: 8485a7e717fSJohn Baldwin case SYS_RES_MEMORY: 8495a7e717fSJohn Baldwin break; 8505a7e717fSJohn Baldwin default: 8515a7e717fSJohn Baldwin return (EINVAL); 8525a7e717fSJohn Baldwin } 8535a7e717fSJohn Baldwin 8545a7e717fSJohn Baldwin resource_init_map_request(&args); 8555a7e717fSJohn Baldwin error = resource_validate_map_request(r, argsp, &args, &start, &length); 8565a7e717fSJohn Baldwin if (error) 8575a7e717fSJohn Baldwin return (error); 8585a7e717fSJohn Baldwin 8595a7e717fSJohn Baldwin map->r_bustag = &bs_be_tag; 8605a7e717fSJohn Baldwin map->r_bushandle = start; 8615a7e717fSJohn Baldwin map->r_size = length; 8625a7e717fSJohn Baldwin map->r_vaddr = NULL; 8635a7e717fSJohn Baldwin return (0); 8645a7e717fSJohn Baldwin } 8655a7e717fSJohn Baldwin 8665a7e717fSJohn Baldwin static int 867*d77f2092SJohn Baldwin lbc_unmap_resource(device_t bus, device_t child, struct resource *r, 8685a7e717fSJohn Baldwin struct resource_map *map) 8698bc8506eSJustin Hibbits { 8708bc8506eSJustin Hibbits 8715a7e717fSJohn Baldwin /* Mappings are only supported on I/O and memory resources. */ 872*d77f2092SJohn Baldwin switch (rman_get_type(r)) { 8735a7e717fSJohn Baldwin case SYS_RES_IOPORT: 8745a7e717fSJohn Baldwin case SYS_RES_MEMORY: 8755a7e717fSJohn Baldwin break; 8765a7e717fSJohn Baldwin default: 8775a7e717fSJohn Baldwin return (EINVAL); 8785a7e717fSJohn Baldwin } 8795a7e717fSJohn Baldwin return (0); 8808bc8506eSJustin Hibbits } 8818bc8506eSJustin Hibbits 882d1d3233eSRafal Jaworowski static const struct ofw_bus_devinfo * 883d1d3233eSRafal Jaworowski lbc_get_devinfo(device_t bus, device_t child) 88408077f58SMarcel Moolenaar { 885d1d3233eSRafal Jaworowski struct lbc_devinfo *di; 88608077f58SMarcel Moolenaar 887d1d3233eSRafal Jaworowski di = device_get_ivars(child); 888d1d3233eSRafal Jaworowski return (&di->di_ofw); 88908077f58SMarcel Moolenaar } 890f6703dd2SMarcel Moolenaar 891f6703dd2SMarcel Moolenaar void 892f6703dd2SMarcel Moolenaar lbc_write_reg(device_t child, u_int off, uint32_t val) 893f6703dd2SMarcel Moolenaar { 89423fbc06bSMarcel Moolenaar device_t dev; 895f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 896f6703dd2SMarcel Moolenaar 89723fbc06bSMarcel Moolenaar dev = device_get_parent(child); 89823fbc06bSMarcel Moolenaar 89923fbc06bSMarcel Moolenaar if (off >= 0x1000) { 90023fbc06bSMarcel Moolenaar device_printf(dev, "%s(%s): invalid offset %#x\n", 90123fbc06bSMarcel Moolenaar __func__, device_get_nameunit(child), off); 90223fbc06bSMarcel Moolenaar return; 90323fbc06bSMarcel Moolenaar } 90423fbc06bSMarcel Moolenaar 90523fbc06bSMarcel Moolenaar sc = device_get_softc(dev); 90623fbc06bSMarcel Moolenaar 90723fbc06bSMarcel Moolenaar if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0u) { 90823fbc06bSMarcel Moolenaar sc->sc_ltesr ^= (val & sc->sc_ltesr); 90923fbc06bSMarcel Moolenaar return; 91023fbc06bSMarcel Moolenaar } 91123fbc06bSMarcel Moolenaar 91223fbc06bSMarcel Moolenaar if (off == LBC85XX_LTEATR && (val & 1) == 0) 91323fbc06bSMarcel Moolenaar sc->sc_ltesr = ~0u; 914f6703dd2SMarcel Moolenaar bus_space_write_4(sc->sc_bst, sc->sc_bsh, off, val); 915f6703dd2SMarcel Moolenaar } 916f6703dd2SMarcel Moolenaar 917f6703dd2SMarcel Moolenaar uint32_t 918f6703dd2SMarcel Moolenaar lbc_read_reg(device_t child, u_int off) 919f6703dd2SMarcel Moolenaar { 92023fbc06bSMarcel Moolenaar device_t dev; 921f6703dd2SMarcel Moolenaar struct lbc_softc *sc; 92223fbc06bSMarcel Moolenaar uint32_t val; 923f6703dd2SMarcel Moolenaar 92423fbc06bSMarcel Moolenaar dev = device_get_parent(child); 92523fbc06bSMarcel Moolenaar 92623fbc06bSMarcel Moolenaar if (off >= 0x1000) { 92723fbc06bSMarcel Moolenaar device_printf(dev, "%s(%s): invalid offset %#x\n", 92823fbc06bSMarcel Moolenaar __func__, device_get_nameunit(child), off); 92923fbc06bSMarcel Moolenaar return (~0U); 93023fbc06bSMarcel Moolenaar } 93123fbc06bSMarcel Moolenaar 93223fbc06bSMarcel Moolenaar sc = device_get_softc(dev); 93323fbc06bSMarcel Moolenaar 93423fbc06bSMarcel Moolenaar if (off == LBC85XX_LTESR && sc->sc_ltesr != ~0U) 93523fbc06bSMarcel Moolenaar val = sc->sc_ltesr; 93623fbc06bSMarcel Moolenaar else 93723fbc06bSMarcel Moolenaar val = bus_space_read_4(sc->sc_bst, sc->sc_bsh, off); 93823fbc06bSMarcel Moolenaar return (val); 939f6703dd2SMarcel Moolenaar } 940