1208149Snwhitehorn/*- 2208149Snwhitehorn * Copyright (C) 2002 Benno Rice. 3208149Snwhitehorn * All rights reserved. 4208149Snwhitehorn * 5208149Snwhitehorn * Redistribution and use in source and binary forms, with or without 6208149Snwhitehorn * modification, are permitted provided that the following conditions 7208149Snwhitehorn * are met: 8208149Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9208149Snwhitehorn * notice, this list of conditions and the following disclaimer. 10208149Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11208149Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12208149Snwhitehorn * documentation and/or other materials provided with the distribution. 13208149Snwhitehorn * 14208149Snwhitehorn * THIS SOFTWARE IS PROVIDED BY Benno Rice ``AS IS'' AND ANY EXPRESS OR 15208149Snwhitehorn * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16208149Snwhitehorn * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17208149Snwhitehorn * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18208149Snwhitehorn * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19208149Snwhitehorn * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 20208149Snwhitehorn * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 21208149Snwhitehorn * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 22208149Snwhitehorn * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 23208149Snwhitehorn * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24208149Snwhitehorn */ 25208149Snwhitehorn 26227843Smarius#include <sys/cdefs.h> 27227843Smarius__FBSDID("$FreeBSD$"); 28227843Smarius 29208149Snwhitehorn#include <sys/param.h> 30208149Snwhitehorn#include <sys/systm.h> 31208149Snwhitehorn#include <sys/module.h> 32208149Snwhitehorn#include <sys/bus.h> 33208149Snwhitehorn#include <sys/conf.h> 34208149Snwhitehorn#include <sys/kernel.h> 35208149Snwhitehorn 36208149Snwhitehorn#include <dev/ofw/openfirm.h> 37208149Snwhitehorn#include <dev/ofw/ofw_pci.h> 38208149Snwhitehorn#include <dev/ofw/ofw_bus.h> 39208149Snwhitehorn#include <dev/ofw/ofw_bus_subr.h> 40208149Snwhitehorn 41208149Snwhitehorn#include <dev/pci/pcivar.h> 42208149Snwhitehorn#include <dev/pci/pcireg.h> 43208149Snwhitehorn 44208149Snwhitehorn#include <machine/bus.h> 45208149Snwhitehorn#include <machine/intr_machdep.h> 46208149Snwhitehorn#include <machine/md_var.h> 47208149Snwhitehorn#include <machine/pio.h> 48208149Snwhitehorn#include <machine/resource.h> 49208149Snwhitehorn 50208149Snwhitehorn#include <sys/rman.h> 51208149Snwhitehorn 52230993Snwhitehorn#include <powerpc/ofw/ofw_pci.h> 53208149Snwhitehorn#include <powerpc/powermac/uninorthvar.h> 54208149Snwhitehorn 55208149Snwhitehorn#include <vm/vm.h> 56208149Snwhitehorn#include <vm/pmap.h> 57208149Snwhitehorn 58208149Snwhitehorn#include "pcib_if.h" 59208149Snwhitehorn 60208149Snwhitehorn#define UNINORTH_DEBUG 0 61208149Snwhitehorn 62208149Snwhitehorn/* 63208149Snwhitehorn * Device interface. 64208149Snwhitehorn */ 65208149Snwhitehornstatic int uninorth_probe(device_t); 66208149Snwhitehornstatic int uninorth_attach(device_t); 67208149Snwhitehorn 68208149Snwhitehorn/* 69208149Snwhitehorn * pcib interface. 70208149Snwhitehorn */ 71208149Snwhitehornstatic u_int32_t uninorth_read_config(device_t, u_int, u_int, u_int, 72208149Snwhitehorn u_int, int); 73208149Snwhitehornstatic void uninorth_write_config(device_t, u_int, u_int, u_int, 74208149Snwhitehorn u_int, u_int32_t, int); 75208149Snwhitehorn 76208149Snwhitehorn/* 77208149Snwhitehorn * Local routines. 78208149Snwhitehorn */ 79208149Snwhitehornstatic int uninorth_enable_config(struct uninorth_softc *, u_int, 80208149Snwhitehorn u_int, u_int, u_int); 81208149Snwhitehorn 82208149Snwhitehorn/* 83208149Snwhitehorn * Driver methods. 84208149Snwhitehorn */ 85208149Snwhitehornstatic device_method_t uninorth_methods[] = { 86208149Snwhitehorn /* Device interface */ 87208149Snwhitehorn DEVMETHOD(device_probe, uninorth_probe), 88208149Snwhitehorn DEVMETHOD(device_attach, uninorth_attach), 89208149Snwhitehorn 90208149Snwhitehorn /* pcib interface */ 91208149Snwhitehorn DEVMETHOD(pcib_read_config, uninorth_read_config), 92208149Snwhitehorn DEVMETHOD(pcib_write_config, uninorth_write_config), 93208149Snwhitehorn 94227843Smarius DEVMETHOD_END 95208149Snwhitehorn}; 96208149Snwhitehorn 97208149Snwhitehornstatic devclass_t uninorth_devclass; 98208149Snwhitehorn 99230993SnwhitehornDEFINE_CLASS_1(pcib, uninorth_driver, uninorth_methods, 100230993Snwhitehorn sizeof(struct uninorth_softc), ofw_pci_driver); 101208149SnwhitehornDRIVER_MODULE(uninorth, nexus, uninorth_driver, uninorth_devclass, 0, 0); 102208149Snwhitehorn 103208149Snwhitehornstatic int 104208149Snwhitehornuninorth_probe(device_t dev) 105208149Snwhitehorn{ 106208149Snwhitehorn const char *type, *compatible; 107208149Snwhitehorn 108208149Snwhitehorn type = ofw_bus_get_type(dev); 109208149Snwhitehorn compatible = ofw_bus_get_compat(dev); 110208149Snwhitehorn 111208149Snwhitehorn if (type == NULL || compatible == NULL) 112208149Snwhitehorn return (ENXIO); 113208149Snwhitehorn 114208149Snwhitehorn if (strcmp(type, "pci") != 0) 115208149Snwhitehorn return (ENXIO); 116208149Snwhitehorn 117208149Snwhitehorn if (strcmp(compatible, "uni-north") == 0) { 118208149Snwhitehorn device_set_desc(dev, "Apple UniNorth Host-PCI bridge"); 119208149Snwhitehorn return (0); 120208149Snwhitehorn } else if (strcmp(compatible, "u3-agp") == 0) { 121208149Snwhitehorn device_set_desc(dev, "Apple U3 Host-AGP bridge"); 122208149Snwhitehorn return (0); 123208149Snwhitehorn } else if (strcmp(compatible, "u4-pcie") == 0) { 124208149Snwhitehorn device_set_desc(dev, "IBM CPC945 PCI Express Root"); 125208149Snwhitehorn return (0); 126208149Snwhitehorn } 127208149Snwhitehorn 128208149Snwhitehorn return (ENXIO); 129208149Snwhitehorn} 130208149Snwhitehorn 131208149Snwhitehornstatic int 132208149Snwhitehornuninorth_attach(device_t dev) 133208149Snwhitehorn{ 134208149Snwhitehorn struct uninorth_softc *sc; 135208149Snwhitehorn const char *compatible; 136208149Snwhitehorn phandle_t node; 137230993Snwhitehorn u_int32_t reg[3]; 138208149Snwhitehorn 139208149Snwhitehorn node = ofw_bus_get_node(dev); 140208149Snwhitehorn sc = device_get_softc(dev); 141208149Snwhitehorn 142208149Snwhitehorn if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 143208149Snwhitehorn return (ENXIO); 144208149Snwhitehorn 145208149Snwhitehorn sc->sc_ver = 0; 146208149Snwhitehorn compatible = ofw_bus_get_compat(dev); 147208149Snwhitehorn if (strcmp(compatible, "u3-agp") == 0) 148208149Snwhitehorn sc->sc_ver = 3; 149208149Snwhitehorn if (strcmp(compatible, "u4-pcie") == 0) 150208149Snwhitehorn sc->sc_ver = 4; 151208149Snwhitehorn 152208149Snwhitehorn if (sc->sc_ver >= 3) { 153208149Snwhitehorn sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[1] + 0x800000, PAGE_SIZE); 154208149Snwhitehorn sc->sc_data = (vm_offset_t)pmap_mapdev(reg[1] + 0xc00000, PAGE_SIZE); 155208149Snwhitehorn } else { 156208149Snwhitehorn sc->sc_addr = (vm_offset_t)pmap_mapdev(reg[0] + 0x800000, PAGE_SIZE); 157208149Snwhitehorn sc->sc_data = (vm_offset_t)pmap_mapdev(reg[0] + 0xc00000, PAGE_SIZE); 158208149Snwhitehorn } 159208149Snwhitehorn 160230993Snwhitehorn return (ofw_pci_attach(dev)); 161208149Snwhitehorn} 162208149Snwhitehorn 163208149Snwhitehornstatic u_int32_t 164208149Snwhitehornuninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 165208149Snwhitehorn int width) 166208149Snwhitehorn{ 167208149Snwhitehorn struct uninorth_softc *sc; 168208149Snwhitehorn vm_offset_t caoff; 169208149Snwhitehorn 170208149Snwhitehorn sc = device_get_softc(dev); 171208149Snwhitehorn caoff = sc->sc_data + (reg & 0x07); 172208149Snwhitehorn 173208149Snwhitehorn if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) { 174208149Snwhitehorn switch (width) { 175208149Snwhitehorn case 1: 176208149Snwhitehorn return (in8rb(caoff)); 177208149Snwhitehorn break; 178208149Snwhitehorn case 2: 179208149Snwhitehorn return (in16rb(caoff)); 180208149Snwhitehorn break; 181208149Snwhitehorn case 4: 182208149Snwhitehorn return (in32rb(caoff)); 183208149Snwhitehorn break; 184208149Snwhitehorn } 185208149Snwhitehorn } 186208149Snwhitehorn 187208149Snwhitehorn return (0xffffffff); 188208149Snwhitehorn} 189208149Snwhitehorn 190208149Snwhitehornstatic void 191208149Snwhitehornuninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func, 192208149Snwhitehorn u_int reg, u_int32_t val, int width) 193208149Snwhitehorn{ 194208149Snwhitehorn struct uninorth_softc *sc; 195208149Snwhitehorn vm_offset_t caoff; 196208149Snwhitehorn 197208149Snwhitehorn sc = device_get_softc(dev); 198208149Snwhitehorn caoff = sc->sc_data + (reg & 0x07); 199208149Snwhitehorn 200208149Snwhitehorn if (uninorth_enable_config(sc, bus, slot, func, reg)) { 201208149Snwhitehorn switch (width) { 202208149Snwhitehorn case 1: 203208149Snwhitehorn out8rb(caoff, val); 204208149Snwhitehorn break; 205208149Snwhitehorn case 2: 206208149Snwhitehorn out16rb(caoff, val); 207208149Snwhitehorn break; 208208149Snwhitehorn case 4: 209208149Snwhitehorn out32rb(caoff, val); 210208149Snwhitehorn break; 211208149Snwhitehorn } 212208149Snwhitehorn } 213208149Snwhitehorn} 214208149Snwhitehorn 215208149Snwhitehornstatic int 216208149Snwhitehornuninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot, 217208149Snwhitehorn u_int func, u_int reg) 218208149Snwhitehorn{ 219208149Snwhitehorn uint32_t cfgval; 220208149Snwhitehorn uint32_t pass; 221208149Snwhitehorn 222230993Snwhitehorn if (resource_int_value(device_get_name(sc->pci_sc.sc_dev), 223230993Snwhitehorn device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) { 224208149Snwhitehorn if (pass == slot) 225208149Snwhitehorn return (0); 226208149Snwhitehorn } 227208149Snwhitehorn 228208149Snwhitehorn /* 229208149Snwhitehorn * Issue type 0 configuration space accesses for the root bus. 230208149Snwhitehorn * 231208149Snwhitehorn * NOTE: On U4, issue only type 1 accesses. There is a secret 232208149Snwhitehorn * PCI Express <-> PCI Express bridge not present in the device tree, 233208149Snwhitehorn * and we need to route all of our configuration space through it. 234208149Snwhitehorn */ 235230993Snwhitehorn if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) { 236208149Snwhitehorn /* 237208149Snwhitehorn * No slots less than 11 on the primary bus on U3 and lower 238208149Snwhitehorn */ 239208149Snwhitehorn if (slot < 11) 240208149Snwhitehorn return (0); 241208149Snwhitehorn 242208149Snwhitehorn cfgval = (1 << slot) | (func << 8) | (reg & 0xfc); 243208149Snwhitehorn } else { 244208149Snwhitehorn cfgval = (bus << 16) | (slot << 11) | (func << 8) | 245208149Snwhitehorn (reg & 0xfc) | 1; 246208149Snwhitehorn } 247208149Snwhitehorn 248208149Snwhitehorn /* Set extended register bits on U4 */ 249208149Snwhitehorn if (sc->sc_ver == 4) 250208149Snwhitehorn cfgval |= (reg >> 8) << 28; 251208149Snwhitehorn 252208149Snwhitehorn do { 253208149Snwhitehorn out32rb(sc->sc_addr, cfgval); 254208149Snwhitehorn } while (in32rb(sc->sc_addr) != cfgval); 255208149Snwhitehorn 256208149Snwhitehorn return (1); 257208149Snwhitehorn} 258208149Snwhitehorn 259