1*ca2c1931SNathan Whitehorn /*- 2*ca2c1931SNathan Whitehorn * Copyright (C) 2002 Benno Rice. 3*ca2c1931SNathan Whitehorn * All rights reserved. 4*ca2c1931SNathan Whitehorn * 5*ca2c1931SNathan Whitehorn * Redistribution and use in source and binary forms, with or without 6*ca2c1931SNathan Whitehorn * modification, are permitted provided that the following conditions 7*ca2c1931SNathan Whitehorn * are met: 8*ca2c1931SNathan Whitehorn * 1. Redistributions of source code must retain the above copyright 9*ca2c1931SNathan Whitehorn * notice, this list of conditions and the following disclaimer. 10*ca2c1931SNathan Whitehorn * 2. Redistributions in binary form must reproduce the above copyright 11*ca2c1931SNathan Whitehorn * notice, this list of conditions and the following disclaimer in the 12*ca2c1931SNathan Whitehorn * documentation and/or other materials provided with the distribution. 13*ca2c1931SNathan Whitehorn * 14*ca2c1931SNathan Whitehorn * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15*ca2c1931SNathan Whitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16*ca2c1931SNathan Whitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17*ca2c1931SNathan Whitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18*ca2c1931SNathan Whitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19*ca2c1931SNathan Whitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20*ca2c1931SNathan Whitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21*ca2c1931SNathan Whitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22*ca2c1931SNathan Whitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23*ca2c1931SNathan Whitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24*ca2c1931SNathan Whitehorn * 25*ca2c1931SNathan Whitehorn * $FreeBSD$ 26*ca2c1931SNathan Whitehorn */ 27*ca2c1931SNathan Whitehorn 28*ca2c1931SNathan Whitehorn #include <sys/param.h> 29*ca2c1931SNathan Whitehorn #include <sys/systm.h> 30*ca2c1931SNathan Whitehorn #include <sys/module.h> 31*ca2c1931SNathan Whitehorn #include <sys/bus.h> 32*ca2c1931SNathan Whitehorn #include <sys/conf.h> 33*ca2c1931SNathan Whitehorn #include <sys/kernel.h> 34*ca2c1931SNathan Whitehorn 35*ca2c1931SNathan Whitehorn #include <dev/ofw/openfirm.h> 36*ca2c1931SNathan Whitehorn #include <dev/ofw/ofw_pci.h> 37*ca2c1931SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 38*ca2c1931SNathan Whitehorn #include <dev/ofw/ofw_bus_subr.h> 39*ca2c1931SNathan Whitehorn 40*ca2c1931SNathan Whitehorn #include <dev/pci/pcivar.h> 41*ca2c1931SNathan Whitehorn #include <dev/pci/pcireg.h> 42*ca2c1931SNathan Whitehorn 43*ca2c1931SNathan Whitehorn #include <machine/bus.h> 44*ca2c1931SNathan Whitehorn #include <machine/intr_machdep.h> 45*ca2c1931SNathan Whitehorn #include <machine/md_var.h> 46*ca2c1931SNathan Whitehorn #include <machine/pio.h> 47*ca2c1931SNathan Whitehorn #include <machine/resource.h> 48*ca2c1931SNathan Whitehorn 49*ca2c1931SNathan Whitehorn #include <sys/rman.h> 50*ca2c1931SNathan Whitehorn 51*ca2c1931SNathan Whitehorn #include <powerpc/powermac/uninorthvar.h> 52*ca2c1931SNathan Whitehorn 53*ca2c1931SNathan Whitehorn #include <vm/vm.h> 54*ca2c1931SNathan Whitehorn #include <vm/pmap.h> 55*ca2c1931SNathan Whitehorn 56*ca2c1931SNathan Whitehorn #include "pcib_if.h" 57*ca2c1931SNathan Whitehorn 58*ca2c1931SNathan Whitehorn #define UNINORTH_DEBUG 0 59*ca2c1931SNathan Whitehorn 60*ca2c1931SNathan Whitehorn /* 61*ca2c1931SNathan Whitehorn * Device interface. 62*ca2c1931SNathan Whitehorn */ 63*ca2c1931SNathan Whitehorn static int uninorth_probe(device_t); 64*ca2c1931SNathan Whitehorn static int uninorth_attach(device_t); 65*ca2c1931SNathan Whitehorn 66*ca2c1931SNathan Whitehorn /* 67*ca2c1931SNathan Whitehorn * Bus interface. 68*ca2c1931SNathan Whitehorn */ 69*ca2c1931SNathan Whitehorn static int uninorth_read_ivar(device_t, device_t, int, 70*ca2c1931SNathan Whitehorn uintptr_t *); 71*ca2c1931SNathan Whitehorn static struct resource * uninorth_alloc_resource(device_t bus, 72*ca2c1931SNathan Whitehorn device_t child, int type, int *rid, u_long start, 73*ca2c1931SNathan Whitehorn u_long end, u_long count, u_int flags); 74*ca2c1931SNathan Whitehorn static int uninorth_activate_resource(device_t bus, device_t child, 75*ca2c1931SNathan Whitehorn int type, int rid, struct resource *res); 76*ca2c1931SNathan Whitehorn 77*ca2c1931SNathan Whitehorn /* 78*ca2c1931SNathan Whitehorn * pcib interface. 79*ca2c1931SNathan Whitehorn */ 80*ca2c1931SNathan Whitehorn static int uninorth_maxslots(device_t); 81*ca2c1931SNathan Whitehorn static u_int32_t uninorth_read_config(device_t, u_int, u_int, u_int, 82*ca2c1931SNathan Whitehorn u_int, int); 83*ca2c1931SNathan Whitehorn static void uninorth_write_config(device_t, u_int, u_int, u_int, 84*ca2c1931SNathan Whitehorn u_int, u_int32_t, int); 85*ca2c1931SNathan Whitehorn static int uninorth_route_interrupt(device_t, device_t, int); 86*ca2c1931SNathan Whitehorn 87*ca2c1931SNathan Whitehorn /* 88*ca2c1931SNathan Whitehorn * OFW Bus interface 89*ca2c1931SNathan Whitehorn */ 90*ca2c1931SNathan Whitehorn 91*ca2c1931SNathan Whitehorn static phandle_t uninorth_get_node(device_t bus, device_t dev); 92*ca2c1931SNathan Whitehorn 93*ca2c1931SNathan Whitehorn /* 94*ca2c1931SNathan Whitehorn * Local routines. 95*ca2c1931SNathan Whitehorn */ 96*ca2c1931SNathan Whitehorn static int uninorth_enable_config(struct uninorth_softc *, u_int, 97*ca2c1931SNathan Whitehorn u_int, u_int, u_int); 98*ca2c1931SNathan Whitehorn 99*ca2c1931SNathan Whitehorn /* 100*ca2c1931SNathan Whitehorn * Driver methods. 101*ca2c1931SNathan Whitehorn */ 102*ca2c1931SNathan Whitehorn static device_method_t uninorth_methods[] = { 103*ca2c1931SNathan Whitehorn /* Device interface */ 104*ca2c1931SNathan Whitehorn DEVMETHOD(device_probe, uninorth_probe), 105*ca2c1931SNathan Whitehorn DEVMETHOD(device_attach, uninorth_attach), 106*ca2c1931SNathan Whitehorn 107*ca2c1931SNathan Whitehorn /* Bus interface */ 108*ca2c1931SNathan Whitehorn DEVMETHOD(bus_print_child, bus_generic_print_child), 109*ca2c1931SNathan Whitehorn DEVMETHOD(bus_read_ivar, uninorth_read_ivar), 110*ca2c1931SNathan Whitehorn DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 111*ca2c1931SNathan Whitehorn DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 112*ca2c1931SNathan Whitehorn DEVMETHOD(bus_alloc_resource, uninorth_alloc_resource), 113*ca2c1931SNathan Whitehorn DEVMETHOD(bus_activate_resource, uninorth_activate_resource), 114*ca2c1931SNathan Whitehorn 115*ca2c1931SNathan Whitehorn /* pcib interface */ 116*ca2c1931SNathan Whitehorn DEVMETHOD(pcib_maxslots, uninorth_maxslots), 117*ca2c1931SNathan Whitehorn DEVMETHOD(pcib_read_config, uninorth_read_config), 118*ca2c1931SNathan Whitehorn DEVMETHOD(pcib_write_config, uninorth_write_config), 119*ca2c1931SNathan Whitehorn DEVMETHOD(pcib_route_interrupt, uninorth_route_interrupt), 120*ca2c1931SNathan Whitehorn 121*ca2c1931SNathan Whitehorn /* ofw_bus interface */ 122*ca2c1931SNathan Whitehorn DEVMETHOD(ofw_bus_get_node, uninorth_get_node), 123*ca2c1931SNathan Whitehorn 124*ca2c1931SNathan Whitehorn { 0, 0 } 125*ca2c1931SNathan Whitehorn }; 126*ca2c1931SNathan Whitehorn 127*ca2c1931SNathan Whitehorn static driver_t uninorth_driver = { 128*ca2c1931SNathan Whitehorn "pcib", 129*ca2c1931SNathan Whitehorn uninorth_methods, 130*ca2c1931SNathan Whitehorn sizeof(struct uninorth_softc) 131*ca2c1931SNathan Whitehorn }; 132*ca2c1931SNathan Whitehorn 133*ca2c1931SNathan Whitehorn static devclass_t uninorth_devclass; 134*ca2c1931SNathan Whitehorn 135*ca2c1931SNathan Whitehorn DRIVER_MODULE(uninorth, nexus, uninorth_driver, uninorth_devclass, 0, 0); 136*ca2c1931SNathan Whitehorn 137*ca2c1931SNathan Whitehorn static int 138*ca2c1931SNathan Whitehorn uninorth_probe(device_t dev) 139*ca2c1931SNathan Whitehorn { 140*ca2c1931SNathan Whitehorn const char *type, *compatible; 141*ca2c1931SNathan Whitehorn 142*ca2c1931SNathan Whitehorn type = ofw_bus_get_type(dev); 143*ca2c1931SNathan Whitehorn compatible = ofw_bus_get_compat(dev); 144*ca2c1931SNathan Whitehorn 145*ca2c1931SNathan Whitehorn if (type == NULL || compatible == NULL) 146*ca2c1931SNathan Whitehorn return (ENXIO); 147*ca2c1931SNathan Whitehorn 148*ca2c1931SNathan Whitehorn if (strcmp(type, "pci") != 0) 149*ca2c1931SNathan Whitehorn return (ENXIO); 150*ca2c1931SNathan Whitehorn 151*ca2c1931SNathan Whitehorn if (strcmp(compatible, "uni-north") == 0) { 152*ca2c1931SNathan Whitehorn device_set_desc(dev, "Apple UniNorth Host-PCI bridge"); 153*ca2c1931SNathan Whitehorn return (0); 154*ca2c1931SNathan Whitehorn } else if (strcmp(compatible, "u3-agp") == 0) { 155*ca2c1931SNathan Whitehorn device_set_desc(dev, "Apple U3 Host-AGP bridge"); 156*ca2c1931SNathan Whitehorn return (0); 157*ca2c1931SNathan Whitehorn } else if (strcmp(compatible, "u4-pcie") == 0) { 158*ca2c1931SNathan Whitehorn device_set_desc(dev, "IBM CPC945 PCI Express Root"); 159*ca2c1931SNathan Whitehorn return (0); 160*ca2c1931SNathan Whitehorn } 161*ca2c1931SNathan Whitehorn 162*ca2c1931SNathan Whitehorn return (ENXIO); 163*ca2c1931SNathan Whitehorn } 164*ca2c1931SNathan Whitehorn 165*ca2c1931SNathan Whitehorn static int 166*ca2c1931SNathan Whitehorn uninorth_attach(device_t dev) 167*ca2c1931SNathan Whitehorn { 168*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 169*ca2c1931SNathan Whitehorn const char *compatible; 170*ca2c1931SNathan Whitehorn phandle_t node; 171*ca2c1931SNathan Whitehorn u_int32_t reg[3], busrange[2]; 172*ca2c1931SNathan Whitehorn struct uninorth_range *rp, *io, *mem[2]; 173*ca2c1931SNathan Whitehorn int nmem, i, error; 174*ca2c1931SNathan Whitehorn 175*ca2c1931SNathan Whitehorn node = ofw_bus_get_node(dev); 176*ca2c1931SNathan Whitehorn sc = device_get_softc(dev); 177*ca2c1931SNathan Whitehorn 178*ca2c1931SNathan Whitehorn if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 179*ca2c1931SNathan Whitehorn return (ENXIO); 180*ca2c1931SNathan Whitehorn 181*ca2c1931SNathan Whitehorn if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8) 182*ca2c1931SNathan Whitehorn return (ENXIO); 183*ca2c1931SNathan Whitehorn 184*ca2c1931SNathan Whitehorn sc->sc_ver = 0; 185*ca2c1931SNathan Whitehorn compatible = ofw_bus_get_compat(dev); 186*ca2c1931SNathan Whitehorn if (strcmp(compatible, "u3-agp") == 0) 187*ca2c1931SNathan Whitehorn sc->sc_ver = 3; 188*ca2c1931SNathan Whitehorn if (strcmp(compatible, "u4-pcie") == 0) 189*ca2c1931SNathan Whitehorn sc->sc_ver = 4; 190*ca2c1931SNathan Whitehorn 191*ca2c1931SNathan Whitehorn sc->sc_dev = dev; 192*ca2c1931SNathan Whitehorn sc->sc_node = node; 193*ca2c1931SNathan Whitehorn if (sc->sc_ver >= 3) { 194*ca2c1931SNathan Whitehorn sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[1] + 0x800000, PAGE_SIZE); 195*ca2c1931SNathan Whitehorn sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1] + 0xc00000, PAGE_SIZE); 196*ca2c1931SNathan Whitehorn } else { 197*ca2c1931SNathan Whitehorn sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[0] + 0x800000, PAGE_SIZE); 198*ca2c1931SNathan Whitehorn sc->sc_data = (vm_offset_t)pmap_mapdev(reg[0] + 0xc00000, PAGE_SIZE); 199*ca2c1931SNathan Whitehorn } 200*ca2c1931SNathan Whitehorn sc->sc_bus = busrange[0]; 201*ca2c1931SNathan Whitehorn 202*ca2c1931SNathan Whitehorn bzero(sc->sc_range, sizeof(sc->sc_range)); 203*ca2c1931SNathan Whitehorn if (sc->sc_ver >= 3) { 204*ca2c1931SNathan Whitehorn /* 205*ca2c1931SNathan Whitehorn * On Apple U3 systems, we have an otherwise standard 206*ca2c1931SNathan Whitehorn * Uninorth controller driving AGP. The one difference 207*ca2c1931SNathan Whitehorn * is that it uses a new PCI ranges format, so do the 208*ca2c1931SNathan Whitehorn * translation. 209*ca2c1931SNathan Whitehorn */ 210*ca2c1931SNathan Whitehorn 211*ca2c1931SNathan Whitehorn struct uninorth_range64 range64[6]; 212*ca2c1931SNathan Whitehorn bzero(range64, sizeof(range64)); 213*ca2c1931SNathan Whitehorn 214*ca2c1931SNathan Whitehorn sc->sc_nrange = OF_getprop(node, "ranges", range64, 215*ca2c1931SNathan Whitehorn sizeof(range64)); 216*ca2c1931SNathan Whitehorn for (i = 0; range64[i].pci_hi != 0; i++) { 217*ca2c1931SNathan Whitehorn sc->sc_range[i].pci_hi = range64[i].pci_hi; 218*ca2c1931SNathan Whitehorn sc->sc_range[i].pci_mid = range64[i].pci_mid; 219*ca2c1931SNathan Whitehorn sc->sc_range[i].pci_lo = range64[i].pci_lo; 220*ca2c1931SNathan Whitehorn sc->sc_range[i].host = range64[i].host_lo; 221*ca2c1931SNathan Whitehorn sc->sc_range[i].size_hi = range64[i].size_hi; 222*ca2c1931SNathan Whitehorn sc->sc_range[i].size_lo = range64[i].size_lo; 223*ca2c1931SNathan Whitehorn } 224*ca2c1931SNathan Whitehorn } else { 225*ca2c1931SNathan Whitehorn sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range, 226*ca2c1931SNathan Whitehorn sizeof(sc->sc_range)); 227*ca2c1931SNathan Whitehorn } 228*ca2c1931SNathan Whitehorn 229*ca2c1931SNathan Whitehorn if (sc->sc_nrange == -1) { 230*ca2c1931SNathan Whitehorn device_printf(dev, "could not get ranges\n"); 231*ca2c1931SNathan Whitehorn return (ENXIO); 232*ca2c1931SNathan Whitehorn } 233*ca2c1931SNathan Whitehorn 234*ca2c1931SNathan Whitehorn sc->sc_range[6].pci_hi = 0; 235*ca2c1931SNathan Whitehorn io = NULL; 236*ca2c1931SNathan Whitehorn nmem = 0; 237*ca2c1931SNathan Whitehorn 238*ca2c1931SNathan Whitehorn for (rp = sc->sc_range; rp->pci_hi != 0; rp++) { 239*ca2c1931SNathan Whitehorn switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { 240*ca2c1931SNathan Whitehorn case OFW_PCI_PHYS_HI_SPACE_CONFIG: 241*ca2c1931SNathan Whitehorn break; 242*ca2c1931SNathan Whitehorn case OFW_PCI_PHYS_HI_SPACE_IO: 243*ca2c1931SNathan Whitehorn io = rp; 244*ca2c1931SNathan Whitehorn break; 245*ca2c1931SNathan Whitehorn case OFW_PCI_PHYS_HI_SPACE_MEM32: 246*ca2c1931SNathan Whitehorn mem[nmem] = rp; 247*ca2c1931SNathan Whitehorn nmem++; 248*ca2c1931SNathan Whitehorn break; 249*ca2c1931SNathan Whitehorn case OFW_PCI_PHYS_HI_SPACE_MEM64: 250*ca2c1931SNathan Whitehorn break; 251*ca2c1931SNathan Whitehorn } 252*ca2c1931SNathan Whitehorn } 253*ca2c1931SNathan Whitehorn 254*ca2c1931SNathan Whitehorn if (io == NULL) { 255*ca2c1931SNathan Whitehorn device_printf(dev, "can't find io range\n"); 256*ca2c1931SNathan Whitehorn return (ENXIO); 257*ca2c1931SNathan Whitehorn } 258*ca2c1931SNathan Whitehorn sc->sc_io_rman.rm_type = RMAN_ARRAY; 259*ca2c1931SNathan Whitehorn sc->sc_io_rman.rm_descr = "UniNorth PCI I/O Ports"; 260*ca2c1931SNathan Whitehorn sc->sc_iostart = io->host; 261*ca2c1931SNathan Whitehorn if (rman_init(&sc->sc_io_rman) != 0 || 262*ca2c1931SNathan Whitehorn rman_manage_region(&sc->sc_io_rman, io->pci_lo, 263*ca2c1931SNathan Whitehorn io->pci_lo + io->size_lo - 1) != 0) { 264*ca2c1931SNathan Whitehorn panic("uninorth_attach: failed to set up I/O rman"); 265*ca2c1931SNathan Whitehorn } 266*ca2c1931SNathan Whitehorn 267*ca2c1931SNathan Whitehorn if (nmem == 0) { 268*ca2c1931SNathan Whitehorn device_printf(dev, "can't find mem ranges\n"); 269*ca2c1931SNathan Whitehorn return (ENXIO); 270*ca2c1931SNathan Whitehorn } 271*ca2c1931SNathan Whitehorn sc->sc_mem_rman.rm_type = RMAN_ARRAY; 272*ca2c1931SNathan Whitehorn sc->sc_mem_rman.rm_descr = "UniNorth PCI Memory"; 273*ca2c1931SNathan Whitehorn error = rman_init(&sc->sc_mem_rman); 274*ca2c1931SNathan Whitehorn if (error) { 275*ca2c1931SNathan Whitehorn device_printf(dev, "rman_init() failed. error = %d\n", error); 276*ca2c1931SNathan Whitehorn return (error); 277*ca2c1931SNathan Whitehorn } 278*ca2c1931SNathan Whitehorn for (i = 0; i < nmem; i++) { 279*ca2c1931SNathan Whitehorn error = rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo, 280*ca2c1931SNathan Whitehorn mem[i]->pci_lo + mem[i]->size_lo - 1); 281*ca2c1931SNathan Whitehorn if (error) { 282*ca2c1931SNathan Whitehorn device_printf(dev, 283*ca2c1931SNathan Whitehorn "rman_manage_region() failed. error = %d\n", error); 284*ca2c1931SNathan Whitehorn return (error); 285*ca2c1931SNathan Whitehorn } 286*ca2c1931SNathan Whitehorn } 287*ca2c1931SNathan Whitehorn 288*ca2c1931SNathan Whitehorn ofw_bus_setup_iinfo(node, &sc->sc_pci_iinfo, sizeof(cell_t)); 289*ca2c1931SNathan Whitehorn 290*ca2c1931SNathan Whitehorn device_add_child(dev, "pci", device_get_unit(dev)); 291*ca2c1931SNathan Whitehorn return (bus_generic_attach(dev)); 292*ca2c1931SNathan Whitehorn } 293*ca2c1931SNathan Whitehorn 294*ca2c1931SNathan Whitehorn static int 295*ca2c1931SNathan Whitehorn uninorth_maxslots(device_t dev) 296*ca2c1931SNathan Whitehorn { 297*ca2c1931SNathan Whitehorn 298*ca2c1931SNathan Whitehorn return (PCI_SLOTMAX); 299*ca2c1931SNathan Whitehorn } 300*ca2c1931SNathan Whitehorn 301*ca2c1931SNathan Whitehorn static u_int32_t 302*ca2c1931SNathan Whitehorn uninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 303*ca2c1931SNathan Whitehorn int width) 304*ca2c1931SNathan Whitehorn { 305*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 306*ca2c1931SNathan Whitehorn vm_offset_t caoff; 307*ca2c1931SNathan Whitehorn 308*ca2c1931SNathan Whitehorn sc = device_get_softc(dev); 309*ca2c1931SNathan Whitehorn caoff = sc->sc_data + (reg & 0x07); 310*ca2c1931SNathan Whitehorn 311*ca2c1931SNathan Whitehorn if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) { 312*ca2c1931SNathan Whitehorn switch (width) { 313*ca2c1931SNathan Whitehorn case 1: 314*ca2c1931SNathan Whitehorn return (in8rb(caoff)); 315*ca2c1931SNathan Whitehorn break; 316*ca2c1931SNathan Whitehorn case 2: 317*ca2c1931SNathan Whitehorn return (in16rb(caoff)); 318*ca2c1931SNathan Whitehorn break; 319*ca2c1931SNathan Whitehorn case 4: 320*ca2c1931SNathan Whitehorn return (in32rb(caoff)); 321*ca2c1931SNathan Whitehorn break; 322*ca2c1931SNathan Whitehorn } 323*ca2c1931SNathan Whitehorn } 324*ca2c1931SNathan Whitehorn 325*ca2c1931SNathan Whitehorn return (0xffffffff); 326*ca2c1931SNathan Whitehorn } 327*ca2c1931SNathan Whitehorn 328*ca2c1931SNathan Whitehorn static void 329*ca2c1931SNathan Whitehorn uninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func, 330*ca2c1931SNathan Whitehorn u_int reg, u_int32_t val, int width) 331*ca2c1931SNathan Whitehorn { 332*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 333*ca2c1931SNathan Whitehorn vm_offset_t caoff; 334*ca2c1931SNathan Whitehorn 335*ca2c1931SNathan Whitehorn sc = device_get_softc(dev); 336*ca2c1931SNathan Whitehorn caoff = sc->sc_data + (reg & 0x07); 337*ca2c1931SNathan Whitehorn 338*ca2c1931SNathan Whitehorn if (uninorth_enable_config(sc, bus, slot, func, reg)) { 339*ca2c1931SNathan Whitehorn switch (width) { 340*ca2c1931SNathan Whitehorn case 1: 341*ca2c1931SNathan Whitehorn out8rb(caoff, val); 342*ca2c1931SNathan Whitehorn break; 343*ca2c1931SNathan Whitehorn case 2: 344*ca2c1931SNathan Whitehorn out16rb(caoff, val); 345*ca2c1931SNathan Whitehorn break; 346*ca2c1931SNathan Whitehorn case 4: 347*ca2c1931SNathan Whitehorn out32rb(caoff, val); 348*ca2c1931SNathan Whitehorn break; 349*ca2c1931SNathan Whitehorn } 350*ca2c1931SNathan Whitehorn } 351*ca2c1931SNathan Whitehorn } 352*ca2c1931SNathan Whitehorn 353*ca2c1931SNathan Whitehorn static int 354*ca2c1931SNathan Whitehorn uninorth_route_interrupt(device_t bus, device_t dev, int pin) 355*ca2c1931SNathan Whitehorn { 356*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 357*ca2c1931SNathan Whitehorn struct ofw_pci_register reg; 358*ca2c1931SNathan Whitehorn uint32_t pintr, mintr; 359*ca2c1931SNathan Whitehorn uint8_t maskbuf[sizeof(reg) + sizeof(pintr)]; 360*ca2c1931SNathan Whitehorn 361*ca2c1931SNathan Whitehorn sc = device_get_softc(bus); 362*ca2c1931SNathan Whitehorn pintr = pin; 363*ca2c1931SNathan Whitehorn if (ofw_bus_lookup_imap(ofw_bus_get_node(dev), &sc->sc_pci_iinfo, ®, 364*ca2c1931SNathan Whitehorn sizeof(reg), &pintr, sizeof(pintr), &mintr, sizeof(mintr), 365*ca2c1931SNathan Whitehorn maskbuf)) 366*ca2c1931SNathan Whitehorn return (mintr); 367*ca2c1931SNathan Whitehorn 368*ca2c1931SNathan Whitehorn /* Maybe it's a real interrupt, not an intpin */ 369*ca2c1931SNathan Whitehorn if (pin > 4) 370*ca2c1931SNathan Whitehorn return (pin); 371*ca2c1931SNathan Whitehorn 372*ca2c1931SNathan Whitehorn device_printf(bus, "could not route pin %d for device %d.%d\n", 373*ca2c1931SNathan Whitehorn pin, pci_get_slot(dev), pci_get_function(dev)); 374*ca2c1931SNathan Whitehorn return (PCI_INVALID_IRQ); 375*ca2c1931SNathan Whitehorn } 376*ca2c1931SNathan Whitehorn 377*ca2c1931SNathan Whitehorn static int 378*ca2c1931SNathan Whitehorn uninorth_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 379*ca2c1931SNathan Whitehorn { 380*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 381*ca2c1931SNathan Whitehorn 382*ca2c1931SNathan Whitehorn sc = device_get_softc(dev); 383*ca2c1931SNathan Whitehorn 384*ca2c1931SNathan Whitehorn switch (which) { 385*ca2c1931SNathan Whitehorn case PCIB_IVAR_DOMAIN: 386*ca2c1931SNathan Whitehorn *result = device_get_unit(dev); 387*ca2c1931SNathan Whitehorn return (0); 388*ca2c1931SNathan Whitehorn case PCIB_IVAR_BUS: 389*ca2c1931SNathan Whitehorn *result = sc->sc_bus; 390*ca2c1931SNathan Whitehorn return (0); 391*ca2c1931SNathan Whitehorn } 392*ca2c1931SNathan Whitehorn 393*ca2c1931SNathan Whitehorn return (ENOENT); 394*ca2c1931SNathan Whitehorn } 395*ca2c1931SNathan Whitehorn 396*ca2c1931SNathan Whitehorn static struct resource * 397*ca2c1931SNathan Whitehorn uninorth_alloc_resource(device_t bus, device_t child, int type, int *rid, 398*ca2c1931SNathan Whitehorn u_long start, u_long end, u_long count, u_int flags) 399*ca2c1931SNathan Whitehorn { 400*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 401*ca2c1931SNathan Whitehorn struct resource *rv; 402*ca2c1931SNathan Whitehorn struct rman *rm; 403*ca2c1931SNathan Whitehorn int needactivate; 404*ca2c1931SNathan Whitehorn 405*ca2c1931SNathan Whitehorn needactivate = flags & RF_ACTIVE; 406*ca2c1931SNathan Whitehorn flags &= ~RF_ACTIVE; 407*ca2c1931SNathan Whitehorn 408*ca2c1931SNathan Whitehorn sc = device_get_softc(bus); 409*ca2c1931SNathan Whitehorn 410*ca2c1931SNathan Whitehorn switch (type) { 411*ca2c1931SNathan Whitehorn case SYS_RES_MEMORY: 412*ca2c1931SNathan Whitehorn rm = &sc->sc_mem_rman; 413*ca2c1931SNathan Whitehorn break; 414*ca2c1931SNathan Whitehorn 415*ca2c1931SNathan Whitehorn case SYS_RES_IOPORT: 416*ca2c1931SNathan Whitehorn rm = &sc->sc_io_rman; 417*ca2c1931SNathan Whitehorn break; 418*ca2c1931SNathan Whitehorn 419*ca2c1931SNathan Whitehorn case SYS_RES_IRQ: 420*ca2c1931SNathan Whitehorn return (bus_alloc_resource(bus, type, rid, start, end, count, 421*ca2c1931SNathan Whitehorn flags)); 422*ca2c1931SNathan Whitehorn 423*ca2c1931SNathan Whitehorn default: 424*ca2c1931SNathan Whitehorn device_printf(bus, "unknown resource request from %s\n", 425*ca2c1931SNathan Whitehorn device_get_nameunit(child)); 426*ca2c1931SNathan Whitehorn return (NULL); 427*ca2c1931SNathan Whitehorn } 428*ca2c1931SNathan Whitehorn 429*ca2c1931SNathan Whitehorn rv = rman_reserve_resource(rm, start, end, count, flags, child); 430*ca2c1931SNathan Whitehorn if (rv == NULL) { 431*ca2c1931SNathan Whitehorn device_printf(bus, "failed to reserve resource for %s\n", 432*ca2c1931SNathan Whitehorn device_get_nameunit(child)); 433*ca2c1931SNathan Whitehorn return (NULL); 434*ca2c1931SNathan Whitehorn } 435*ca2c1931SNathan Whitehorn 436*ca2c1931SNathan Whitehorn rman_set_rid(rv, *rid); 437*ca2c1931SNathan Whitehorn 438*ca2c1931SNathan Whitehorn if (needactivate) { 439*ca2c1931SNathan Whitehorn if (bus_activate_resource(child, type, *rid, rv) != 0) { 440*ca2c1931SNathan Whitehorn device_printf(bus, 441*ca2c1931SNathan Whitehorn "failed to activate resource for %s\n", 442*ca2c1931SNathan Whitehorn device_get_nameunit(child)); 443*ca2c1931SNathan Whitehorn rman_release_resource(rv); 444*ca2c1931SNathan Whitehorn return (NULL); 445*ca2c1931SNathan Whitehorn } 446*ca2c1931SNathan Whitehorn } 447*ca2c1931SNathan Whitehorn 448*ca2c1931SNathan Whitehorn return (rv); 449*ca2c1931SNathan Whitehorn } 450*ca2c1931SNathan Whitehorn 451*ca2c1931SNathan Whitehorn static int 452*ca2c1931SNathan Whitehorn uninorth_activate_resource(device_t bus, device_t child, int type, int rid, 453*ca2c1931SNathan Whitehorn struct resource *res) 454*ca2c1931SNathan Whitehorn { 455*ca2c1931SNathan Whitehorn void *p; 456*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 457*ca2c1931SNathan Whitehorn 458*ca2c1931SNathan Whitehorn sc = device_get_softc(bus); 459*ca2c1931SNathan Whitehorn 460*ca2c1931SNathan Whitehorn if (type == SYS_RES_IRQ) 461*ca2c1931SNathan Whitehorn return (bus_activate_resource(bus, type, rid, res)); 462*ca2c1931SNathan Whitehorn 463*ca2c1931SNathan Whitehorn if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 464*ca2c1931SNathan Whitehorn vm_offset_t start; 465*ca2c1931SNathan Whitehorn 466*ca2c1931SNathan Whitehorn start = (vm_offset_t)rman_get_start(res); 467*ca2c1931SNathan Whitehorn /* 468*ca2c1931SNathan Whitehorn * For i/o-ports, convert the start address to the 469*ca2c1931SNathan Whitehorn * uninorth PCI i/o window 470*ca2c1931SNathan Whitehorn */ 471*ca2c1931SNathan Whitehorn if (type == SYS_RES_IOPORT) 472*ca2c1931SNathan Whitehorn start += sc->sc_iostart; 473*ca2c1931SNathan Whitehorn 474*ca2c1931SNathan Whitehorn if (bootverbose) 475*ca2c1931SNathan Whitehorn printf("uninorth mapdev: start %zx, len %ld\n", start, 476*ca2c1931SNathan Whitehorn rman_get_size(res)); 477*ca2c1931SNathan Whitehorn 478*ca2c1931SNathan Whitehorn p = pmap_mapdev(start, (vm_size_t)rman_get_size(res)); 479*ca2c1931SNathan Whitehorn if (p == NULL) 480*ca2c1931SNathan Whitehorn return (ENOMEM); 481*ca2c1931SNathan Whitehorn rman_set_virtual(res, p); 482*ca2c1931SNathan Whitehorn rman_set_bustag(res, &bs_le_tag); 483*ca2c1931SNathan Whitehorn rman_set_bushandle(res, (u_long)p); 484*ca2c1931SNathan Whitehorn } 485*ca2c1931SNathan Whitehorn 486*ca2c1931SNathan Whitehorn return (rman_activate_resource(res)); 487*ca2c1931SNathan Whitehorn } 488*ca2c1931SNathan Whitehorn 489*ca2c1931SNathan Whitehorn static int 490*ca2c1931SNathan Whitehorn uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot, 491*ca2c1931SNathan Whitehorn u_int func, u_int reg) 492*ca2c1931SNathan Whitehorn { 493*ca2c1931SNathan Whitehorn uint32_t cfgval; 494*ca2c1931SNathan Whitehorn uint32_t pass; 495*ca2c1931SNathan Whitehorn 496*ca2c1931SNathan Whitehorn if (resource_int_value(device_get_name(sc->sc_dev), 497*ca2c1931SNathan Whitehorn device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) { 498*ca2c1931SNathan Whitehorn if (pass == slot) 499*ca2c1931SNathan Whitehorn return (0); 500*ca2c1931SNathan Whitehorn } 501*ca2c1931SNathan Whitehorn 502*ca2c1931SNathan Whitehorn /* 503*ca2c1931SNathan Whitehorn * Issue type 0 configuration space accesses for the root bus. 504*ca2c1931SNathan Whitehorn * 505*ca2c1931SNathan Whitehorn * NOTE: On U4, issue only type 1 accesses. There is a secret 506*ca2c1931SNathan Whitehorn * PCI Express <-> PCI Express bridge not present in the device tree, 507*ca2c1931SNathan Whitehorn * and we need to route all of our configuration space through it. 508*ca2c1931SNathan Whitehorn */ 509*ca2c1931SNathan Whitehorn if (sc->sc_bus == bus && sc->sc_ver < 4) { 510*ca2c1931SNathan Whitehorn /* 511*ca2c1931SNathan Whitehorn * No slots less than 11 on the primary bus on U3 and lower 512*ca2c1931SNathan Whitehorn */ 513*ca2c1931SNathan Whitehorn if (slot < 11) 514*ca2c1931SNathan Whitehorn return (0); 515*ca2c1931SNathan Whitehorn 516*ca2c1931SNathan Whitehorn cfgval = (1 << slot) | (func << 8) | (reg & 0xfc); 517*ca2c1931SNathan Whitehorn } else { 518*ca2c1931SNathan Whitehorn cfgval = (bus << 16) | (slot << 11) | (func << 8) | 519*ca2c1931SNathan Whitehorn (reg & 0xfc) | 1; 520*ca2c1931SNathan Whitehorn } 521*ca2c1931SNathan Whitehorn 522*ca2c1931SNathan Whitehorn /* Set extended register bits on U4 */ 523*ca2c1931SNathan Whitehorn if (sc->sc_ver == 4) 524*ca2c1931SNathan Whitehorn cfgval |= (reg >> 8) << 28; 525*ca2c1931SNathan Whitehorn 526*ca2c1931SNathan Whitehorn do { 527*ca2c1931SNathan Whitehorn out32rb(sc->sc_addr, cfgval); 528*ca2c1931SNathan Whitehorn } while (in32rb(sc->sc_addr) != cfgval); 529*ca2c1931SNathan Whitehorn 530*ca2c1931SNathan Whitehorn return (1); 531*ca2c1931SNathan Whitehorn } 532*ca2c1931SNathan Whitehorn 533*ca2c1931SNathan Whitehorn static phandle_t 534*ca2c1931SNathan Whitehorn uninorth_get_node(device_t bus, device_t dev) 535*ca2c1931SNathan Whitehorn { 536*ca2c1931SNathan Whitehorn struct uninorth_softc *sc; 537*ca2c1931SNathan Whitehorn 538*ca2c1931SNathan Whitehorn sc = device_get_softc(bus); 539*ca2c1931SNathan Whitehorn /* We only have one child, the PCI bus, which needs our own node. */ 540*ca2c1931SNathan Whitehorn 541*ca2c1931SNathan Whitehorn return sc->sc_node; 542*ca2c1931SNathan Whitehorn } 543*ca2c1931SNathan Whitehorn 544