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: releng/10.2/sys/powerpc/powermac/uninorthpci.c 266160 2014-05-15 17:30:16Z ian $"); 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); 101266160SianDRIVER_MODULE(uninorth, ofwbus, 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; 137266019Sian uint32_t reg[3]; 138266019Sian uint64_t regbase; 139266019Sian cell_t acells; 140208149Snwhitehorn 141208149Snwhitehorn node = ofw_bus_get_node(dev); 142208149Snwhitehorn sc = device_get_softc(dev); 143208149Snwhitehorn 144208149Snwhitehorn if (OF_getprop(node, "reg", reg, sizeof(reg)) < 8) 145208149Snwhitehorn return (ENXIO); 146208149Snwhitehorn 147208149Snwhitehorn sc->sc_ver = 0; 148208149Snwhitehorn compatible = ofw_bus_get_compat(dev); 149208149Snwhitehorn if (strcmp(compatible, "u3-agp") == 0) 150208149Snwhitehorn sc->sc_ver = 3; 151208149Snwhitehorn if (strcmp(compatible, "u4-pcie") == 0) 152208149Snwhitehorn sc->sc_ver = 4; 153208149Snwhitehorn 154266019Sian acells = 1; 155266019Sian OF_getprop(OF_parent(node), "#address-cells", &acells, sizeof(acells)); 156266019Sian 157266019Sian regbase = reg[0]; 158266019Sian if (acells == 2) { 159266019Sian regbase <<= 32; 160266019Sian regbase |= reg[1]; 161208149Snwhitehorn } 162208149Snwhitehorn 163266019Sian sc->sc_addr = (vm_offset_t)pmap_mapdev(regbase + 0x800000, PAGE_SIZE); 164266019Sian sc->sc_data = (vm_offset_t)pmap_mapdev(regbase + 0xc00000, PAGE_SIZE); 165266019Sian 166230993Snwhitehorn return (ofw_pci_attach(dev)); 167208149Snwhitehorn} 168208149Snwhitehorn 169208149Snwhitehornstatic u_int32_t 170208149Snwhitehornuninorth_read_config(device_t dev, u_int bus, u_int slot, u_int func, u_int reg, 171208149Snwhitehorn int width) 172208149Snwhitehorn{ 173208149Snwhitehorn struct uninorth_softc *sc; 174208149Snwhitehorn vm_offset_t caoff; 175208149Snwhitehorn 176208149Snwhitehorn sc = device_get_softc(dev); 177208149Snwhitehorn caoff = sc->sc_data + (reg & 0x07); 178208149Snwhitehorn 179208149Snwhitehorn if (uninorth_enable_config(sc, bus, slot, func, reg) != 0) { 180208149Snwhitehorn switch (width) { 181208149Snwhitehorn case 1: 182208149Snwhitehorn return (in8rb(caoff)); 183208149Snwhitehorn break; 184208149Snwhitehorn case 2: 185208149Snwhitehorn return (in16rb(caoff)); 186208149Snwhitehorn break; 187208149Snwhitehorn case 4: 188208149Snwhitehorn return (in32rb(caoff)); 189208149Snwhitehorn break; 190208149Snwhitehorn } 191208149Snwhitehorn } 192208149Snwhitehorn 193208149Snwhitehorn return (0xffffffff); 194208149Snwhitehorn} 195208149Snwhitehorn 196208149Snwhitehornstatic void 197208149Snwhitehornuninorth_write_config(device_t dev, u_int bus, u_int slot, u_int func, 198208149Snwhitehorn u_int reg, u_int32_t val, int width) 199208149Snwhitehorn{ 200208149Snwhitehorn struct uninorth_softc *sc; 201208149Snwhitehorn vm_offset_t caoff; 202208149Snwhitehorn 203208149Snwhitehorn sc = device_get_softc(dev); 204208149Snwhitehorn caoff = sc->sc_data + (reg & 0x07); 205208149Snwhitehorn 206208149Snwhitehorn if (uninorth_enable_config(sc, bus, slot, func, reg)) { 207208149Snwhitehorn switch (width) { 208208149Snwhitehorn case 1: 209208149Snwhitehorn out8rb(caoff, val); 210208149Snwhitehorn break; 211208149Snwhitehorn case 2: 212208149Snwhitehorn out16rb(caoff, val); 213208149Snwhitehorn break; 214208149Snwhitehorn case 4: 215208149Snwhitehorn out32rb(caoff, val); 216208149Snwhitehorn break; 217208149Snwhitehorn } 218208149Snwhitehorn } 219208149Snwhitehorn} 220208149Snwhitehorn 221208149Snwhitehornstatic int 222208149Snwhitehornuninorth_enable_config(struct uninorth_softc *sc, u_int bus, u_int slot, 223208149Snwhitehorn u_int func, u_int reg) 224208149Snwhitehorn{ 225208149Snwhitehorn uint32_t cfgval; 226208149Snwhitehorn uint32_t pass; 227208149Snwhitehorn 228230993Snwhitehorn if (resource_int_value(device_get_name(sc->pci_sc.sc_dev), 229230993Snwhitehorn device_get_unit(sc->pci_sc.sc_dev), "skipslot", &pass) == 0) { 230208149Snwhitehorn if (pass == slot) 231208149Snwhitehorn return (0); 232208149Snwhitehorn } 233208149Snwhitehorn 234208149Snwhitehorn /* 235208149Snwhitehorn * Issue type 0 configuration space accesses for the root bus. 236208149Snwhitehorn * 237208149Snwhitehorn * NOTE: On U4, issue only type 1 accesses. There is a secret 238208149Snwhitehorn * PCI Express <-> PCI Express bridge not present in the device tree, 239208149Snwhitehorn * and we need to route all of our configuration space through it. 240208149Snwhitehorn */ 241230993Snwhitehorn if (sc->pci_sc.sc_bus == bus && sc->sc_ver < 4) { 242208149Snwhitehorn /* 243208149Snwhitehorn * No slots less than 11 on the primary bus on U3 and lower 244208149Snwhitehorn */ 245208149Snwhitehorn if (slot < 11) 246208149Snwhitehorn return (0); 247208149Snwhitehorn 248208149Snwhitehorn cfgval = (1 << slot) | (func << 8) | (reg & 0xfc); 249208149Snwhitehorn } else { 250208149Snwhitehorn cfgval = (bus << 16) | (slot << 11) | (func << 8) | 251208149Snwhitehorn (reg & 0xfc) | 1; 252208149Snwhitehorn } 253208149Snwhitehorn 254208149Snwhitehorn /* Set extended register bits on U4 */ 255208149Snwhitehorn if (sc->sc_ver == 4) 256208149Snwhitehorn cfgval |= (reg >> 8) << 28; 257208149Snwhitehorn 258208149Snwhitehorn do { 259208149Snwhitehorn out32rb(sc->sc_addr, cfgval); 260208149Snwhitehorn } while (in32rb(sc->sc_addr) != cfgval); 261208149Snwhitehorn 262208149Snwhitehorn return (1); 263208149Snwhitehorn} 264208149Snwhitehorn 265