1*3f51d888SZbigniew Bodek /* 2*3f51d888SZbigniew Bodek * Copyright (C) 2016 Cavium Inc. 3*3f51d888SZbigniew Bodek * All rights reserved. 4*3f51d888SZbigniew Bodek * 5*3f51d888SZbigniew Bodek * Developed by Semihalf. 6*3f51d888SZbigniew Bodek * 7*3f51d888SZbigniew Bodek * Redistribution and use in source and binary forms, with or without 8*3f51d888SZbigniew Bodek * modification, are permitted provided that the following conditions 9*3f51d888SZbigniew Bodek * are met: 10*3f51d888SZbigniew Bodek * 1. Redistributions of source code must retain the above copyright 11*3f51d888SZbigniew Bodek * notice, this list of conditions and the following disclaimer. 12*3f51d888SZbigniew Bodek * 2. Redistributions in binary form must reproduce the above copyright 13*3f51d888SZbigniew Bodek * notice, this list of conditions and the following disclaimer in the 14*3f51d888SZbigniew Bodek * documentation and/or other materials provided with the distribution. 15*3f51d888SZbigniew Bodek * 16*3f51d888SZbigniew Bodek * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17*3f51d888SZbigniew Bodek * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18*3f51d888SZbigniew Bodek * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19*3f51d888SZbigniew Bodek * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20*3f51d888SZbigniew Bodek * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21*3f51d888SZbigniew Bodek * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22*3f51d888SZbigniew Bodek * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23*3f51d888SZbigniew Bodek * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24*3f51d888SZbigniew Bodek * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25*3f51d888SZbigniew Bodek * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26*3f51d888SZbigniew Bodek * SUCH DAMAGE. 27*3f51d888SZbigniew Bodek */ 28*3f51d888SZbigniew Bodek #include "opt_platform.h" 29*3f51d888SZbigniew Bodek 30*3f51d888SZbigniew Bodek #include <sys/cdefs.h> 31*3f51d888SZbigniew Bodek __FBSDID("$FreeBSD$"); 32*3f51d888SZbigniew Bodek 33*3f51d888SZbigniew Bodek #include <sys/param.h> 34*3f51d888SZbigniew Bodek #include <sys/systm.h> 35*3f51d888SZbigniew Bodek #include <sys/bus.h> 36*3f51d888SZbigniew Bodek #include <sys/kernel.h> 37*3f51d888SZbigniew Bodek #include <sys/module.h> 38*3f51d888SZbigniew Bodek #include <sys/resource.h> 39*3f51d888SZbigniew Bodek #include <sys/rman.h> 40*3f51d888SZbigniew Bodek #include <sys/socket.h> 41*3f51d888SZbigniew Bodek #include <sys/queue.h> 42*3f51d888SZbigniew Bodek 43*3f51d888SZbigniew Bodek #include <dev/ofw/ofw_bus.h> 44*3f51d888SZbigniew Bodek #include <dev/ofw/ofw_bus_subr.h> 45*3f51d888SZbigniew Bodek #include <dev/fdt/simplebus.h> 46*3f51d888SZbigniew Bodek 47*3f51d888SZbigniew Bodek #include <machine/bus.h> 48*3f51d888SZbigniew Bodek #include <machine/resource.h> 49*3f51d888SZbigniew Bodek 50*3f51d888SZbigniew Bodek static MALLOC_DEFINE(M_MRMLB, "MRML bridge", "Cavium MRML bridge"); 51*3f51d888SZbigniew Bodek 52*3f51d888SZbigniew Bodek static device_probe_t mrmlb_fdt_probe; 53*3f51d888SZbigniew Bodek static device_attach_t mrmlb_fdt_attach; 54*3f51d888SZbigniew Bodek 55*3f51d888SZbigniew Bodek static struct resource * mrmlb_ofw_bus_alloc_res(device_t, device_t, int, int *, 56*3f51d888SZbigniew Bodek rman_res_t, rman_res_t, rman_res_t, u_int); 57*3f51d888SZbigniew Bodek 58*3f51d888SZbigniew Bodek static const struct ofw_bus_devinfo * mrmlb_ofw_get_devinfo(device_t, device_t); 59*3f51d888SZbigniew Bodek 60*3f51d888SZbigniew Bodek static device_method_t mrmlbus_fdt_methods[] = { 61*3f51d888SZbigniew Bodek /* Device interface */ 62*3f51d888SZbigniew Bodek DEVMETHOD(device_probe, mrmlb_fdt_probe), 63*3f51d888SZbigniew Bodek DEVMETHOD(device_attach, mrmlb_fdt_attach), 64*3f51d888SZbigniew Bodek 65*3f51d888SZbigniew Bodek /* Bus interface */ 66*3f51d888SZbigniew Bodek DEVMETHOD(bus_alloc_resource, mrmlb_ofw_bus_alloc_res), 67*3f51d888SZbigniew Bodek DEVMETHOD(bus_release_resource, bus_generic_release_resource), 68*3f51d888SZbigniew Bodek DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 69*3f51d888SZbigniew Bodek 70*3f51d888SZbigniew Bodek /* ofw_bus interface */ 71*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_devinfo, mrmlb_ofw_get_devinfo), 72*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 73*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 74*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 75*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 76*3f51d888SZbigniew Bodek DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 77*3f51d888SZbigniew Bodek 78*3f51d888SZbigniew Bodek DEVMETHOD_END 79*3f51d888SZbigniew Bodek }; 80*3f51d888SZbigniew Bodek 81*3f51d888SZbigniew Bodek DEFINE_CLASS_0(mrmlbus, mrmlbus_fdt_driver, mrmlbus_fdt_methods, 82*3f51d888SZbigniew Bodek sizeof(struct simplebus_softc)); 83*3f51d888SZbigniew Bodek 84*3f51d888SZbigniew Bodek static devclass_t mrmlbus_fdt_devclass; 85*3f51d888SZbigniew Bodek 86*3f51d888SZbigniew Bodek EARLY_DRIVER_MODULE(mrmlbus, pcib, mrmlbus_fdt_driver, mrmlbus_fdt_devclass, 0, 0, 87*3f51d888SZbigniew Bodek BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 88*3f51d888SZbigniew Bodek 89*3f51d888SZbigniew Bodek static int mrmlb_ofw_fill_ranges(phandle_t, struct simplebus_softc *); 90*3f51d888SZbigniew Bodek static int mrmlb_ofw_bus_attach(device_t); 91*3f51d888SZbigniew Bodek 92*3f51d888SZbigniew Bodek static int 93*3f51d888SZbigniew Bodek mrmlb_fdt_probe(device_t dev) 94*3f51d888SZbigniew Bodek { 95*3f51d888SZbigniew Bodek 96*3f51d888SZbigniew Bodek if (!ofw_bus_status_okay(dev)) 97*3f51d888SZbigniew Bodek return (ENXIO); 98*3f51d888SZbigniew Bodek 99*3f51d888SZbigniew Bodek if (!ofw_bus_is_compatible(dev, "cavium,thunder-8890-mrml-bridge")) 100*3f51d888SZbigniew Bodek return (ENXIO); 101*3f51d888SZbigniew Bodek 102*3f51d888SZbigniew Bodek device_set_desc(dev, "Cavium ThunderX MRML bridge"); 103*3f51d888SZbigniew Bodek return (BUS_PROBE_SPECIFIC); 104*3f51d888SZbigniew Bodek } 105*3f51d888SZbigniew Bodek 106*3f51d888SZbigniew Bodek static int 107*3f51d888SZbigniew Bodek mrmlb_fdt_attach(device_t dev) 108*3f51d888SZbigniew Bodek { 109*3f51d888SZbigniew Bodek int err; 110*3f51d888SZbigniew Bodek 111*3f51d888SZbigniew Bodek err = mrmlb_ofw_bus_attach(dev); 112*3f51d888SZbigniew Bodek if (err != 0) 113*3f51d888SZbigniew Bodek return (err); 114*3f51d888SZbigniew Bodek 115*3f51d888SZbigniew Bodek return (bus_generic_attach(dev)); 116*3f51d888SZbigniew Bodek } 117*3f51d888SZbigniew Bodek 118*3f51d888SZbigniew Bodek /* OFW bus interface */ 119*3f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo { 120*3f51d888SZbigniew Bodek struct ofw_bus_devinfo di_dinfo; 121*3f51d888SZbigniew Bodek struct resource_list di_rl; 122*3f51d888SZbigniew Bodek }; 123*3f51d888SZbigniew Bodek 124*3f51d888SZbigniew Bodek static const struct ofw_bus_devinfo * 125*3f51d888SZbigniew Bodek mrmlb_ofw_get_devinfo(device_t bus __unused, device_t child) 126*3f51d888SZbigniew Bodek { 127*3f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 128*3f51d888SZbigniew Bodek 129*3f51d888SZbigniew Bodek di = device_get_ivars(child); 130*3f51d888SZbigniew Bodek return (&di->di_dinfo); 131*3f51d888SZbigniew Bodek } 132*3f51d888SZbigniew Bodek 133*3f51d888SZbigniew Bodek static struct resource * 134*3f51d888SZbigniew Bodek mrmlb_ofw_bus_alloc_res(device_t bus, device_t child, int type, int *rid, 135*3f51d888SZbigniew Bodek rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 136*3f51d888SZbigniew Bodek { 137*3f51d888SZbigniew Bodek struct simplebus_softc *sc; 138*3f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 139*3f51d888SZbigniew Bodek struct resource_list_entry *rle; 140*3f51d888SZbigniew Bodek int i; 141*3f51d888SZbigniew Bodek 142*3f51d888SZbigniew Bodek if ((start == 0UL) && (end == ~0UL)) { 143*3f51d888SZbigniew Bodek if ((di = device_get_ivars(child)) == NULL) 144*3f51d888SZbigniew Bodek return (NULL); 145*3f51d888SZbigniew Bodek if (type == SYS_RES_IOPORT) 146*3f51d888SZbigniew Bodek type = SYS_RES_MEMORY; 147*3f51d888SZbigniew Bodek 148*3f51d888SZbigniew Bodek /* Find defaults for this rid */ 149*3f51d888SZbigniew Bodek rle = resource_list_find(&di->di_rl, type, *rid); 150*3f51d888SZbigniew Bodek if (rle == NULL) 151*3f51d888SZbigniew Bodek return (NULL); 152*3f51d888SZbigniew Bodek 153*3f51d888SZbigniew Bodek start = rle->start; 154*3f51d888SZbigniew Bodek end = rle->end; 155*3f51d888SZbigniew Bodek count = rle->count; 156*3f51d888SZbigniew Bodek } 157*3f51d888SZbigniew Bodek 158*3f51d888SZbigniew Bodek sc = device_get_softc(bus); 159*3f51d888SZbigniew Bodek 160*3f51d888SZbigniew Bodek if (type == SYS_RES_MEMORY) { 161*3f51d888SZbigniew Bodek /* Remap through ranges property */ 162*3f51d888SZbigniew Bodek for (i = 0; i < sc->nranges; i++) { 163*3f51d888SZbigniew Bodek if (start >= sc->ranges[i].bus && end < 164*3f51d888SZbigniew Bodek sc->ranges[i].bus + sc->ranges[i].size) { 165*3f51d888SZbigniew Bodek start -= sc->ranges[i].bus; 166*3f51d888SZbigniew Bodek start += sc->ranges[i].host; 167*3f51d888SZbigniew Bodek end -= sc->ranges[i].bus; 168*3f51d888SZbigniew Bodek end += sc->ranges[i].host; 169*3f51d888SZbigniew Bodek break; 170*3f51d888SZbigniew Bodek } 171*3f51d888SZbigniew Bodek } 172*3f51d888SZbigniew Bodek 173*3f51d888SZbigniew Bodek if (i == sc->nranges && sc->nranges != 0) { 174*3f51d888SZbigniew Bodek device_printf(bus, "Could not map resource " 175*3f51d888SZbigniew Bodek "%#lx-%#lx\n", start, end); 176*3f51d888SZbigniew Bodek return (NULL); 177*3f51d888SZbigniew Bodek } 178*3f51d888SZbigniew Bodek } 179*3f51d888SZbigniew Bodek 180*3f51d888SZbigniew Bodek return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 181*3f51d888SZbigniew Bodek count, flags)); 182*3f51d888SZbigniew Bodek } 183*3f51d888SZbigniew Bodek 184*3f51d888SZbigniew Bodek /* Helper functions */ 185*3f51d888SZbigniew Bodek 186*3f51d888SZbigniew Bodek static int 187*3f51d888SZbigniew Bodek mrmlb_ofw_fill_ranges(phandle_t node, struct simplebus_softc *sc) 188*3f51d888SZbigniew Bodek { 189*3f51d888SZbigniew Bodek int host_address_cells; 190*3f51d888SZbigniew Bodek cell_t *base_ranges; 191*3f51d888SZbigniew Bodek ssize_t nbase_ranges; 192*3f51d888SZbigniew Bodek int err; 193*3f51d888SZbigniew Bodek int i, j, k; 194*3f51d888SZbigniew Bodek 195*3f51d888SZbigniew Bodek err = OF_searchencprop(OF_parent(node), "#address-cells", 196*3f51d888SZbigniew Bodek &host_address_cells, sizeof(host_address_cells)); 197*3f51d888SZbigniew Bodek if (err <= 0) 198*3f51d888SZbigniew Bodek return (-1); 199*3f51d888SZbigniew Bodek 200*3f51d888SZbigniew Bodek nbase_ranges = OF_getproplen(node, "ranges"); 201*3f51d888SZbigniew Bodek if (nbase_ranges < 0) 202*3f51d888SZbigniew Bodek return (-1); 203*3f51d888SZbigniew Bodek sc->nranges = nbase_ranges / sizeof(cell_t) / 204*3f51d888SZbigniew Bodek (sc->acells + host_address_cells + sc->scells); 205*3f51d888SZbigniew Bodek if (sc->nranges == 0) 206*3f51d888SZbigniew Bodek return (0); 207*3f51d888SZbigniew Bodek 208*3f51d888SZbigniew Bodek sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), 209*3f51d888SZbigniew Bodek M_MRMLB, M_WAITOK); 210*3f51d888SZbigniew Bodek base_ranges = malloc(nbase_ranges, M_MRMLB, M_WAITOK); 211*3f51d888SZbigniew Bodek OF_getencprop(node, "ranges", base_ranges, nbase_ranges); 212*3f51d888SZbigniew Bodek 213*3f51d888SZbigniew Bodek for (i = 0, j = 0; i < sc->nranges; i++) { 214*3f51d888SZbigniew Bodek sc->ranges[i].bus = 0; 215*3f51d888SZbigniew Bodek for (k = 0; k < sc->acells; k++) { 216*3f51d888SZbigniew Bodek sc->ranges[i].bus <<= 32; 217*3f51d888SZbigniew Bodek sc->ranges[i].bus |= base_ranges[j++]; 218*3f51d888SZbigniew Bodek } 219*3f51d888SZbigniew Bodek sc->ranges[i].host = 0; 220*3f51d888SZbigniew Bodek for (k = 0; k < host_address_cells; k++) { 221*3f51d888SZbigniew Bodek sc->ranges[i].host <<= 32; 222*3f51d888SZbigniew Bodek sc->ranges[i].host |= base_ranges[j++]; 223*3f51d888SZbigniew Bodek } 224*3f51d888SZbigniew Bodek sc->ranges[i].size = 0; 225*3f51d888SZbigniew Bodek for (k = 0; k < sc->scells; k++) { 226*3f51d888SZbigniew Bodek sc->ranges[i].size <<= 32; 227*3f51d888SZbigniew Bodek sc->ranges[i].size |= base_ranges[j++]; 228*3f51d888SZbigniew Bodek } 229*3f51d888SZbigniew Bodek } 230*3f51d888SZbigniew Bodek 231*3f51d888SZbigniew Bodek free(base_ranges, M_MRMLB); 232*3f51d888SZbigniew Bodek return (sc->nranges); 233*3f51d888SZbigniew Bodek } 234*3f51d888SZbigniew Bodek 235*3f51d888SZbigniew Bodek static int 236*3f51d888SZbigniew Bodek mrmlb_ofw_bus_attach(device_t dev) 237*3f51d888SZbigniew Bodek { 238*3f51d888SZbigniew Bodek struct simplebus_softc *sc; 239*3f51d888SZbigniew Bodek struct mrmlb_ofw_devinfo *di; 240*3f51d888SZbigniew Bodek device_t child; 241*3f51d888SZbigniew Bodek phandle_t parent, node; 242*3f51d888SZbigniew Bodek 243*3f51d888SZbigniew Bodek parent = ofw_bus_get_node(dev); 244*3f51d888SZbigniew Bodek simplebus_init(dev, parent); 245*3f51d888SZbigniew Bodek 246*3f51d888SZbigniew Bodek sc = device_get_softc(dev); 247*3f51d888SZbigniew Bodek 248*3f51d888SZbigniew Bodek if (mrmlb_ofw_fill_ranges(parent, sc) < 0) { 249*3f51d888SZbigniew Bodek device_printf(dev, "could not get ranges\n"); 250*3f51d888SZbigniew Bodek return (ENXIO); 251*3f51d888SZbigniew Bodek } 252*3f51d888SZbigniew Bodek /* Iterate through all bus subordinates */ 253*3f51d888SZbigniew Bodek for (node = OF_child(parent); node > 0; node = OF_peer(node)) { 254*3f51d888SZbigniew Bodek /* Allocate and populate devinfo. */ 255*3f51d888SZbigniew Bodek di = malloc(sizeof(*di), M_MRMLB, M_WAITOK | M_ZERO); 256*3f51d888SZbigniew Bodek if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node) != 0) { 257*3f51d888SZbigniew Bodek free(di, M_MRMLB); 258*3f51d888SZbigniew Bodek continue; 259*3f51d888SZbigniew Bodek } 260*3f51d888SZbigniew Bodek 261*3f51d888SZbigniew Bodek /* Initialize and populate resource list. */ 262*3f51d888SZbigniew Bodek resource_list_init(&di->di_rl); 263*3f51d888SZbigniew Bodek ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, 264*3f51d888SZbigniew Bodek &di->di_rl); 265*3f51d888SZbigniew Bodek ofw_bus_intr_to_rl(dev, node, &di->di_rl, NULL); 266*3f51d888SZbigniew Bodek 267*3f51d888SZbigniew Bodek /* Add newbus device for this FDT node */ 268*3f51d888SZbigniew Bodek child = device_add_child(dev, NULL, -1); 269*3f51d888SZbigniew Bodek if (child == NULL) { 270*3f51d888SZbigniew Bodek resource_list_free(&di->di_rl); 271*3f51d888SZbigniew Bodek ofw_bus_gen_destroy_devinfo(&di->di_dinfo); 272*3f51d888SZbigniew Bodek free(di, M_MRMLB); 273*3f51d888SZbigniew Bodek continue; 274*3f51d888SZbigniew Bodek } 275*3f51d888SZbigniew Bodek 276*3f51d888SZbigniew Bodek device_set_ivars(child, di); 277*3f51d888SZbigniew Bodek } 278*3f51d888SZbigniew Bodek 279*3f51d888SZbigniew Bodek return (0); 280*3f51d888SZbigniew Bodek } 281