1194763Smarius/*- 2194763Smarius * Copyright (C) 2001 Eduardo Horvath. 3194763Smarius * Copyright (c) 2007 Marius Strobl <marius@FreeBSD.org> 4194763Smarius * All rights reserved. 5194763Smarius * 6194763Smarius * 7194763Smarius * Redistribution and use in source and binary forms, with or without 8194763Smarius * modification, are permitted provided that the following conditions 9194763Smarius * are met: 10194763Smarius * 1. Redistributions of source code must retain the above copyright 11194763Smarius * notice, this list of conditions and the following disclaimer. 12194763Smarius * 2. Redistributions in binary form must reproduce the above copyright 13194763Smarius * notice, this list of conditions and the following disclaimer in the 14194763Smarius * documentation and/or other materials provided with the distribution. 15194763Smarius * 16194763Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 17194763Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18194763Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19194763Smarius * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 20194763Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21194763Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22194763Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23194763Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24194763Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25194763Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26194763Smarius * SUCH DAMAGE. 27194763Smarius * 28194763Smarius * from: NetBSD: if_gem_pci.c,v 1.7 2001/10/18 15:09:15 thorpej Exp 29194763Smarius */ 30194763Smarius 31194763Smarius#include <sys/cdefs.h> 32194763Smarius__FBSDID("$FreeBSD$"); 33194763Smarius 34194763Smarius/* 35194763Smarius * SBus bindings for Sun GEM Ethernet controllers 36194763Smarius */ 37194763Smarius 38194763Smarius#include <sys/param.h> 39194763Smarius#include <sys/systm.h> 40194763Smarius#include <sys/bus.h> 41194763Smarius#include <sys/kernel.h> 42194763Smarius#include <sys/lock.h> 43194763Smarius#include <sys/module.h> 44194763Smarius#include <sys/mutex.h> 45194763Smarius#include <sys/resource.h> 46194763Smarius#include <sys/rman.h> 47194763Smarius#include <sys/socket.h> 48194763Smarius 49194763Smarius#include <net/ethernet.h> 50194763Smarius#include <net/if.h> 51194763Smarius 52194763Smarius#include <dev/ofw/ofw_bus.h> 53194763Smarius 54194763Smarius#include <machine/bus.h> 55194763Smarius#include <machine/ofw_machdep.h> 56194763Smarius#include <machine/resource.h> 57194763Smarius 58194763Smarius#include <sparc64/sbus/sbusvar.h> 59194763Smarius 60194763Smarius#include <dev/gem/if_gemreg.h> 61194763Smarius#include <dev/gem/if_gemvar.h> 62194763Smarius 63194763Smarius#include "miibus_if.h" 64194763Smarius 65194763Smariusstatic device_probe_t gem_sbus_probe; 66194763Smariusstatic device_attach_t gem_sbus_attach; 67194763Smariusstatic device_detach_t gem_sbus_detach; 68194763Smariusstatic device_suspend_t gem_sbus_suspend; 69194763Smariusstatic device_resume_t gem_sbus_resume; 70194763Smarius 71194763Smariusstatic device_method_t gem_sbus_methods[] = { 72194763Smarius /* Device interface */ 73194763Smarius DEVMETHOD(device_probe, gem_sbus_probe), 74194763Smarius DEVMETHOD(device_attach, gem_sbus_attach), 75194763Smarius DEVMETHOD(device_detach, gem_sbus_detach), 76194763Smarius DEVMETHOD(device_suspend, gem_sbus_suspend), 77194763Smarius DEVMETHOD(device_resume, gem_sbus_resume), 78194763Smarius /* Use the suspend handler here, it is all that is required. */ 79194763Smarius DEVMETHOD(device_shutdown, gem_sbus_suspend), 80194763Smarius 81194763Smarius /* MII interface */ 82194763Smarius DEVMETHOD(miibus_readreg, gem_mii_readreg), 83194763Smarius DEVMETHOD(miibus_writereg, gem_mii_writereg), 84194763Smarius DEVMETHOD(miibus_statchg, gem_mii_statchg), 85194763Smarius 86227843Smarius DEVMETHOD_END 87194763Smarius}; 88194763Smarius 89194763Smariusstatic driver_t gem_sbus_driver = { 90194763Smarius "gem", 91194763Smarius gem_sbus_methods, 92194763Smarius sizeof(struct gem_softc) 93194763Smarius}; 94194763Smarius 95194763SmariusDRIVER_MODULE(gem, sbus, gem_sbus_driver, gem_devclass, 0, 0); 96194763SmariusMODULE_DEPEND(gem, sbus, 1, 1, 1); 97194763SmariusMODULE_DEPEND(gem, ether, 1, 1, 1); 98194763Smarius 99194763Smariusstatic int 100194763Smariusgem_sbus_probe(device_t dev) 101194763Smarius{ 102194763Smarius 103194763Smarius if (strcmp(ofw_bus_get_name(dev), "network") == 0 && 104194763Smarius ofw_bus_get_compat(dev) != NULL && 105194763Smarius strcmp(ofw_bus_get_compat(dev), "SUNW,sbus-gem") == 0) { 106194763Smarius device_set_desc(dev, "Sun GEM Gigabit Ethernet"); 107194763Smarius return (0); 108194763Smarius } 109194763Smarius 110194763Smarius return (ENXIO); 111194763Smarius} 112194763Smarius 113194763Smariusstatic struct resource_spec gem_sbus_res_spec[] = { 114194763Smarius { SYS_RES_IRQ, 0, RF_SHAREABLE | RF_ACTIVE }, /* GEM_RES_INTR */ 115194763Smarius { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* GEM_RES_BANK1 */ 116194763Smarius { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* GEM_RES_BANK2 */ 117194763Smarius { -1, 0 } 118194763Smarius}; 119194763Smarius 120194763Smariusstatic int 121194763Smariusgem_sbus_attach(device_t dev) 122194763Smarius{ 123194763Smarius struct gem_softc *sc; 124194763Smarius int burst; 125194763Smarius uint32_t val; 126194763Smarius 127194763Smarius sc = device_get_softc(dev); 128194763Smarius sc->sc_variant = GEM_SUN_GEM; 129194763Smarius sc->sc_dev = dev; 130212725Smarius /* All known SBus models use a SERDES. */ 131212725Smarius sc->sc_flags = GEM_SERDES; 132194763Smarius 133194763Smarius if (bus_alloc_resources(dev, gem_sbus_res_spec, sc->sc_res)) { 134194763Smarius device_printf(dev, "failed to allocate resources\n"); 135194763Smarius bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res); 136194763Smarius return (ENXIO); 137194763Smarius } 138194763Smarius 139194763Smarius GEM_LOCK_INIT(sc, device_get_nameunit(dev)); 140194763Smarius 141194763Smarius OF_getetheraddr(dev, sc->sc_enaddr); 142194763Smarius 143194763Smarius burst = sbus_get_burstsz(dev); 144194763Smarius val = GEM_SBUS_CFG_PARITY; 145194763Smarius if ((burst & SBUS_BURST64_MASK) != 0) { 146194763Smarius val |= GEM_SBUS_CFG_64BIT; 147194763Smarius burst >>= SBUS_BURST64_SHIFT; 148194763Smarius } 149194763Smarius if ((burst & SBUS_BURST_64) != 0) 150194763Smarius val |= GEM_SBUS_CFG_BURST_64; 151194763Smarius else if ((burst & SBUS_BURST_32) != 0) 152194763Smarius val |= GEM_SBUS_CFG_BURST_32; 153194763Smarius else { 154194763Smarius device_printf(dev, "unsupported burst size\n"); 155194763Smarius goto fail; 156194763Smarius } 157194763Smarius /* Reset the SBus interface only. */ 158194763Smarius (void)GEM_BANK2_READ_4(sc, GEM_SBUS_BIF_RESET); 159194763Smarius DELAY(100); 160194763Smarius GEM_BANK2_WRITE_4(sc, GEM_SBUS_CONFIG, val); 161194763Smarius 162194763Smarius if (gem_attach(sc) != 0) { 163194763Smarius device_printf(dev, "could not be attached\n"); 164194763Smarius goto fail; 165194763Smarius } 166194763Smarius 167194763Smarius if (bus_setup_intr(dev, sc->sc_res[GEM_RES_INTR], INTR_TYPE_NET | 168194763Smarius INTR_MPSAFE, NULL, gem_intr, sc, &sc->sc_ih) != 0) { 169194763Smarius device_printf(dev, "failed to set up interrupt\n"); 170194763Smarius gem_detach(sc); 171194763Smarius goto fail; 172194763Smarius } 173194763Smarius return (0); 174194763Smarius 175194763Smarius fail: 176194763Smarius GEM_LOCK_DESTROY(sc); 177194763Smarius bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res); 178194763Smarius return (ENXIO); 179194763Smarius} 180194763Smarius 181194763Smariusstatic int 182194763Smariusgem_sbus_detach(device_t dev) 183194763Smarius{ 184194763Smarius struct gem_softc *sc; 185194763Smarius 186194763Smarius sc = device_get_softc(dev); 187194763Smarius bus_teardown_intr(dev, sc->sc_res[GEM_RES_INTR], sc->sc_ih); 188194763Smarius gem_detach(sc); 189194763Smarius GEM_LOCK_DESTROY(sc); 190194763Smarius bus_release_resources(dev, gem_sbus_res_spec, sc->sc_res); 191194763Smarius return (0); 192194763Smarius} 193194763Smarius 194194763Smariusstatic int 195194763Smariusgem_sbus_suspend(device_t dev) 196194763Smarius{ 197194763Smarius 198194763Smarius gem_suspend(device_get_softc(dev)); 199194763Smarius return (0); 200194763Smarius} 201194763Smarius 202194763Smariusstatic int 203194763Smariusgem_sbus_resume(device_t dev) 204194763Smarius{ 205194763Smarius 206194763Smarius gem_resume(device_get_softc(dev)); 207194763Smarius return (0); 208194763Smarius} 209