if_hme_sbus.c revision 119418
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 * 3. All advertising materials mentioning features or use of this software
1791396Stmm *    must display the following acknowledgement:
1891396Stmm *        This product includes software developed by the NetBSD
1991396Stmm *        Foundation, Inc. and its contributors.
2091396Stmm * 4. Neither the name of The NetBSD Foundation nor the names of its
2191396Stmm *    contributors may be used to endorse or promote products derived
2291396Stmm *    from this software without specific prior written permission.
2391396Stmm *
2491396Stmm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2591396Stmm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2691396Stmm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2791396Stmm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2891396Stmm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2991396Stmm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3091396Stmm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3191396Stmm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3291396Stmm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3391396Stmm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3491396Stmm * POSSIBILITY OF SUCH DAMAGE.
3591396Stmm *
3691396Stmm *	from: NetBSD: if_hme_sbus.c,v 1.9 2001/11/13 06:58:17 lukem Exp
3791396Stmm */
3891396Stmm
39119418Sobrien#include <sys/cdefs.h>
40119418Sobrien__FBSDID("$FreeBSD: head/sys/dev/hme/if_hme_sbus.c 119418 2003-08-24 17:55:58Z obrien $");
41119418Sobrien
4291396Stmm/*
4391396Stmm * SBus front-end device driver for the HME ethernet device.
4491396Stmm */
4591396Stmm
4691396Stmm#include <sys/param.h>
4791396Stmm#include <sys/systm.h>
4891396Stmm#include <sys/bus.h>
4991396Stmm#include <sys/kernel.h>
5091396Stmm#include <sys/resource.h>
5191396Stmm#include <sys/socket.h>
5291396Stmm
5391396Stmm#include <machine/bus.h>
5491396Stmm#include <machine/ofw_machdep.h>
5591396Stmm#include <machine/resource.h>
5691396Stmm
5791396Stmm#include <sys/rman.h>
5891396Stmm
59119338Simp#include <dev/ofw/openfirm.h>
6091396Stmm
6191396Stmm#include <net/ethernet.h>
6291396Stmm#include <net/if.h>
6391396Stmm#include <net/if_arp.h>
6491396Stmm#include <net/if_dl.h>
6591396Stmm#include <net/if_media.h>
6691396Stmm
67119351Smarcel#include <dev/mii/mii.h>
68119351Smarcel#include <dev/mii/miivar.h>
6991396Stmm
7091396Stmm#include <sparc64/sbus/sbusvar.h>
7191396Stmm
72119351Smarcel#include <dev/hme/if_hmereg.h>
73119351Smarcel#include <dev/hme/if_hmevar.h>
7491396Stmm
7591396Stmm#include "miibus_if.h"
7691396Stmm
7791396Stmmstruct hme_sbus_softc {
7891396Stmm	struct	hme_softc	hsc_hme;	/* HME device */
7991396Stmm	struct	resource	*hsc_seb_res;
8091396Stmm	int			hsc_seb_rid;
8191396Stmm	struct	resource	*hsc_etx_res;
8291396Stmm	int			hsc_etx_rid;
8391396Stmm	struct	resource	*hsc_erx_res;
8491396Stmm	int			hsc_erx_rid;
8591396Stmm	struct	resource	*hsc_mac_res;
8691396Stmm	int			hsc_mac_rid;
8791396Stmm	struct	resource	*hsc_mif_res;
8891396Stmm	int			hsc_mif_rid;
8991396Stmm	struct	resource	*hsc_ires;
9091396Stmm	int			hsc_irid;
9191396Stmm	void			*hsc_ih;
9291396Stmm};
9391396Stmm
9491396Stmmstatic int hme_sbus_probe(device_t);
9591396Stmmstatic int hme_sbus_attach(device_t);
96108976Stmmstatic int hme_sbus_detach(device_t);
97108976Stmmstatic int hme_sbus_suspend(device_t);
98108976Stmmstatic int hme_sbus_resume(device_t);
9991396Stmm
10091396Stmmstatic device_method_t hme_sbus_methods[] = {
10191396Stmm	/* Device interface */
10291396Stmm	DEVMETHOD(device_probe,		hme_sbus_probe),
10391396Stmm	DEVMETHOD(device_attach,	hme_sbus_attach),
104108976Stmm	DEVMETHOD(device_detach,	hme_sbus_detach),
105108976Stmm	DEVMETHOD(device_suspend,	hme_sbus_suspend),
106108976Stmm	DEVMETHOD(device_resume,	hme_sbus_resume),
107108976Stmm	/* Can just use the suspend method here. */
108108976Stmm	DEVMETHOD(device_shutdown,	hme_sbus_suspend),
10991396Stmm
11091396Stmm	/* bus interface */
11191396Stmm	DEVMETHOD(bus_print_child,	bus_generic_print_child),
11291396Stmm	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
11391396Stmm
11491396Stmm	/* MII interface */
11591396Stmm	DEVMETHOD(miibus_readreg,	hme_mii_readreg),
11691396Stmm	DEVMETHOD(miibus_writereg,	hme_mii_writereg),
11791396Stmm	DEVMETHOD(miibus_statchg,	hme_mii_statchg),
11891396Stmm
11991396Stmm	{ 0, 0 }
12091396Stmm};
12191396Stmm
12291396Stmmstatic driver_t hme_sbus_driver = {
12391396Stmm	"hme",
12491396Stmm	hme_sbus_methods,
12591396Stmm	sizeof(struct hme_sbus_softc)
12691396Stmm};
12791396Stmm
128113506SmdoddDRIVER_MODULE(hme, sbus, hme_sbus_driver, hme_devclass, 0, 0);
129113506SmdoddMODULE_DEPEND(hme, ether, 1, 1, 1);
13091396Stmm
13191396Stmmstatic int
13291396Stmmhme_sbus_probe(device_t dev)
13391396Stmm{
13491396Stmm	char *name;
13591396Stmm
13691396Stmm	name = sbus_get_name(dev);
13791396Stmm	if (strcmp(name, "SUNW,qfe") == 0 ||
13891396Stmm	    strcmp(name, "SUNW,hme") == 0) {
13991396Stmm		device_set_desc(dev, "Sun HME 10/100 Ethernet");
14091396Stmm		return (0);
14191396Stmm	}
14291396Stmm	return (ENXIO);
14391396Stmm}
14491396Stmm
14591396Stmmstatic int
14691396Stmmhme_sbus_attach(device_t dev)
14791396Stmm{
14891396Stmm	struct hme_sbus_softc *hsc = device_get_softc(dev);
14991396Stmm	struct hme_softc *sc = &hsc->hsc_hme;
15091396Stmm	u_int32_t burst;
15191396Stmm	u_long start, count;
15291396Stmm	int error;
15391396Stmm
15491396Stmm	/*
15591396Stmm	 * Map five register banks:
15691396Stmm	 *
15791396Stmm	 *	bank 0: HME SEB registers
15891396Stmm	 *	bank 1: HME ETX registers
15991396Stmm	 *	bank 2: HME ERX registers
16091396Stmm	 *	bank 3: HME MAC registers
16191396Stmm	 *	bank 4: HME MIF registers
16291396Stmm	 *
16391396Stmm	 */
16491396Stmm	sc->sc_sebo = sc->sc_etxo = sc->sc_erxo = sc->sc_maco = sc->sc_mifo = 0;
16591396Stmm	hsc->hsc_seb_rid = 0;
16691396Stmm	hsc->hsc_seb_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
16791396Stmm	    &hsc->hsc_seb_rid, 0, ~0, 1, RF_ACTIVE);
16891396Stmm	if (hsc->hsc_seb_res == NULL) {
16991396Stmm		device_printf(dev, "cannot map SEB registers\n");
17091396Stmm		return (ENXIO);
17191396Stmm	}
17291396Stmm	sc->sc_sebt = rman_get_bustag(hsc->hsc_seb_res);
17391396Stmm	sc->sc_sebh = rman_get_bushandle(hsc->hsc_seb_res);
17491396Stmm
17591396Stmm	hsc->hsc_etx_rid = 1;
17691396Stmm	hsc->hsc_etx_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
17791396Stmm	    &hsc->hsc_etx_rid, 0, ~0, 1, RF_ACTIVE);
17891396Stmm	if (hsc->hsc_etx_res == NULL) {
17991396Stmm		device_printf(dev, "cannot map ETX registers\n");
18091396Stmm		goto fail_seb_res;
18191396Stmm	}
18291396Stmm	sc->sc_etxt = rman_get_bustag(hsc->hsc_etx_res);
18391396Stmm	sc->sc_etxh = rman_get_bushandle(hsc->hsc_etx_res);
18491396Stmm
18591396Stmm	hsc->hsc_erx_rid = 2;
18691396Stmm	hsc->hsc_erx_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
18791396Stmm	    &hsc->hsc_erx_rid, 0, ~0, 1, RF_ACTIVE);
18891396Stmm	if (hsc->hsc_erx_res == NULL) {
18991396Stmm		device_printf(dev, "cannot map ERX registers\n");
19091396Stmm		goto fail_etx_res;
19191396Stmm	}
19291396Stmm	sc->sc_erxt = rman_get_bustag(hsc->hsc_erx_res);
19391396Stmm	sc->sc_erxh = rman_get_bushandle(hsc->hsc_erx_res);
19491396Stmm
19591396Stmm	hsc->hsc_mac_rid = 3;
19691396Stmm	hsc->hsc_mac_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
19791396Stmm	    &hsc->hsc_mac_rid, 0, ~0, 1, RF_ACTIVE);
19891396Stmm	if (hsc->hsc_mac_res == NULL) {
19991396Stmm		device_printf(dev, "cannot map MAC registers\n");
20091396Stmm		goto fail_erx_res;
20191396Stmm	}
20291396Stmm	sc->sc_mact = rman_get_bustag(hsc->hsc_mac_res);
20391396Stmm	sc->sc_mach = rman_get_bushandle(hsc->hsc_mac_res);
20491396Stmm
20591396Stmm	/*
20691396Stmm	 * At least on some HMEs, the MIF registers seem to be inside the MAC
20791396Stmm	 * range, so map try to kluge around it.
20891396Stmm	 */
20991396Stmm	hsc->hsc_mif_rid = 4;
21091396Stmm	hsc->hsc_mif_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
21191396Stmm	    &hsc->hsc_mif_rid, 0, ~0, 1, RF_ACTIVE);
21291396Stmm	if (hsc->hsc_mif_res == NULL) {
21391396Stmm		if (bus_get_resource(dev, SYS_RES_MEMORY, hsc->hsc_mif_rid,
21491396Stmm		    &start, &count) != 0) {
21591396Stmm			device_printf(dev, "cannot get MIF registers\n");
21691396Stmm			goto fail_mac_res;
21791396Stmm		}
21891396Stmm		if (start < rman_get_start(hsc->hsc_mac_res) ||
21991396Stmm		    start + count - 1 > rman_get_end(hsc->hsc_mac_res)) {
22091396Stmm			device_printf(dev, "cannot move MIF registers to MAC "
22191396Stmm			    "bank\n");
22291396Stmm			goto fail_mac_res;
22391396Stmm		}
22491396Stmm		sc->sc_mift = sc->sc_mact;
22591396Stmm		sc->sc_mifh = sc->sc_mach;
22691396Stmm		sc->sc_mifo = sc->sc_maco + start -
22791396Stmm		    rman_get_start(hsc->hsc_mac_res);
22891396Stmm	} else {
22991396Stmm		sc->sc_mift = rman_get_bustag(hsc->hsc_mif_res);
23091396Stmm		sc->sc_mifh = rman_get_bushandle(hsc->hsc_mif_res);
23191396Stmm	}
23291396Stmm
23391396Stmm	hsc->hsc_irid = 0;
23491396Stmm	hsc->hsc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &hsc->hsc_irid, 0,
23593043Stmm	    ~0, 1, RF_SHAREABLE | RF_ACTIVE);
23691396Stmm	if (hsc->hsc_ires == NULL) {
23791396Stmm		device_printf(dev, "could not allocate interrupt\n");
23891396Stmm		error = ENXIO;
23991396Stmm		goto fail_mif_res;
24091396Stmm	}
24191396Stmm
24291396Stmm
24391396Stmm	OF_getetheraddr(dev, sc->sc_arpcom.ac_enaddr);
24491396Stmm
24591396Stmm	burst = sbus_get_burstsz(dev);
24691396Stmm	/* Translate into plain numerical format */
24791396Stmm	sc->sc_burst =  (burst & SBUS_BURST_32) ? 32 :
24891396Stmm	    (burst & SBUS_BURST_16) ? 16 : 0;
24991396Stmm
25091396Stmm	sc->sc_pci = 0;	/* XXX: should all be done in bus_dma. */
25191396Stmm	sc->sc_dev = dev;
25291396Stmm
25391396Stmm	if ((error = hme_config(sc)) != 0) {
25491396Stmm		device_printf(dev, "could not be configured\n");
25591396Stmm		goto fail_ires;
25691396Stmm	}
25791396Stmm
25891396Stmm
25991396Stmm	if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET, hme_intr,
26091396Stmm	     sc, &hsc->hsc_ih)) != 0) {
26191396Stmm		device_printf(dev, "couldn't establish interrupt\n");
262108976Stmm		hme_detach(sc);
26391396Stmm		goto fail_ires;
26491396Stmm	}
26591396Stmm	return (0);
26691396Stmm
26791396Stmmfail_ires:
26891396Stmm	bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires);
26991396Stmmfail_mif_res:
27091396Stmm	if (hsc->hsc_mif_res != NULL) {
27191396Stmm		bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mif_rid,
27291396Stmm		    hsc->hsc_mif_res);
27391396Stmm	}
27491396Stmmfail_mac_res:
27591396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mac_rid,
27691396Stmm	    hsc->hsc_mac_res);
27791396Stmmfail_erx_res:
27891396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_erx_rid,
27991396Stmm	    hsc->hsc_erx_res);
28091396Stmmfail_etx_res:
28191396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_etx_rid,
28291396Stmm	    hsc->hsc_etx_res);
28391396Stmmfail_seb_res:
28491396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_seb_rid,
28591396Stmm	    hsc->hsc_seb_res);
28691396Stmm	return (ENXIO);
28791396Stmm}
288108976Stmm
289108976Stmmstatic int
290108976Stmmhme_sbus_detach(device_t dev)
291108976Stmm{
292108976Stmm	struct hme_sbus_softc *hsc = device_get_softc(dev);
293108976Stmm	struct hme_softc *sc = &hsc->hsc_hme;
294108976Stmm
295108976Stmm	hme_detach(sc);
296108976Stmm
297108976Stmm	bus_teardown_intr(dev, hsc->hsc_ires, hsc->hsc_ih);
298108976Stmm	if (hsc->hsc_mif_res != NULL) {
299108976Stmm		bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mif_rid,
300108976Stmm		    hsc->hsc_mif_res);
301108976Stmm	}
302108976Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mac_rid,
303108976Stmm	    hsc->hsc_mac_res);
304108976Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_erx_rid,
305108976Stmm	    hsc->hsc_erx_res);
306108976Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_etx_rid,
307108976Stmm	    hsc->hsc_etx_res);
308108976Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_seb_rid,
309108976Stmm	    hsc->hsc_seb_res);
310108976Stmm	return (0);
311108976Stmm}
312108976Stmm
313108976Stmmstatic int
314108976Stmmhme_sbus_suspend(device_t dev)
315108976Stmm{
316108976Stmm	struct hme_sbus_softc *hsc = device_get_softc(dev);
317108976Stmm	struct hme_softc *sc = &hsc->hsc_hme;
318108976Stmm
319108976Stmm	hme_suspend(sc);
320108976Stmm	return (0);
321108976Stmm}
322108976Stmm
323108976Stmmstatic int
324108976Stmmhme_sbus_resume(device_t dev)
325108976Stmm{
326108976Stmm	struct hme_sbus_softc *hsc = device_get_softc(dev);
327108976Stmm	struct hme_softc *sc = &hsc->hsc_hme;
328108976Stmm
329108976Stmm	hme_resume(sc);
330108976Stmm	return (0);
331108976Stmm}
332