191396Stmm/*-
291396Stmm * Copyright (c) 1999 The NetBSD Foundation, Inc.
391396Stmm * All rights reserved.
491396Stmm *
591396Stmm * This code is derived from software contributed to The NetBSD Foundation
691396Stmm * by Paul Kranenburg.
791396Stmm *
891396Stmm * Redistribution and use in source and binary forms, with or without
991396Stmm * modification, are permitted provided that the following conditions
1091396Stmm * are met:
1191396Stmm * 1. Redistributions of source code must retain the above copyright
1291396Stmm *    notice, this list of conditions and the following disclaimer.
1391396Stmm * 2. Redistributions in binary form must reproduce the above copyright
1491396Stmm *    notice, this list of conditions and the following disclaimer in the
1591396Stmm *    documentation and/or other materials provided with the distribution.
1691396Stmm *
1791396Stmm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
1891396Stmm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
1991396Stmm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2091396Stmm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2191396Stmm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2291396Stmm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2391396Stmm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2491396Stmm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2591396Stmm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2691396Stmm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2791396Stmm * POSSIBILITY OF SUCH DAMAGE.
2891396Stmm *
29133599Smarius *	from: NetBSD: if_hme_sbus.c,v 1.19 2004/03/17 17:04:58 pk Exp
3091396Stmm */
3191396Stmm
32119418Sobrien#include <sys/cdefs.h>
33119418Sobrien__FBSDID("$FreeBSD$");
34119418Sobrien
3591396Stmm/*
3691396Stmm * SBus front-end device driver for the HME ethernet device.
3791396Stmm */
3891396Stmm
3991396Stmm#include <sys/param.h>
4091396Stmm#include <sys/systm.h>
4191396Stmm#include <sys/bus.h>
42257290Sglebius#include <sys/lock.h>
4391396Stmm#include <sys/kernel.h>
44130026Sphk#include <sys/module.h>
45257290Sglebius#include <sys/mutex.h>
4691396Stmm#include <sys/resource.h>
4791396Stmm#include <sys/socket.h>
4891396Stmm
49133589Smarius#include <dev/ofw/ofw_bus.h>
50133589Smarius
5191396Stmm#include <machine/bus.h>
5291396Stmm#include <machine/ofw_machdep.h>
5391396Stmm#include <machine/resource.h>
5491396Stmm
5591396Stmm#include <sys/rman.h>
5691396Stmm
5791396Stmm#include <net/if.h>
5891396Stmm#include <net/if_media.h>
59257290Sglebius#include <net/ethernet.h>
6091396Stmm
61119351Smarcel#include <dev/mii/mii.h>
62119351Smarcel#include <dev/mii/miivar.h>
6391396Stmm
6491396Stmm#include <sparc64/sbus/sbusvar.h>
6591396Stmm
66119351Smarcel#include <dev/hme/if_hmereg.h>
67119351Smarcel#include <dev/hme/if_hmevar.h>
6891396Stmm
6991396Stmm#include "miibus_if.h"
7091396Stmm
7191396Stmmstruct hme_sbus_softc {
7291396Stmm	struct	hme_softc	hsc_hme;	/* HME device */
7391396Stmm	struct	resource	*hsc_seb_res;
7491396Stmm	struct	resource	*hsc_etx_res;
7591396Stmm	struct	resource	*hsc_erx_res;
7691396Stmm	struct	resource	*hsc_mac_res;
7791396Stmm	struct	resource	*hsc_mif_res;
7891396Stmm	struct	resource	*hsc_ires;
7991396Stmm	void			*hsc_ih;
8091396Stmm};
8191396Stmm
8291396Stmmstatic int hme_sbus_probe(device_t);
8391396Stmmstatic int hme_sbus_attach(device_t);
84108976Stmmstatic int hme_sbus_detach(device_t);
85108976Stmmstatic int hme_sbus_suspend(device_t);
86108976Stmmstatic int hme_sbus_resume(device_t);
8791396Stmm
8891396Stmmstatic device_method_t hme_sbus_methods[] = {
8991396Stmm	/* Device interface */
9091396Stmm	DEVMETHOD(device_probe,		hme_sbus_probe),
9191396Stmm	DEVMETHOD(device_attach,	hme_sbus_attach),
92108976Stmm	DEVMETHOD(device_detach,	hme_sbus_detach),
93108976Stmm	DEVMETHOD(device_suspend,	hme_sbus_suspend),
94108976Stmm	DEVMETHOD(device_resume,	hme_sbus_resume),
95108976Stmm	/* Can just use the suspend method here. */
96108976Stmm	DEVMETHOD(device_shutdown,	hme_sbus_suspend),
9791396Stmm
9891396Stmm	/* MII interface */
9991396Stmm	DEVMETHOD(miibus_readreg,	hme_mii_readreg),
10091396Stmm	DEVMETHOD(miibus_writereg,	hme_mii_writereg),
10191396Stmm	DEVMETHOD(miibus_statchg,	hme_mii_statchg),
10291396Stmm
103227843Smarius	DEVMETHOD_END
10491396Stmm};
10591396Stmm
10691396Stmmstatic driver_t hme_sbus_driver = {
10791396Stmm	"hme",
10891396Stmm	hme_sbus_methods,
10991396Stmm	sizeof(struct hme_sbus_softc)
11091396Stmm};
11191396Stmm
112113506SmdoddDRIVER_MODULE(hme, sbus, hme_sbus_driver, hme_devclass, 0, 0);
113178589SmariusMODULE_DEPEND(hme, sbus, 1, 1, 1);
114113506SmdoddMODULE_DEPEND(hme, ether, 1, 1, 1);
11591396Stmm
11691396Stmmstatic int
11791396Stmmhme_sbus_probe(device_t dev)
11891396Stmm{
119133589Smarius	const char *name;
12091396Stmm
121133589Smarius	name = ofw_bus_get_name(dev);
12291396Stmm	if (strcmp(name, "SUNW,qfe") == 0 ||
12391396Stmm	    strcmp(name, "SUNW,hme") == 0) {
12491396Stmm		device_set_desc(dev, "Sun HME 10/100 Ethernet");
12591396Stmm		return (0);
12691396Stmm	}
12791396Stmm	return (ENXIO);
12891396Stmm}
12991396Stmm
13091396Stmmstatic int
13191396Stmmhme_sbus_attach(device_t dev)
13291396Stmm{
133178589Smarius	struct hme_sbus_softc *hsc;
134178589Smarius	struct hme_softc *sc;
13591396Stmm	u_long start, count;
136178589Smarius	uint32_t burst;
137178589Smarius	int i, error = 0;
13891396Stmm
139178589Smarius	hsc = device_get_softc(dev);
140178589Smarius	sc = &hsc->hsc_hme;
141137982Syongari	mtx_init(&sc->sc_lock, device_get_nameunit(dev), MTX_NETWORK_LOCK,
142137982Syongari	    MTX_DEF);
14391396Stmm	/*
14491396Stmm	 * Map five register banks:
14591396Stmm	 *
14691396Stmm	 *	bank 0: HME SEB registers
14791396Stmm	 *	bank 1: HME ETX registers
14891396Stmm	 *	bank 2: HME ERX registers
14991396Stmm	 *	bank 3: HME MAC registers
15091396Stmm	 *	bank 4: HME MIF registers
15191396Stmm	 *
15291396Stmm	 */
153178589Smarius	i = 0;
154127135Snjl	hsc->hsc_seb_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
155178589Smarius	    &i, RF_ACTIVE);
15691396Stmm	if (hsc->hsc_seb_res == NULL) {
15791396Stmm		device_printf(dev, "cannot map SEB registers\n");
158137982Syongari		error = ENXIO;
159137982Syongari		goto fail_mtx_res;
16091396Stmm	}
16191396Stmm	sc->sc_sebt = rman_get_bustag(hsc->hsc_seb_res);
16291396Stmm	sc->sc_sebh = rman_get_bushandle(hsc->hsc_seb_res);
16391396Stmm
164178589Smarius	i = 1;
165127135Snjl	hsc->hsc_etx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
166178589Smarius	    &i, RF_ACTIVE);
16791396Stmm	if (hsc->hsc_etx_res == NULL) {
16891396Stmm		device_printf(dev, "cannot map ETX registers\n");
169133599Smarius		error = ENXIO;
17091396Stmm		goto fail_seb_res;
17191396Stmm	}
17291396Stmm	sc->sc_etxt = rman_get_bustag(hsc->hsc_etx_res);
17391396Stmm	sc->sc_etxh = rman_get_bushandle(hsc->hsc_etx_res);
17491396Stmm
175178589Smarius	i = 2;
176127135Snjl	hsc->hsc_erx_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
177178589Smarius	    &i, RF_ACTIVE);
17891396Stmm	if (hsc->hsc_erx_res == NULL) {
17991396Stmm		device_printf(dev, "cannot map ERX registers\n");
180133599Smarius		error = ENXIO;
18191396Stmm		goto fail_etx_res;
18291396Stmm	}
18391396Stmm	sc->sc_erxt = rman_get_bustag(hsc->hsc_erx_res);
18491396Stmm	sc->sc_erxh = rman_get_bushandle(hsc->hsc_erx_res);
18591396Stmm
186178589Smarius	i = 3;
187127135Snjl	hsc->hsc_mac_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
188178589Smarius	    &i, RF_ACTIVE);
18991396Stmm	if (hsc->hsc_mac_res == NULL) {
19091396Stmm		device_printf(dev, "cannot map MAC registers\n");
191133599Smarius		error = ENXIO;
19291396Stmm		goto fail_erx_res;
19391396Stmm	}
19491396Stmm	sc->sc_mact = rman_get_bustag(hsc->hsc_mac_res);
19591396Stmm	sc->sc_mach = rman_get_bushandle(hsc->hsc_mac_res);
19691396Stmm
19791396Stmm	/*
19891396Stmm	 * At least on some HMEs, the MIF registers seem to be inside the MAC
199133599Smarius	 * range, so try to kludge around it.
20091396Stmm	 */
201178589Smarius	i = 4;
202127135Snjl	hsc->hsc_mif_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
203178589Smarius	    &i, RF_ACTIVE);
20491396Stmm	if (hsc->hsc_mif_res == NULL) {
205178589Smarius		if (bus_get_resource(dev, SYS_RES_MEMORY, i,
20691396Stmm		    &start, &count) != 0) {
20791396Stmm			device_printf(dev, "cannot get MIF registers\n");
208133599Smarius			error = ENXIO;
20991396Stmm			goto fail_mac_res;
21091396Stmm		}
21191396Stmm		if (start < rman_get_start(hsc->hsc_mac_res) ||
21291396Stmm		    start + count - 1 > rman_get_end(hsc->hsc_mac_res)) {
21391396Stmm			device_printf(dev, "cannot move MIF registers to MAC "
21491396Stmm			    "bank\n");
215133599Smarius			error = ENXIO;
21691396Stmm			goto fail_mac_res;
21791396Stmm		}
21891396Stmm		sc->sc_mift = sc->sc_mact;
219133599Smarius		bus_space_subregion(sc->sc_mact, sc->sc_mach,
220133599Smarius		    start - rman_get_start(hsc->hsc_mac_res), count,
221133599Smarius		    &sc->sc_mifh);
22291396Stmm	} else {
22391396Stmm		sc->sc_mift = rman_get_bustag(hsc->hsc_mif_res);
22491396Stmm		sc->sc_mifh = rman_get_bushandle(hsc->hsc_mif_res);
22591396Stmm	}
22691396Stmm
227178589Smarius	i = 0;
228178589Smarius	hsc->hsc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ,
229178589Smarius	    &i, RF_SHAREABLE | RF_ACTIVE);
23091396Stmm	if (hsc->hsc_ires == NULL) {
23191396Stmm		device_printf(dev, "could not allocate interrupt\n");
23291396Stmm		error = ENXIO;
23391396Stmm		goto fail_mif_res;
23491396Stmm	}
23591396Stmm
236147256Sbrooks	OF_getetheraddr(dev, sc->sc_enaddr);
23791396Stmm
23891396Stmm	burst = sbus_get_burstsz(dev);
23991396Stmm	/* Translate into plain numerical format */
240133149Syongari	if ((burst & SBUS_BURST_64))
241133149Syongari		sc->sc_burst = 64;
242133149Syongari	else if ((burst & SBUS_BURST_32))
243133149Syongari		sc->sc_burst = 32;
244133149Syongari	else if ((burst & SBUS_BURST_16))
245133149Syongari		sc->sc_burst = 16;
246133149Syongari	else
247133149Syongari		 sc->sc_burst = 0;
24891396Stmm
24991396Stmm	sc->sc_dev = dev;
250178470Smarius	sc->sc_flags = 0;
25191396Stmm
25291396Stmm	if ((error = hme_config(sc)) != 0) {
25391396Stmm		device_printf(dev, "could not be configured\n");
25491396Stmm		goto fail_ires;
25591396Stmm	}
25691396Stmm
257137982Syongari	if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET |
258166901Spiso	    INTR_MPSAFE, NULL, hme_intr, sc, &hsc->hsc_ih)) != 0) {
25991396Stmm		device_printf(dev, "couldn't establish interrupt\n");
260108976Stmm		hme_detach(sc);
26191396Stmm		goto fail_ires;
26291396Stmm	}
26391396Stmm	return (0);
26491396Stmm
26591396Stmmfail_ires:
266178589Smarius	bus_release_resource(dev, SYS_RES_IRQ,
267178589Smarius	    rman_get_rid(hsc->hsc_ires), hsc->hsc_ires);
26891396Stmmfail_mif_res:
26991396Stmm	if (hsc->hsc_mif_res != NULL) {
270178589Smarius		bus_release_resource(dev, SYS_RES_MEMORY,
271178589Smarius		    rman_get_rid(hsc->hsc_mif_res), hsc->hsc_mif_res);
27291396Stmm	}
27391396Stmmfail_mac_res:
274178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
275178589Smarius	    rman_get_rid(hsc->hsc_mac_res), hsc->hsc_mac_res);
27691396Stmmfail_erx_res:
277178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
278178589Smarius	    rman_get_rid(hsc->hsc_erx_res), hsc->hsc_erx_res);
27991396Stmmfail_etx_res:
280178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
281178589Smarius	    rman_get_rid(hsc->hsc_etx_res), hsc->hsc_etx_res);
28291396Stmmfail_seb_res:
283178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
284178589Smarius	    rman_get_rid(hsc->hsc_seb_res), hsc->hsc_seb_res);
285137982Syongarifail_mtx_res:
286137982Syongari	mtx_destroy(&sc->sc_lock);
287133599Smarius	return (error);
28891396Stmm}
289108976Stmm
290108976Stmmstatic int
291108976Stmmhme_sbus_detach(device_t dev)
292108976Stmm{
293178589Smarius	struct hme_sbus_softc *hsc;
294178589Smarius	struct hme_softc *sc;
295108976Stmm
296178589Smarius	hsc = device_get_softc(dev);
297178589Smarius	sc = &hsc->hsc_hme;
298137982Syongari	bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih);
299108976Stmm	hme_detach(sc);
300178589Smarius	bus_release_resource(dev, SYS_RES_IRQ,
301178589Smarius	    rman_get_rid(hsc->hsc_ires), hsc->hsc_ires);
302108976Stmm	if (hsc->hsc_mif_res != NULL) {
303178589Smarius		bus_release_resource(dev, SYS_RES_MEMORY,
304178589Smarius		    rman_get_rid(hsc->hsc_mif_res), hsc->hsc_mif_res);
305108976Stmm	}
306178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
307178589Smarius	    rman_get_rid(hsc->hsc_mac_res), hsc->hsc_mac_res);
308178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
309178589Smarius	    rman_get_rid(hsc->hsc_erx_res), hsc->hsc_erx_res);
310178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
311178589Smarius	    rman_get_rid(hsc->hsc_etx_res), hsc->hsc_etx_res);
312178589Smarius	bus_release_resource(dev, SYS_RES_MEMORY,
313178589Smarius	    rman_get_rid(hsc->hsc_seb_res), hsc->hsc_seb_res);
314137982Syongari	mtx_destroy(&sc->sc_lock);
315108976Stmm	return (0);
316108976Stmm}
317108976Stmm
318108976Stmmstatic int
319108976Stmmhme_sbus_suspend(device_t dev)
320108976Stmm{
321178589Smarius	struct hme_sbus_softc *hsc;
322108976Stmm
323178589Smarius	hsc = device_get_softc(dev);
324178589Smarius	hme_suspend(&hsc->hsc_hme);
325108976Stmm	return (0);
326108976Stmm}
327108976Stmm
328108976Stmmstatic int
329108976Stmmhme_sbus_resume(device_t dev)
330108976Stmm{
331178589Smarius	struct hme_sbus_softc *hsc;
332108976Stmm
333178589Smarius	hsc = device_get_softc(dev);
334178589Smarius	hme_resume(&hsc->hsc_hme);
335108976Stmm	return (0);
336108976Stmm}
337