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