160727d8bSWarner Losh /*- 298f8e6c0SBenno Rice * Copyright (C) 2002 Benno Rice. 398f8e6c0SBenno Rice * All rights reserved. 498f8e6c0SBenno Rice * 598f8e6c0SBenno Rice * Redistribution and use in source and binary forms, with or without 698f8e6c0SBenno Rice * modification, are permitted provided that the following conditions 798f8e6c0SBenno Rice * are met: 898f8e6c0SBenno Rice * 1. Redistributions of source code must retain the above copyright 998f8e6c0SBenno Rice * notice, this list of conditions and the following disclaimer. 1098f8e6c0SBenno Rice * 2. Redistributions in binary form must reproduce the above copyright 1198f8e6c0SBenno Rice * notice, this list of conditions and the following disclaimer in the 1298f8e6c0SBenno Rice * documentation and/or other materials provided with the distribution. 1398f8e6c0SBenno Rice * 1498f8e6c0SBenno Rice * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 1598f8e6c0SBenno Rice * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1698f8e6c0SBenno Rice * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1798f8e6c0SBenno Rice * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 1898f8e6c0SBenno Rice * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 1998f8e6c0SBenno Rice * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 2098f8e6c0SBenno Rice * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 2198f8e6c0SBenno Rice * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2298f8e6c0SBenno Rice * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 2398f8e6c0SBenno Rice * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2498f8e6c0SBenno Rice * 2598f8e6c0SBenno Rice * $FreeBSD$ 2698f8e6c0SBenno Rice */ 2798f8e6c0SBenno Rice 2898f8e6c0SBenno Rice #include <sys/param.h> 2998f8e6c0SBenno Rice #include <sys/systm.h> 3040cdee9dSPeter Grehan #include <sys/module.h> 3198f8e6c0SBenno Rice #include <sys/bus.h> 3298f8e6c0SBenno Rice #include <sys/conf.h> 3398f8e6c0SBenno Rice #include <sys/kernel.h> 3498f8e6c0SBenno Rice 3598f8e6c0SBenno Rice #include <dev/ofw/openfirm.h> 3698f8e6c0SBenno Rice #include <dev/ofw/ofw_pci.h> 3751d163d3SNathan Whitehorn #include <dev/ofw/ofw_bus.h> 3898f8e6c0SBenno Rice 3998f8e6c0SBenno Rice #include <dev/pci/pcivar.h> 4098f8e6c0SBenno Rice #include <dev/pci/pcireg.h> 4198f8e6c0SBenno Rice 4298f8e6c0SBenno Rice #include <machine/bus.h> 4398f8e6c0SBenno Rice #include <machine/md_var.h> 44de2fa7b8SMarcel Moolenaar #include <machine/pio.h> 4598f8e6c0SBenno Rice #include <machine/resource.h> 4698f8e6c0SBenno Rice 4798f8e6c0SBenno Rice #include <sys/rman.h> 4898f8e6c0SBenno Rice 4998f8e6c0SBenno Rice #include <powerpc/powermac/uninorthvar.h> 5098f8e6c0SBenno Rice 5198f8e6c0SBenno Rice #include <vm/vm.h> 5298f8e6c0SBenno Rice #include <vm/pmap.h> 5398f8e6c0SBenno Rice 5498f8e6c0SBenno Rice #include "pcib_if.h" 5598f8e6c0SBenno Rice 5698f8e6c0SBenno Rice #define UNINORTH_DEBUG 0 5798f8e6c0SBenno Rice 5898f8e6c0SBenno Rice /* 5998f8e6c0SBenno Rice * Device interface. 6098f8e6c0SBenno Rice */ 6198f8e6c0SBenno Rice static int uninorth_probe(device_t); 6298f8e6c0SBenno Rice static int uninorth_attach(device_t); 6398f8e6c0SBenno Rice 6498f8e6c0SBenno Rice /* 6598f8e6c0SBenno Rice * Bus interface. 6698f8e6c0SBenno Rice */ 6798f8e6c0SBenno Rice static int uninorth_read_ivar(device_t, device_t, int, 6898f8e6c0SBenno Rice uintptr_t *); 6998f8e6c0SBenno Rice static struct resource * uninorth_alloc_resource(device_t bus, 7098f8e6c0SBenno Rice device_t child, int type, int *rid, u_long start, 7198f8e6c0SBenno Rice u_long end, u_long count, u_int flags); 7298f8e6c0SBenno Rice static int uninorth_activate_resource(device_t bus, device_t child, 7398f8e6c0SBenno Rice int type, int rid, struct resource *res); 7498f8e6c0SBenno Rice 7598f8e6c0SBenno Rice /* 7698f8e6c0SBenno Rice * pcib interface. 7798f8e6c0SBenno Rice */ 7898f8e6c0SBenno Rice static int uninorth_maxslots(device_t); 7998f8e6c0SBenno Rice static u_int32_t uninorth_read_config(device_t, u_int, u_int, u_int, 8098f8e6c0SBenno Rice u_int, int); 8198f8e6c0SBenno Rice static void uninorth_write_config(device_t, u_int, u_int, u_int, 8298f8e6c0SBenno Rice u_int, u_int32_t, int); 8398f8e6c0SBenno Rice static int uninorth_route_interrupt(device_t, device_t, int); 8498f8e6c0SBenno Rice 8598f8e6c0SBenno Rice /* 8651d163d3SNathan Whitehorn * OFW Bus interface 8751d163d3SNathan Whitehorn */ 8851d163d3SNathan Whitehorn 8951d163d3SNathan Whitehorn static phandle_t uninorth_get_node(device_t bus, device_t dev); 9051d163d3SNathan Whitehorn 9151d163d3SNathan Whitehorn /* 9298f8e6c0SBenno Rice * Local routines. 9398f8e6c0SBenno Rice */ 9498f8e6c0SBenno Rice static int uninorth_enable_config(struct uninorth_softc *, u_int, 9598f8e6c0SBenno Rice u_int, u_int, u_int); 96d48bbef3SPeter Grehan static void unin_enable_gmac(void); 9798f8e6c0SBenno Rice 9898f8e6c0SBenno Rice /* 9998f8e6c0SBenno Rice * Driver methods. 10098f8e6c0SBenno Rice */ 10198f8e6c0SBenno Rice static device_method_t uninorth_methods[] = { 10298f8e6c0SBenno Rice /* Device interface */ 10398f8e6c0SBenno Rice DEVMETHOD(device_probe, uninorth_probe), 10498f8e6c0SBenno Rice DEVMETHOD(device_attach, uninorth_attach), 10598f8e6c0SBenno Rice 10698f8e6c0SBenno Rice /* Bus interface */ 10798f8e6c0SBenno Rice DEVMETHOD(bus_print_child, bus_generic_print_child), 10898f8e6c0SBenno Rice DEVMETHOD(bus_read_ivar, uninorth_read_ivar), 10998f8e6c0SBenno Rice DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 11098f8e6c0SBenno Rice DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 11198f8e6c0SBenno Rice DEVMETHOD(bus_alloc_resource, uninorth_alloc_resource), 11298f8e6c0SBenno Rice DEVMETHOD(bus_activate_resource, uninorth_activate_resource), 11398f8e6c0SBenno Rice 11498f8e6c0SBenno Rice /* pcib interface */ 11598f8e6c0SBenno Rice DEVMETHOD(pcib_maxslots, uninorth_maxslots), 11698f8e6c0SBenno Rice DEVMETHOD(pcib_read_config, uninorth_read_config), 11798f8e6c0SBenno Rice DEVMETHOD(pcib_write_config, uninorth_write_config), 11898f8e6c0SBenno Rice DEVMETHOD(pcib_route_interrupt, uninorth_route_interrupt), 11998f8e6c0SBenno Rice 12051d163d3SNathan Whitehorn /* ofw_bus interface */ 12151d163d3SNathan Whitehorn DEVMETHOD(ofw_bus_get_node, uninorth_get_node), 12251d163d3SNathan Whitehorn 12398f8e6c0SBenno Rice { 0, 0 } 12498f8e6c0SBenno Rice }; 12598f8e6c0SBenno Rice 12698f8e6c0SBenno Rice static driver_t uninorth_driver = { 12798f8e6c0SBenno Rice "pcib", 12898f8e6c0SBenno Rice uninorth_methods, 12998f8e6c0SBenno Rice sizeof(struct uninorth_softc) 13098f8e6c0SBenno Rice }; 13198f8e6c0SBenno Rice 13298f8e6c0SBenno Rice static devclass_t uninorth_devclass; 13398f8e6c0SBenno Rice 13498f8e6c0SBenno Rice DRIVER_MODULE(uninorth, nexus, uninorth_driver, uninorth_devclass, 0, 0); 13598f8e6c0SBenno Rice 13698f8e6c0SBenno Rice static int 13798f8e6c0SBenno Rice uninorth_probe(device_t dev) 13898f8e6c0SBenno Rice { 13951d163d3SNathan Whitehorn const char *type, *compatible; 14098f8e6c0SBenno Rice 14151d163d3SNathan Whitehorn type = ofw_bus_get_type(dev); 14251d163d3SNathan Whitehorn compatible = ofw_bus_get_compat(dev); 14398f8e6c0SBenno Rice 14498f8e6c0SBenno Rice if (type == NULL || compatible == NULL) 14598f8e6c0SBenno Rice return (ENXIO); 14698f8e6c0SBenno Rice 14751d163d3SNathan Whitehorn if (strcmp(type, "pci") != 0) 14898f8e6c0SBenno Rice return (ENXIO); 14998f8e6c0SBenno Rice 15051d163d3SNathan Whitehorn if (strcmp(compatible, "uni-north") == 0) { 15198f8e6c0SBenno Rice device_set_desc(dev, "Apple UniNorth Host-PCI bridge"); 15298f8e6c0SBenno Rice return (0); 15351d163d3SNathan Whitehorn } else if (strcmp(compatible,"u3-agp") == 0) { 15451d163d3SNathan Whitehorn device_set_desc(dev, "Apple U3 Host-AGP bridge"); 15551d163d3SNathan Whitehorn return (0); 15651d163d3SNathan Whitehorn } 15751d163d3SNathan Whitehorn 15851d163d3SNathan Whitehorn return (ENXIO); 15998f8e6c0SBenno Rice } 16098f8e6c0SBenno Rice 16198f8e6c0SBenno Rice static int 16298f8e6c0SBenno Rice uninorth_attach(device_t dev) 16398f8e6c0SBenno Rice { 16498f8e6c0SBenno Rice struct uninorth_softc *sc; 16551d163d3SNathan Whitehorn const char *compatible; 16698f8e6c0SBenno Rice phandle_t node; 167d48bbef3SPeter Grehan phandle_t child; 16898f8e6c0SBenno Rice u_int32_t reg[2], busrange[2]; 16998f8e6c0SBenno Rice struct uninorth_range *rp, *io, *mem[2]; 170bda386dbSKevin Lo int nmem, i, error; 17198f8e6c0SBenno Rice 17251d163d3SNathan Whitehorn node = ofw_bus_get_node(dev); 17398f8e6c0SBenno Rice sc = device_get_softc(dev); 17498f8e6c0SBenno Rice 17598f8e6c0SBenno Rice if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 17698f8e6c0SBenno Rice return (ENXIO); 17798f8e6c0SBenno Rice 17898f8e6c0SBenno Rice if (OF_getprop(node, "bus-range", busrange, sizeof(busrange)) != 8) 17998f8e6c0SBenno Rice return (ENXIO); 18098f8e6c0SBenno Rice 18151d163d3SNathan Whitehorn sc->sc_u3 = 0; 18251d163d3SNathan Whitehorn compatible = ofw_bus_get_compat(dev); 18351d163d3SNathan Whitehorn if (strcmp(compatible,"u3-agp") == 0) 18451d163d3SNathan Whitehorn sc->sc_u3 = 1; 18551d163d3SNathan Whitehorn 18698f8e6c0SBenno Rice sc->sc_dev = dev; 18798f8e6c0SBenno Rice sc->sc_node = node; 18851d163d3SNathan Whitehorn if (sc->sc_u3) { 18951d163d3SNathan Whitehorn sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[1] + 0x800000, PAGE_SIZE); 19051d163d3SNathan Whitehorn sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1] + 0xc00000, PAGE_SIZE); 19151d163d3SNathan Whitehorn } else { 19298f8e6c0SBenno Rice sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[0] + 0x800000, PAGE_SIZE); 19398f8e6c0SBenno Rice sc->sc_data = (vm_offset_t)pmap_mapdev(reg[0] + 0xc00000, PAGE_SIZE); 19451d163d3SNathan Whitehorn } 19598f8e6c0SBenno Rice sc->sc_bus = busrange[0]; 19698f8e6c0SBenno Rice 19798f8e6c0SBenno Rice bzero(sc->sc_range, sizeof(sc->sc_range)); 19851d163d3SNathan Whitehorn if (sc->sc_u3) { 19951d163d3SNathan Whitehorn /* 20051d163d3SNathan Whitehorn * On Apple U3 systems, we have an otherwise standard 20151d163d3SNathan Whitehorn * Uninorth controller driving AGP. The one difference 20251d163d3SNathan Whitehorn * is that it uses a new PCI ranges format, so do the 20351d163d3SNathan Whitehorn * translation. 20451d163d3SNathan Whitehorn */ 20551d163d3SNathan Whitehorn 20651d163d3SNathan Whitehorn struct uninorth_range64 range64[6]; 20751d163d3SNathan Whitehorn bzero(range64, sizeof(range64)); 20851d163d3SNathan Whitehorn 20951d163d3SNathan Whitehorn sc->sc_nrange = OF_getprop(node, "ranges", range64, 21051d163d3SNathan Whitehorn sizeof(range64)); 21151d163d3SNathan Whitehorn for (i = 0; range64[i].pci_hi != 0; i++) { 21251d163d3SNathan Whitehorn sc->sc_range[i].pci_hi = range64[i].pci_hi; 21351d163d3SNathan Whitehorn sc->sc_range[i].pci_mid = range64[i].pci_mid; 21451d163d3SNathan Whitehorn sc->sc_range[i].pci_lo = range64[i].pci_lo; 21551d163d3SNathan Whitehorn sc->sc_range[i].host = range64[i].host_lo; 21651d163d3SNathan Whitehorn sc->sc_range[i].size_hi = range64[i].size_hi; 21751d163d3SNathan Whitehorn sc->sc_range[i].size_lo = range64[i].size_lo; 21851d163d3SNathan Whitehorn } 21951d163d3SNathan Whitehorn } else { 22098f8e6c0SBenno Rice sc->sc_nrange = OF_getprop(node, "ranges", sc->sc_range, 22198f8e6c0SBenno Rice sizeof(sc->sc_range)); 22251d163d3SNathan Whitehorn } 22398f8e6c0SBenno Rice 22498f8e6c0SBenno Rice if (sc->sc_nrange == -1) { 22598f8e6c0SBenno Rice device_printf(dev, "could not get ranges\n"); 22698f8e6c0SBenno Rice return (ENXIO); 22798f8e6c0SBenno Rice } 22898f8e6c0SBenno Rice 22998f8e6c0SBenno Rice sc->sc_range[6].pci_hi = 0; 23098f8e6c0SBenno Rice io = NULL; 23198f8e6c0SBenno Rice nmem = 0; 23298f8e6c0SBenno Rice 23398f8e6c0SBenno Rice for (rp = sc->sc_range; rp->pci_hi != 0; rp++) { 23498f8e6c0SBenno Rice switch (rp->pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) { 23598f8e6c0SBenno Rice case OFW_PCI_PHYS_HI_SPACE_CONFIG: 23698f8e6c0SBenno Rice break; 23798f8e6c0SBenno Rice case OFW_PCI_PHYS_HI_SPACE_IO: 23898f8e6c0SBenno Rice io = rp; 23998f8e6c0SBenno Rice break; 24098f8e6c0SBenno Rice case OFW_PCI_PHYS_HI_SPACE_MEM32: 24198f8e6c0SBenno Rice mem[nmem] = rp; 24298f8e6c0SBenno Rice nmem++; 24398f8e6c0SBenno Rice break; 24498f8e6c0SBenno Rice case OFW_PCI_PHYS_HI_SPACE_MEM64: 24598f8e6c0SBenno Rice break; 24698f8e6c0SBenno Rice } 24798f8e6c0SBenno Rice } 24898f8e6c0SBenno Rice 24998f8e6c0SBenno Rice if (io == NULL) { 25098f8e6c0SBenno Rice device_printf(dev, "can't find io range\n"); 25198f8e6c0SBenno Rice return (ENXIO); 25298f8e6c0SBenno Rice } 25398f8e6c0SBenno Rice sc->sc_io_rman.rm_type = RMAN_ARRAY; 25498f8e6c0SBenno Rice sc->sc_io_rman.rm_descr = "UniNorth PCI I/O Ports"; 255714aa5b9SAndrew Gallatin sc->sc_iostart = io->host; 25698f8e6c0SBenno Rice if (rman_init(&sc->sc_io_rman) != 0 || 25798f8e6c0SBenno Rice rman_manage_region(&sc->sc_io_rman, io->pci_lo, 2583b7b274aSPeter Grehan io->pci_lo + io->size_lo - 1) != 0) { 259bda386dbSKevin Lo panic("uninorth_attach: failed to set up I/O rman"); 26098f8e6c0SBenno Rice } 26198f8e6c0SBenno Rice 26298f8e6c0SBenno Rice if (nmem == 0) { 26398f8e6c0SBenno Rice device_printf(dev, "can't find mem ranges\n"); 26498f8e6c0SBenno Rice return (ENXIO); 26598f8e6c0SBenno Rice } 26698f8e6c0SBenno Rice sc->sc_mem_rman.rm_type = RMAN_ARRAY; 26798f8e6c0SBenno Rice sc->sc_mem_rman.rm_descr = "UniNorth PCI Memory"; 268bda386dbSKevin Lo error = rman_init(&sc->sc_mem_rman); 269bda386dbSKevin Lo if (error) { 270bda386dbSKevin Lo device_printf(dev, "rman_init() failed. error = %d\n", error); 271bda386dbSKevin Lo return (error); 27298f8e6c0SBenno Rice } 27398f8e6c0SBenno Rice for (i = 0; i < nmem; i++) { 274bda386dbSKevin Lo error = rman_manage_region(&sc->sc_mem_rman, mem[i]->pci_lo, 275bda386dbSKevin Lo mem[i]->pci_lo + mem[i]->size_lo - 1); 276bda386dbSKevin Lo if (error) { 27798f8e6c0SBenno Rice device_printf(dev, 278bda386dbSKevin Lo "rman_manage_region() failed. error = %d\n", error); 279bda386dbSKevin Lo return (error); 28098f8e6c0SBenno Rice } 28198f8e6c0SBenno Rice } 28298f8e6c0SBenno Rice 283d48bbef3SPeter Grehan /* 28439513fa6SMarius Strobl * Enable the GMAC Ethernet cell if Open Firmware says it is 28539513fa6SMarius Strobl * used. 286d48bbef3SPeter Grehan */ 287d48bbef3SPeter Grehan for (child = OF_child(node); child; child = OF_peer(child)) { 288d48bbef3SPeter Grehan char compat[32]; 289d48bbef3SPeter Grehan 290d48bbef3SPeter Grehan memset(compat, 0, sizeof(compat)); 291d48bbef3SPeter Grehan OF_getprop(child, "compatible", compat, sizeof(compat)); 292d48bbef3SPeter Grehan if (strcmp(compat, "gmac") == 0) { 293d48bbef3SPeter Grehan unin_enable_gmac(); 294d48bbef3SPeter Grehan } 295d48bbef3SPeter Grehan } 296d48bbef3SPeter Grehan 29798f8e6c0SBenno Rice device_add_child(dev, "pci", device_get_unit(dev)); 29898f8e6c0SBenno Rice return (bus_generic_attach(dev)); 29998f8e6c0SBenno Rice } 30098f8e6c0SBenno Rice 30198f8e6c0SBenno Rice static int 30298f8e6c0SBenno Rice uninorth_maxslots(device_t dev) 30398f8e6c0SBenno Rice { 30498f8e6c0SBenno Rice 30598f8e6c0SBenno Rice return (PCI_SLOTMAX); 30698f8e6c0SBenno Rice } 30798f8e6c0SBenno Rice 30898f8e6c0SBenno Rice static u_int32_t 30998f8e6c0SBenno Rice uninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 31098f8e6c0SBenno Rice int width) 31198f8e6c0SBenno Rice { 31298f8e6c0SBenno Rice struct uninorth_softc *sc; 31398f8e6c0SBenno Rice vm_offset_t caoff; 31498f8e6c0SBenno Rice 31598f8e6c0SBenno Rice sc = device_get_softc(dev); 31698f8e6c0SBenno Rice caoff = sc->sc_data + (reg & 0x07); 31798f8e6c0SBenno Rice 31898f8e6c0SBenno Rice if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) { 31998f8e6c0SBenno Rice switch (width) { 32098f8e6c0SBenno Rice case 1: 32198f8e6c0SBenno Rice return (in8rb(caoff)); 32298f8e6c0SBenno Rice break; 32398f8e6c0SBenno Rice case 2: 32498f8e6c0SBenno Rice return (in16rb(caoff)); 32598f8e6c0SBenno Rice break; 32698f8e6c0SBenno Rice case 4: 32798f8e6c0SBenno Rice return (in32rb(caoff)); 32898f8e6c0SBenno Rice break; 32998f8e6c0SBenno Rice } 33098f8e6c0SBenno Rice } 33198f8e6c0SBenno Rice 33298f8e6c0SBenno Rice return (0xffffffff); 33398f8e6c0SBenno Rice } 33498f8e6c0SBenno Rice 33598f8e6c0SBenno Rice static void 33698f8e6c0SBenno Rice uninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func, 33798f8e6c0SBenno Rice u_int reg, u_int32_t val, int width) 33898f8e6c0SBenno Rice { 33998f8e6c0SBenno Rice struct uninorth_softc *sc; 34098f8e6c0SBenno Rice vm_offset_t caoff; 34198f8e6c0SBenno Rice 34298f8e6c0SBenno Rice sc = device_get_softc(dev); 34398f8e6c0SBenno Rice caoff = sc->sc_data + (reg & 0x07); 34498f8e6c0SBenno Rice 34598f8e6c0SBenno Rice if (uninorth_enable_config(sc, bus, slot, func, reg)) { 34698f8e6c0SBenno Rice switch (width) { 34798f8e6c0SBenno Rice case 1: 34898f8e6c0SBenno Rice out8rb(caoff, val); 34998f8e6c0SBenno Rice break; 35098f8e6c0SBenno Rice case 2: 35198f8e6c0SBenno Rice out16rb(caoff, val); 35298f8e6c0SBenno Rice break; 35398f8e6c0SBenno Rice case 4: 35498f8e6c0SBenno Rice out32rb(caoff, val); 35598f8e6c0SBenno Rice break; 35698f8e6c0SBenno Rice } 35798f8e6c0SBenno Rice } 35898f8e6c0SBenno Rice } 35998f8e6c0SBenno Rice 36098f8e6c0SBenno Rice static int 36198f8e6c0SBenno Rice uninorth_route_interrupt(device_t bus, device_t dev, int pin) 36298f8e6c0SBenno Rice { 36398f8e6c0SBenno Rice 36498f8e6c0SBenno Rice return (0); 36598f8e6c0SBenno Rice } 36698f8e6c0SBenno Rice 36798f8e6c0SBenno Rice static int 36898f8e6c0SBenno Rice uninorth_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 36998f8e6c0SBenno Rice { 37098f8e6c0SBenno Rice struct uninorth_softc *sc; 37198f8e6c0SBenno Rice 37298f8e6c0SBenno Rice sc = device_get_softc(dev); 37398f8e6c0SBenno Rice 37498f8e6c0SBenno Rice switch (which) { 37555aaf894SMarius Strobl case PCIB_IVAR_DOMAIN: 37655aaf894SMarius Strobl *result = device_get_unit(dev); 37755aaf894SMarius Strobl return (0); 37898f8e6c0SBenno Rice case PCIB_IVAR_BUS: 37998f8e6c0SBenno Rice *result = sc->sc_bus; 38098f8e6c0SBenno Rice return (0); 38198f8e6c0SBenno Rice } 38298f8e6c0SBenno Rice 38398f8e6c0SBenno Rice return (ENOENT); 38498f8e6c0SBenno Rice } 38598f8e6c0SBenno Rice 38698f8e6c0SBenno Rice static struct resource * 38798f8e6c0SBenno Rice uninorth_alloc_resource(device_t bus, device_t child, int type, int *rid, 38898f8e6c0SBenno Rice u_long start, u_long end, u_long count, u_int flags) 38998f8e6c0SBenno Rice { 39098f8e6c0SBenno Rice struct uninorth_softc *sc; 39198f8e6c0SBenno Rice struct resource *rv; 39298f8e6c0SBenno Rice struct rman *rm; 39398f8e6c0SBenno Rice int needactivate; 39498f8e6c0SBenno Rice 39598f8e6c0SBenno Rice needactivate = flags & RF_ACTIVE; 39698f8e6c0SBenno Rice flags &= ~RF_ACTIVE; 39798f8e6c0SBenno Rice 39898f8e6c0SBenno Rice sc = device_get_softc(bus); 39998f8e6c0SBenno Rice 40098f8e6c0SBenno Rice switch (type) { 40198f8e6c0SBenno Rice case SYS_RES_MEMORY: 40298f8e6c0SBenno Rice rm = &sc->sc_mem_rman; 40398f8e6c0SBenno Rice break; 404714aa5b9SAndrew Gallatin 405714aa5b9SAndrew Gallatin case SYS_RES_IOPORT: 406714aa5b9SAndrew Gallatin rm = &sc->sc_io_rman; 407714aa5b9SAndrew Gallatin break; 408714aa5b9SAndrew Gallatin 40998f8e6c0SBenno Rice case SYS_RES_IRQ: 41098f8e6c0SBenno Rice return (bus_alloc_resource(bus, type, rid, start, end, count, 41198f8e6c0SBenno Rice flags)); 412de2fa7b8SMarcel Moolenaar 41398f8e6c0SBenno Rice default: 41498f8e6c0SBenno Rice device_printf(bus, "unknown resource request from %s\n", 41598f8e6c0SBenno Rice device_get_nameunit(child)); 41698f8e6c0SBenno Rice return (NULL); 41798f8e6c0SBenno Rice } 41898f8e6c0SBenno Rice 41998f8e6c0SBenno Rice rv = rman_reserve_resource(rm, start, end, count, flags, child); 42098f8e6c0SBenno Rice if (rv == NULL) { 42198f8e6c0SBenno Rice device_printf(bus, "failed to reserve resource for %s\n", 42298f8e6c0SBenno Rice device_get_nameunit(child)); 42398f8e6c0SBenno Rice return (NULL); 42498f8e6c0SBenno Rice } 42598f8e6c0SBenno Rice 426bdfb66f8SWarner Losh rman_set_rid(rv, *rid); 42798f8e6c0SBenno Rice 42898f8e6c0SBenno Rice if (needactivate) { 42998f8e6c0SBenno Rice if (bus_activate_resource(child, type, *rid, rv) != 0) { 43098f8e6c0SBenno Rice device_printf(bus, 43198f8e6c0SBenno Rice "failed to activate resource for %s\n", 43298f8e6c0SBenno Rice device_get_nameunit(child)); 43398f8e6c0SBenno Rice rman_release_resource(rv); 43498f8e6c0SBenno Rice return (NULL); 43598f8e6c0SBenno Rice } 43698f8e6c0SBenno Rice } 43798f8e6c0SBenno Rice 43898f8e6c0SBenno Rice return (rv); 43998f8e6c0SBenno Rice } 44098f8e6c0SBenno Rice 44198f8e6c0SBenno Rice static int 44298f8e6c0SBenno Rice uninorth_activate_resource(device_t bus, device_t child, int type, int rid, 44398f8e6c0SBenno Rice struct resource *res) 44498f8e6c0SBenno Rice { 44598f8e6c0SBenno Rice void *p; 446714aa5b9SAndrew Gallatin struct uninorth_softc *sc; 447714aa5b9SAndrew Gallatin 448714aa5b9SAndrew Gallatin sc = device_get_softc(bus); 44998f8e6c0SBenno Rice 45098f8e6c0SBenno Rice if (type == SYS_RES_IRQ) 45198f8e6c0SBenno Rice return (bus_activate_resource(bus, type, rid, res)); 45298f8e6c0SBenno Rice 453714aa5b9SAndrew Gallatin if (type == SYS_RES_MEMORY || type == SYS_RES_IOPORT) { 454714aa5b9SAndrew Gallatin vm_offset_t start; 455714aa5b9SAndrew Gallatin 456714aa5b9SAndrew Gallatin start = (vm_offset_t)rman_get_start(res); 457714aa5b9SAndrew Gallatin /* 458714aa5b9SAndrew Gallatin * For i/o-ports, convert the start address to the 459714aa5b9SAndrew Gallatin * uninorth PCI i/o window 460714aa5b9SAndrew Gallatin */ 461714aa5b9SAndrew Gallatin if (type == SYS_RES_IOPORT) 462714aa5b9SAndrew Gallatin start += sc->sc_iostart; 463714aa5b9SAndrew Gallatin 464714aa5b9SAndrew Gallatin if (bootverbose) 465714aa5b9SAndrew Gallatin printf("uninorth mapdev: start %x, len %ld\n", start, 466714aa5b9SAndrew Gallatin rman_get_size(res)); 467714aa5b9SAndrew Gallatin 468714aa5b9SAndrew Gallatin p = pmap_mapdev(start, (vm_size_t)rman_get_size(res)); 46998f8e6c0SBenno Rice if (p == NULL) 47098f8e6c0SBenno Rice return (ENOMEM); 47198f8e6c0SBenno Rice rman_set_virtual(res, p); 47269643a41SMarcel Moolenaar rman_set_bustag(res, &bs_le_tag); 47398f8e6c0SBenno Rice rman_set_bushandle(res, (u_long)p); 47498f8e6c0SBenno Rice } 47598f8e6c0SBenno Rice 47698f8e6c0SBenno Rice return (rman_activate_resource(res)); 47798f8e6c0SBenno Rice } 47898f8e6c0SBenno Rice 47998f8e6c0SBenno Rice static int 48098f8e6c0SBenno Rice uninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot, 48198f8e6c0SBenno Rice u_int func, u_int reg) 48298f8e6c0SBenno Rice { 483739211f0SPeter Grehan uint32_t cfgval; 484739211f0SPeter Grehan uint32_t pass; 485739211f0SPeter Grehan 486739211f0SPeter Grehan if (resource_int_value(device_get_name(sc->sc_dev), 487739211f0SPeter Grehan device_get_unit(sc->sc_dev), "skipslot", &pass) == 0) { 488739211f0SPeter Grehan if (pass == slot) 489739211f0SPeter Grehan return (0); 490739211f0SPeter Grehan } 49198f8e6c0SBenno Rice 49298f8e6c0SBenno Rice if (sc->sc_bus == bus) { 49398f8e6c0SBenno Rice /* 49498f8e6c0SBenno Rice * No slots less than 11 on the primary bus 49598f8e6c0SBenno Rice */ 49698f8e6c0SBenno Rice if (slot < 11) 49798f8e6c0SBenno Rice return (0); 49898f8e6c0SBenno Rice 49998f8e6c0SBenno Rice cfgval = (1 << slot) | (func << 8) | (reg & 0xfc); 50098f8e6c0SBenno Rice } else { 50198f8e6c0SBenno Rice cfgval = (bus << 16) | (slot << 11) | (func << 8) | 50298f8e6c0SBenno Rice (reg & 0xfc) | 1; 50398f8e6c0SBenno Rice } 50498f8e6c0SBenno Rice 50598f8e6c0SBenno Rice do { 50698f8e6c0SBenno Rice out32rb(sc->sc_addr, cfgval); 50798f8e6c0SBenno Rice } while (in32rb(sc->sc_addr) != cfgval); 50898f8e6c0SBenno Rice 50998f8e6c0SBenno Rice return (1); 51098f8e6c0SBenno Rice } 51198f8e6c0SBenno Rice 51251d163d3SNathan Whitehorn static phandle_t 51351d163d3SNathan Whitehorn uninorth_get_node(device_t bus, device_t dev) 51451d163d3SNathan Whitehorn { 51551d163d3SNathan Whitehorn struct uninorth_softc *sc; 51651d163d3SNathan Whitehorn 51751d163d3SNathan Whitehorn sc = device_get_softc(bus); 51851d163d3SNathan Whitehorn /* We only have one child, the PCI bus, which needs our own node. */ 51951d163d3SNathan Whitehorn 52051d163d3SNathan Whitehorn return sc->sc_node; 52151d163d3SNathan Whitehorn } 52251d163d3SNathan Whitehorn 52398f8e6c0SBenno Rice /* 52498f8e6c0SBenno Rice * Driver to swallow UniNorth host bridges from the PCI bus side. 52598f8e6c0SBenno Rice */ 52698f8e6c0SBenno Rice static int 52798f8e6c0SBenno Rice unhb_probe(device_t dev) 52898f8e6c0SBenno Rice { 52998f8e6c0SBenno Rice 53098f8e6c0SBenno Rice if (pci_get_class(dev) == PCIC_BRIDGE && 53198f8e6c0SBenno Rice pci_get_subclass(dev) == PCIS_BRIDGE_HOST) { 53298f8e6c0SBenno Rice device_set_desc(dev, "Host to PCI bridge"); 53398f8e6c0SBenno Rice device_quiet(dev); 53498f8e6c0SBenno Rice return (-10000); 53598f8e6c0SBenno Rice } 53698f8e6c0SBenno Rice 53798f8e6c0SBenno Rice return (ENXIO); 53898f8e6c0SBenno Rice } 53998f8e6c0SBenno Rice 54098f8e6c0SBenno Rice static int 54198f8e6c0SBenno Rice unhb_attach(device_t dev) 54298f8e6c0SBenno Rice { 54398f8e6c0SBenno Rice 54498f8e6c0SBenno Rice return (0); 54598f8e6c0SBenno Rice } 54698f8e6c0SBenno Rice 54798f8e6c0SBenno Rice static device_method_t unhb_methods[] = { 54898f8e6c0SBenno Rice /* Device interface */ 54998f8e6c0SBenno Rice DEVMETHOD(device_probe, unhb_probe), 55098f8e6c0SBenno Rice DEVMETHOD(device_attach, unhb_attach), 55198f8e6c0SBenno Rice 55298f8e6c0SBenno Rice { 0, 0 } 55398f8e6c0SBenno Rice }; 55498f8e6c0SBenno Rice 55598f8e6c0SBenno Rice static driver_t unhb_driver = { 55698f8e6c0SBenno Rice "unhb", 55798f8e6c0SBenno Rice unhb_methods, 55898f8e6c0SBenno Rice 1, 55998f8e6c0SBenno Rice }; 56098f8e6c0SBenno Rice static devclass_t unhb_devclass; 56198f8e6c0SBenno Rice 56298f8e6c0SBenno Rice DRIVER_MODULE(unhb, pci, unhb_driver, unhb_devclass, 0, 0); 563d48bbef3SPeter Grehan 564d48bbef3SPeter Grehan 565d48bbef3SPeter Grehan /* 566d48bbef3SPeter Grehan * Small stub driver for the Uninorth chip itself, to allow setting 567d48bbef3SPeter Grehan * of various parameters and cell enables 568d48bbef3SPeter Grehan */ 569d48bbef3SPeter Grehan static struct unin_chip_softc *uncsc; 570d48bbef3SPeter Grehan 571d48bbef3SPeter Grehan static void 572d48bbef3SPeter Grehan unin_enable_gmac(void) 573d48bbef3SPeter Grehan { 574d48bbef3SPeter Grehan volatile u_int *clkreg; 575d48bbef3SPeter Grehan u_int32_t tmpl; 576d48bbef3SPeter Grehan 577d48bbef3SPeter Grehan if (uncsc == NULL) 578d48bbef3SPeter Grehan panic("unin_enable_gmac: device not found"); 579d48bbef3SPeter Grehan 580d48bbef3SPeter Grehan clkreg = (void *)(uncsc->sc_addr + UNIN_CLOCKCNTL); 581d48bbef3SPeter Grehan tmpl = inl(clkreg); 582d48bbef3SPeter Grehan tmpl |= UNIN_CLOCKCNTL_GMAC; 583d48bbef3SPeter Grehan outl(clkreg, tmpl); 584d48bbef3SPeter Grehan } 585d48bbef3SPeter Grehan 586d48bbef3SPeter Grehan static int 587d48bbef3SPeter Grehan unin_chip_probe(device_t dev) 588d48bbef3SPeter Grehan { 58951d163d3SNathan Whitehorn const char *name; 590d48bbef3SPeter Grehan 59151d163d3SNathan Whitehorn name = ofw_bus_get_name(dev); 592d48bbef3SPeter Grehan 593d48bbef3SPeter Grehan if (name == NULL) 594d48bbef3SPeter Grehan return (ENXIO); 595d48bbef3SPeter Grehan 596d48bbef3SPeter Grehan if (strcmp(name, "uni-n") != 0) 597d48bbef3SPeter Grehan return (ENXIO); 598d48bbef3SPeter Grehan 599d48bbef3SPeter Grehan device_set_desc(dev, "Apple UniNorth System Controller"); 600d48bbef3SPeter Grehan return (0); 601d48bbef3SPeter Grehan } 602d48bbef3SPeter Grehan 603d48bbef3SPeter Grehan static int 604d48bbef3SPeter Grehan unin_chip_attach(device_t dev) 605d48bbef3SPeter Grehan { 606d48bbef3SPeter Grehan phandle_t node; 607d48bbef3SPeter Grehan u_int reg[2]; 608d48bbef3SPeter Grehan 609d48bbef3SPeter Grehan uncsc = device_get_softc(dev); 61051d163d3SNathan Whitehorn node = ofw_bus_get_node(dev); 611d48bbef3SPeter Grehan 612d48bbef3SPeter Grehan if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 613d48bbef3SPeter Grehan return (ENXIO); 614d48bbef3SPeter Grehan 615d48bbef3SPeter Grehan uncsc->sc_physaddr = reg[0]; 616d48bbef3SPeter Grehan uncsc->sc_size = reg[1]; 617d48bbef3SPeter Grehan 618d48bbef3SPeter Grehan /* 619d48bbef3SPeter Grehan * Only map the first page, since that is where the registers 620d48bbef3SPeter Grehan * of interest lie. 621d48bbef3SPeter Grehan */ 622d48bbef3SPeter Grehan uncsc->sc_addr = (vm_offset_t) pmap_mapdev(reg[0], PAGE_SIZE); 623d48bbef3SPeter Grehan 624d48bbef3SPeter Grehan uncsc->sc_version = *(u_int *)uncsc->sc_addr; 625d48bbef3SPeter Grehan device_printf(dev, "Version %d\n", uncsc->sc_version); 626d48bbef3SPeter Grehan 627d48bbef3SPeter Grehan return (0); 628d48bbef3SPeter Grehan } 629d48bbef3SPeter Grehan 630d48bbef3SPeter Grehan static device_method_t unin_chip_methods[] = { 631d48bbef3SPeter Grehan /* Device interface */ 632d48bbef3SPeter Grehan DEVMETHOD(device_probe, unin_chip_probe), 633d48bbef3SPeter Grehan DEVMETHOD(device_attach, unin_chip_attach), 634d48bbef3SPeter Grehan 635d48bbef3SPeter Grehan { 0, 0 } 636d48bbef3SPeter Grehan }; 637d48bbef3SPeter Grehan 638d48bbef3SPeter Grehan static driver_t unin_chip_driver = { 639d48bbef3SPeter Grehan "unin", 640d48bbef3SPeter Grehan unin_chip_methods, 641d48bbef3SPeter Grehan sizeof(struct unin_chip_softc) 642d48bbef3SPeter Grehan }; 643d48bbef3SPeter Grehan 644d48bbef3SPeter Grehan static devclass_t unin_chip_devclass; 645d48bbef3SPeter Grehan 646d48bbef3SPeter Grehan DRIVER_MODULE(unin, nexus, unin_chip_driver, unin_chip_devclass, 0, 0); 647d48bbef3SPeter Grehan 648d48bbef3SPeter Grehan 649d48bbef3SPeter Grehan 650d48bbef3SPeter Grehan 651