1282867Szbb/*- 2282867Szbb * Copyright (c) 2015 The FreeBSD Foundation 3282867Szbb * All rights reserved. 4282867Szbb * 5282867Szbb * This software was developed by Semihalf under 6282867Szbb * the sponsorship of the FreeBSD Foundation. 7282867Szbb * 8282867Szbb * Redistribution and use in source and binary forms, with or without 9282867Szbb * modification, are permitted provided that the following conditions 10282867Szbb * are met: 11282867Szbb * 1. Redistributions of source code must retain the above copyright 12282867Szbb * notice, this list of conditions and the following disclaimer. 13282867Szbb * 2. Redistributions in binary form must reproduce the above copyright 14282867Szbb * notice, this list of conditions and the following disclaimer in the 15282867Szbb * documentation and/or other materials provided with the distribution. 16282867Szbb * 17282867Szbb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18282867Szbb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19282867Szbb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20282867Szbb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21282867Szbb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22282867Szbb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23282867Szbb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24282867Szbb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25282867Szbb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26282867Szbb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27282867Szbb * SUCH DAMAGE. 28282867Szbb */ 29282867Szbb 30282867Szbb#include <sys/cdefs.h> 31282867Szbb__FBSDID("$FreeBSD$"); 32282867Szbb 33282867Szbb#include <sys/param.h> 34294572Sandrew#include <sys/systm.h> 35299124Szbb#include <sys/bitstring.h> 36282867Szbb#include <sys/bus.h> 37282867Szbb#include <sys/kernel.h> 38282867Szbb#include <sys/module.h> 39295832Sjhibbits#include <sys/rman.h> 40282867Szbb 41299944Sandrew#include <machine/intr.h> 42285213Szbb#include <machine/resource.h> 43285213Szbb 44282867Szbb#include <dev/ofw/openfirm.h> 45282867Szbb#include <dev/ofw/ofw_bus.h> 46282867Szbb#include <dev/ofw/ofw_bus_subr.h> 47282867Szbb 48282867Szbb#include "gic_v3_reg.h" 49282867Szbb#include "gic_v3_var.h" 50282867Szbb 51282867Szbb/* 52282867Szbb * FDT glue. 53282867Szbb */ 54282867Szbbstatic int gic_v3_fdt_probe(device_t); 55282867Szbbstatic int gic_v3_fdt_attach(device_t); 56305529Sandrewstatic int gic_v3_fdt_print_child(device_t, device_t); 57282867Szbb 58285213Szbbstatic struct resource *gic_v3_ofw_bus_alloc_res(device_t, device_t, int, int *, 59294883Sjhibbits rman_res_t, rman_res_t, rman_res_t, u_int); 60285213Szbbstatic const struct ofw_bus_devinfo *gic_v3_ofw_get_devinfo(device_t, device_t); 61285213Szbb 62282867Szbbstatic device_method_t gic_v3_fdt_methods[] = { 63282867Szbb /* Device interface */ 64282867Szbb DEVMETHOD(device_probe, gic_v3_fdt_probe), 65282867Szbb DEVMETHOD(device_attach, gic_v3_fdt_attach), 66282867Szbb 67285213Szbb /* Bus interface */ 68305529Sandrew DEVMETHOD(bus_print_child, gic_v3_fdt_print_child), 69285213Szbb DEVMETHOD(bus_alloc_resource, gic_v3_ofw_bus_alloc_res), 70285213Szbb DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 71285213Szbb 72285213Szbb /* ofw_bus interface */ 73285213Szbb DEVMETHOD(ofw_bus_get_devinfo, gic_v3_ofw_get_devinfo), 74285213Szbb DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 75285213Szbb DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 76285213Szbb DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 77285213Szbb DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 78285213Szbb DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 79285213Szbb 80282867Szbb /* End */ 81282867Szbb DEVMETHOD_END 82282867Szbb}; 83282867Szbb 84294731SzbbDEFINE_CLASS_1(gic, gic_v3_fdt_driver, gic_v3_fdt_methods, 85282867Szbb sizeof(struct gic_v3_softc), gic_v3_driver); 86282867Szbb 87282867Szbbstatic devclass_t gic_v3_fdt_devclass; 88282867Szbb 89282867SzbbEARLY_DRIVER_MODULE(gic_v3, simplebus, gic_v3_fdt_driver, gic_v3_fdt_devclass, 90282867Szbb 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 91282867SzbbEARLY_DRIVER_MODULE(gic_v3, ofwbus, gic_v3_fdt_driver, gic_v3_fdt_devclass, 92282867Szbb 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 93282867Szbb 94282867Szbb/* 95285213Szbb * Helper functions declarations. 96285213Szbb */ 97285213Szbbstatic int gic_v3_ofw_bus_attach(device_t); 98285213Szbb 99285213Szbb/* 100282867Szbb * Device interface. 101282867Szbb */ 102282867Szbbstatic int 103282867Szbbgic_v3_fdt_probe(device_t dev) 104282867Szbb{ 105282867Szbb 106282867Szbb if (!ofw_bus_status_okay(dev)) 107282867Szbb return (ENXIO); 108282867Szbb 109282867Szbb if (!ofw_bus_is_compatible(dev, "arm,gic-v3")) 110282867Szbb return (ENXIO); 111282867Szbb 112282867Szbb device_set_desc(dev, GIC_V3_DEVSTR); 113282867Szbb return (BUS_PROBE_DEFAULT); 114282867Szbb} 115282867Szbb 116282867Szbbstatic int 117282867Szbbgic_v3_fdt_attach(device_t dev) 118282867Szbb{ 119282867Szbb struct gic_v3_softc *sc; 120282867Szbb pcell_t redist_regions; 121299944Sandrew intptr_t xref; 122282867Szbb int err; 123282867Szbb 124282867Szbb sc = device_get_softc(dev); 125282867Szbb sc->dev = dev; 126282867Szbb 127282867Szbb /* 128282867Szbb * Recover number of the Re-Distributor regions. 129282867Szbb */ 130282867Szbb if (OF_getencprop(ofw_bus_get_node(dev), "#redistributor-regions", 131282867Szbb &redist_regions, sizeof(redist_regions)) <= 0) 132282867Szbb sc->gic_redists.nregions = 1; 133282867Szbb else 134282867Szbb sc->gic_redists.nregions = redist_regions; 135282867Szbb 136282867Szbb err = gic_v3_attach(dev); 137299944Sandrew if (err != 0) 138282867Szbb goto error; 139299944Sandrew 140299944Sandrew xref = OF_xref_from_node(ofw_bus_get_node(dev)); 141301265Sandrew sc->gic_pic = intr_pic_register(dev, xref); 142301265Sandrew if (sc->gic_pic == NULL) { 143299944Sandrew device_printf(dev, "could not register PIC\n"); 144301112Szbb err = ENXIO; 145299944Sandrew goto error; 146299944Sandrew } 147299944Sandrew 148299944Sandrew if (intr_pic_claim_root(dev, xref, arm_gic_v3_intr, sc, 149299944Sandrew GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 150301112Szbb err = ENXIO; 151299944Sandrew goto error; 152299944Sandrew } 153299944Sandrew 154285213Szbb /* 155285213Szbb * Try to register ITS to this GIC. 156285213Szbb * GIC will act as a bus in that case. 157285213Szbb * Failure here will not affect main GIC functionality. 158285213Szbb */ 159285213Szbb if (gic_v3_ofw_bus_attach(dev) != 0) { 160285213Szbb if (bootverbose) { 161285213Szbb device_printf(dev, 162285213Szbb "Failed to attach ITS to this GIC\n"); 163285213Szbb } 164285213Szbb } 165282867Szbb 166301265Sandrew if (device_get_children(dev, &sc->gic_children, &sc->gic_nchildren) != 0) 167301265Sandrew sc->gic_nchildren = 0; 168301265Sandrew 169282867Szbb return (err); 170282867Szbb 171282867Szbberror: 172282867Szbb if (bootverbose) { 173282867Szbb device_printf(dev, 174282867Szbb "Failed to attach. Error %d\n", err); 175282867Szbb } 176282867Szbb /* Failure so free resources */ 177282867Szbb gic_v3_detach(dev); 178282867Szbb 179301112Szbb return (err); 180282867Szbb} 181285213Szbb 182285213Szbb/* OFW bus interface */ 183285213Szbbstruct gic_v3_ofw_devinfo { 184285213Szbb struct ofw_bus_devinfo di_dinfo; 185285213Szbb struct resource_list di_rl; 186285213Szbb}; 187285213Szbb 188305529Sandrewstatic int 189305529Sandrewgic_v3_fdt_print_child(device_t bus, device_t child) 190305529Sandrew{ 191305529Sandrew struct gic_v3_ofw_devinfo *di = device_get_ivars(child); 192305529Sandrew struct resource_list *rl = &di->di_rl; 193305529Sandrew int retval = 0; 194305529Sandrew 195305529Sandrew retval += bus_print_child_header(bus, child); 196305529Sandrew retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#jx"); 197305529Sandrew retval += bus_print_child_footer(bus, child); 198305529Sandrew 199305529Sandrew return (retval); 200305529Sandrew} 201305529Sandrew 202285213Szbbstatic const struct ofw_bus_devinfo * 203285213Szbbgic_v3_ofw_get_devinfo(device_t bus __unused, device_t child) 204285213Szbb{ 205285213Szbb struct gic_v3_ofw_devinfo *di; 206285213Szbb 207285213Szbb di = device_get_ivars(child); 208285213Szbb return (&di->di_dinfo); 209285213Szbb} 210285213Szbb 211285213Szbbstatic struct resource * 212285213Szbbgic_v3_ofw_bus_alloc_res(device_t bus, device_t child, int type, int *rid, 213294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 214285213Szbb{ 215285213Szbb struct gic_v3_ofw_devinfo *di; 216285213Szbb struct resource_list_entry *rle; 217285213Szbb int ranges_len; 218285213Szbb 219295832Sjhibbits if (RMAN_IS_DEFAULT_RANGE(start, end)) { 220285213Szbb if ((di = device_get_ivars(child)) == NULL) 221285213Szbb return (NULL); 222285213Szbb if (type != SYS_RES_MEMORY) 223285213Szbb return (NULL); 224285213Szbb 225285213Szbb /* Find defaults for this rid */ 226285213Szbb rle = resource_list_find(&di->di_rl, type, *rid); 227285213Szbb if (rle == NULL) 228285213Szbb return (NULL); 229285213Szbb 230285213Szbb start = rle->start; 231285213Szbb end = rle->end; 232285213Szbb count = rle->count; 233285213Szbb } 234285213Szbb /* 235285213Szbb * XXX: No ranges remap! 236285213Szbb * Absolute address is expected. 237285213Szbb */ 238285213Szbb if (ofw_bus_has_prop(bus, "ranges")) { 239285213Szbb ranges_len = OF_getproplen(ofw_bus_get_node(bus), "ranges"); 240285213Szbb if (ranges_len != 0) { 241285213Szbb if (bootverbose) { 242285213Szbb device_printf(child, 243285213Szbb "Ranges remap not supported\n"); 244285213Szbb } 245285213Szbb return (NULL); 246285213Szbb } 247285213Szbb } 248285213Szbb return (bus_generic_alloc_resource(bus, child, type, rid, start, end, 249285213Szbb count, flags)); 250285213Szbb} 251285213Szbb 252285213Szbb/* Helper functions */ 253285213Szbb 254285213Szbb/* 255285213Szbb * Bus capability support for GICv3. 256285213Szbb * Collects and configures device informations and finally 257285213Szbb * adds ITS device as a child of GICv3 in Newbus hierarchy. 258285213Szbb */ 259285213Szbbstatic int 260285213Szbbgic_v3_ofw_bus_attach(device_t dev) 261285213Szbb{ 262285213Szbb struct gic_v3_ofw_devinfo *di; 263285213Szbb device_t child; 264285213Szbb phandle_t parent, node; 265285213Szbb pcell_t addr_cells, size_cells; 266285213Szbb 267285213Szbb parent = ofw_bus_get_node(dev); 268285213Szbb if (parent > 0) { 269285213Szbb addr_cells = 2; 270285213Szbb OF_getencprop(parent, "#address-cells", &addr_cells, 271285213Szbb sizeof(addr_cells)); 272285213Szbb size_cells = 2; 273285213Szbb OF_getencprop(parent, "#size-cells", &size_cells, 274285213Szbb sizeof(size_cells)); 275285213Szbb /* Iterate through all GIC subordinates */ 276285213Szbb for (node = OF_child(parent); node > 0; node = OF_peer(node)) { 277285213Szbb /* Allocate and populate devinfo. */ 278285213Szbb di = malloc(sizeof(*di), M_GIC_V3, M_WAITOK | M_ZERO); 279285213Szbb if (ofw_bus_gen_setup_devinfo(&di->di_dinfo, node)) { 280285213Szbb if (bootverbose) { 281285213Szbb device_printf(dev, 282285213Szbb "Could not set up devinfo for ITS\n"); 283285213Szbb } 284285213Szbb free(di, M_GIC_V3); 285285213Szbb continue; 286285213Szbb } 287285213Szbb 288285213Szbb /* Initialize and populate resource list. */ 289285213Szbb resource_list_init(&di->di_rl); 290285213Szbb ofw_bus_reg_to_rl(dev, node, addr_cells, size_cells, 291285213Szbb &di->di_rl); 292285213Szbb 293285213Szbb /* Should not have any interrupts, so don't add any */ 294285213Szbb 295285213Szbb /* Add newbus device for this FDT node */ 296285213Szbb child = device_add_child(dev, NULL, -1); 297285213Szbb if (!child) { 298285213Szbb if (bootverbose) { 299285213Szbb device_printf(dev, 300285213Szbb "Could not add child: %s\n", 301285213Szbb di->di_dinfo.obd_name); 302285213Szbb } 303285213Szbb resource_list_free(&di->di_rl); 304285213Szbb ofw_bus_gen_destroy_devinfo(&di->di_dinfo); 305285213Szbb free(di, M_GIC_V3); 306285213Szbb continue; 307285213Szbb } 308285213Szbb 309285213Szbb device_set_ivars(child, di); 310285213Szbb } 311285213Szbb } 312285213Szbb 313285213Szbb return (bus_generic_attach(dev)); 314285213Szbb} 315