if_hme_sbus.c revision 93043
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 * $FreeBSD: head/sys/dev/hme/if_hme_sbus.c 93043 2002-03-23 19:37:11Z tmm $
3991396Stmm */
4091396Stmm
4191396Stmm/*
4291396Stmm * SBus front-end device driver for the HME ethernet device.
4391396Stmm */
4491396Stmm
4591396Stmm#include <sys/param.h>
4691396Stmm#include <sys/systm.h>
4791396Stmm#include <sys/bus.h>
4891396Stmm#include <sys/kernel.h>
4991396Stmm#include <sys/resource.h>
5091396Stmm#include <sys/socket.h>
5191396Stmm
5291396Stmm#include <machine/bus.h>
5391396Stmm#include <machine/ofw_machdep.h>
5491396Stmm#include <machine/resource.h>
5591396Stmm
5691396Stmm#include <sys/rman.h>
5791396Stmm
5891396Stmm#include <ofw/openfirm.h>
5991396Stmm
6091396Stmm#include <net/ethernet.h>
6191396Stmm#include <net/if.h>
6291396Stmm#include <net/if_arp.h>
6391396Stmm#include <net/if_dl.h>
6491396Stmm#include <net/if_media.h>
6591396Stmm
6691396Stmm#include <mii/mii.h>
6791396Stmm#include <mii/miivar.h>
6891396Stmm
6991396Stmm#include <sparc64/sbus/sbusvar.h>
7091396Stmm
7191396Stmm#include <hme/if_hmereg.h>
7291396Stmm#include <hme/if_hmevar.h>
7391396Stmm
7491396Stmm#include "miibus_if.h"
7591396Stmm
7691396Stmmstruct hme_sbus_softc {
7791396Stmm	struct	hme_softc	hsc_hme;	/* HME device */
7891396Stmm	struct	resource	*hsc_seb_res;
7991396Stmm	int			hsc_seb_rid;
8091396Stmm	struct	resource	*hsc_etx_res;
8191396Stmm	int			hsc_etx_rid;
8291396Stmm	struct	resource	*hsc_erx_res;
8391396Stmm	int			hsc_erx_rid;
8491396Stmm	struct	resource	*hsc_mac_res;
8591396Stmm	int			hsc_mac_rid;
8691396Stmm	struct	resource	*hsc_mif_res;
8791396Stmm	int			hsc_mif_rid;
8891396Stmm	struct	resource	*hsc_ires;
8991396Stmm	int			hsc_irid;
9091396Stmm	void			*hsc_ih;
9191396Stmm};
9291396Stmm
9391396Stmmstatic int hme_sbus_probe(device_t);
9491396Stmmstatic int hme_sbus_attach(device_t);
9591396Stmm
9691396Stmmstatic device_method_t hme_sbus_methods[] = {
9791396Stmm	/* Device interface */
9891396Stmm	DEVMETHOD(device_probe,		hme_sbus_probe),
9991396Stmm	DEVMETHOD(device_attach,	hme_sbus_attach),
10091396Stmm
10191396Stmm	/* bus interface */
10291396Stmm	DEVMETHOD(bus_print_child,	bus_generic_print_child),
10391396Stmm	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
10491396Stmm
10591396Stmm	/* MII interface */
10691396Stmm	DEVMETHOD(miibus_readreg,	hme_mii_readreg),
10791396Stmm	DEVMETHOD(miibus_writereg,	hme_mii_writereg),
10891396Stmm	DEVMETHOD(miibus_statchg,	hme_mii_statchg),
10991396Stmm
11091396Stmm	{ 0, 0 }
11191396Stmm};
11291396Stmm
11391396Stmmstatic driver_t hme_sbus_driver = {
11491396Stmm	"hme",
11591396Stmm	hme_sbus_methods,
11691396Stmm	sizeof(struct hme_sbus_softc)
11791396Stmm};
11891396Stmm
11991396StmmDRIVER_MODULE(if_hme, sbus, hme_sbus_driver, hme_devclass, 0, 0);
12091396Stmm
12191396Stmmstatic int
12291396Stmmhme_sbus_probe(device_t dev)
12391396Stmm{
12491396Stmm	char *name;
12591396Stmm
12691396Stmm	name = sbus_get_name(dev);
12791396Stmm	if (strcmp(name, "SUNW,qfe") == 0 ||
12891396Stmm	    strcmp(name, "SUNW,hme") == 0) {
12991396Stmm		device_set_desc(dev, "Sun HME 10/100 Ethernet");
13091396Stmm		return (0);
13191396Stmm	}
13291396Stmm	return (ENXIO);
13391396Stmm}
13491396Stmm
13591396Stmmstatic int
13691396Stmmhme_sbus_attach(device_t dev)
13791396Stmm{
13891396Stmm	struct hme_sbus_softc *hsc = device_get_softc(dev);
13991396Stmm	struct hme_softc *sc = &hsc->hsc_hme;
14091396Stmm	u_int32_t burst;
14191396Stmm	u_long start, count;
14291396Stmm	int error;
14391396Stmm
14491396Stmm	/*
14591396Stmm	 * Map five register banks:
14691396Stmm	 *
14791396Stmm	 *	bank 0: HME SEB registers
14891396Stmm	 *	bank 1: HME ETX registers
14991396Stmm	 *	bank 2: HME ERX registers
15091396Stmm	 *	bank 3: HME MAC registers
15191396Stmm	 *	bank 4: HME MIF registers
15291396Stmm	 *
15391396Stmm	 */
15491396Stmm	sc->sc_sebo = sc->sc_etxo = sc->sc_erxo = sc->sc_maco = sc->sc_mifo = 0;
15591396Stmm	hsc->hsc_seb_rid = 0;
15691396Stmm	hsc->hsc_seb_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
15791396Stmm	    &hsc->hsc_seb_rid, 0, ~0, 1, RF_ACTIVE);
15891396Stmm	if (hsc->hsc_seb_res == NULL) {
15991396Stmm		device_printf(dev, "cannot map SEB registers\n");
16091396Stmm		return (ENXIO);
16191396Stmm	}
16291396Stmm	sc->sc_sebt = rman_get_bustag(hsc->hsc_seb_res);
16391396Stmm	sc->sc_sebh = rman_get_bushandle(hsc->hsc_seb_res);
16491396Stmm
16591396Stmm	hsc->hsc_etx_rid = 1;
16691396Stmm	hsc->hsc_etx_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
16791396Stmm	    &hsc->hsc_etx_rid, 0, ~0, 1, RF_ACTIVE);
16891396Stmm	if (hsc->hsc_etx_res == NULL) {
16991396Stmm		device_printf(dev, "cannot map ETX registers\n");
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
17591396Stmm	hsc->hsc_erx_rid = 2;
17691396Stmm	hsc->hsc_erx_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
17791396Stmm	    &hsc->hsc_erx_rid, 0, ~0, 1, RF_ACTIVE);
17891396Stmm	if (hsc->hsc_erx_res == NULL) {
17991396Stmm		device_printf(dev, "cannot map ERX registers\n");
18091396Stmm		goto fail_etx_res;
18191396Stmm	}
18291396Stmm	sc->sc_erxt = rman_get_bustag(hsc->hsc_erx_res);
18391396Stmm	sc->sc_erxh = rman_get_bushandle(hsc->hsc_erx_res);
18491396Stmm
18591396Stmm	hsc->hsc_mac_rid = 3;
18691396Stmm	hsc->hsc_mac_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
18791396Stmm	    &hsc->hsc_mac_rid, 0, ~0, 1, RF_ACTIVE);
18891396Stmm	if (hsc->hsc_mac_res == NULL) {
18991396Stmm		device_printf(dev, "cannot map MAC registers\n");
19091396Stmm		goto fail_erx_res;
19191396Stmm	}
19291396Stmm	sc->sc_mact = rman_get_bustag(hsc->hsc_mac_res);
19391396Stmm	sc->sc_mach = rman_get_bushandle(hsc->hsc_mac_res);
19491396Stmm
19591396Stmm	/*
19691396Stmm	 * At least on some HMEs, the MIF registers seem to be inside the MAC
19791396Stmm	 * range, so map try to kluge around it.
19891396Stmm	 */
19991396Stmm	hsc->hsc_mif_rid = 4;
20091396Stmm	hsc->hsc_mif_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
20191396Stmm	    &hsc->hsc_mif_rid, 0, ~0, 1, RF_ACTIVE);
20291396Stmm	if (hsc->hsc_mif_res == NULL) {
20391396Stmm		if (bus_get_resource(dev, SYS_RES_MEMORY, hsc->hsc_mif_rid,
20491396Stmm		    &start, &count) != 0) {
20591396Stmm			device_printf(dev, "cannot get MIF registers\n");
20691396Stmm			goto fail_mac_res;
20791396Stmm		}
20891396Stmm		if (start < rman_get_start(hsc->hsc_mac_res) ||
20991396Stmm		    start + count - 1 > rman_get_end(hsc->hsc_mac_res)) {
21091396Stmm			device_printf(dev, "cannot move MIF registers to MAC "
21191396Stmm			    "bank\n");
21291396Stmm			goto fail_mac_res;
21391396Stmm		}
21491396Stmm		sc->sc_mift = sc->sc_mact;
21591396Stmm		sc->sc_mifh = sc->sc_mach;
21691396Stmm		sc->sc_mifo = sc->sc_maco + start -
21791396Stmm		    rman_get_start(hsc->hsc_mac_res);
21891396Stmm	} else {
21991396Stmm		sc->sc_mift = rman_get_bustag(hsc->hsc_mif_res);
22091396Stmm		sc->sc_mifh = rman_get_bushandle(hsc->hsc_mif_res);
22191396Stmm	}
22291396Stmm
22391396Stmm	hsc->hsc_irid = 0;
22491396Stmm	hsc->hsc_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &hsc->hsc_irid, 0,
22593043Stmm	    ~0, 1, RF_SHAREABLE | RF_ACTIVE);
22691396Stmm	if (hsc->hsc_ires == NULL) {
22791396Stmm		device_printf(dev, "could not allocate interrupt\n");
22891396Stmm		error = ENXIO;
22991396Stmm		goto fail_mif_res;
23091396Stmm	}
23191396Stmm
23291396Stmm
23391396Stmm	OF_getetheraddr(dev, sc->sc_arpcom.ac_enaddr);
23491396Stmm
23591396Stmm	burst = sbus_get_burstsz(dev);
23691396Stmm	/* Translate into plain numerical format */
23791396Stmm	sc->sc_burst =  (burst & SBUS_BURST_32) ? 32 :
23891396Stmm	    (burst & SBUS_BURST_16) ? 16 : 0;
23991396Stmm
24091396Stmm	sc->sc_pci = 0;	/* XXX: should all be done in bus_dma. */
24191396Stmm	sc->sc_dev = dev;
24291396Stmm
24391396Stmm	if ((error = hme_config(sc)) != 0) {
24491396Stmm		device_printf(dev, "could not be configured\n");
24591396Stmm		goto fail_ires;
24691396Stmm	}
24791396Stmm
24891396Stmm
24991396Stmm	if ((error = bus_setup_intr(dev, hsc->hsc_ires, INTR_TYPE_NET, hme_intr,
25091396Stmm	     sc, &hsc->hsc_ih)) != 0) {
25191396Stmm		device_printf(dev, "couldn't establish interrupt\n");
25291396Stmm		goto fail_ires;
25391396Stmm	}
25491396Stmm	return (0);
25591396Stmm
25691396Stmmfail_ires:
25791396Stmm	bus_release_resource(dev, SYS_RES_IRQ, hsc->hsc_irid, hsc->hsc_ires);
25891396Stmmfail_mif_res:
25991396Stmm	if (hsc->hsc_mif_res != NULL) {
26091396Stmm		bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mif_rid,
26191396Stmm		    hsc->hsc_mif_res);
26291396Stmm	}
26391396Stmmfail_mac_res:
26491396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_mac_rid,
26591396Stmm	    hsc->hsc_mac_res);
26691396Stmmfail_erx_res:
26791396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_erx_rid,
26891396Stmm	    hsc->hsc_erx_res);
26991396Stmmfail_etx_res:
27091396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_etx_rid,
27191396Stmm	    hsc->hsc_etx_res);
27291396Stmmfail_seb_res:
27391396Stmm	bus_release_resource(dev, SYS_RES_MEMORY, hsc->hsc_seb_rid,
27491396Stmm	    hsc->hsc_seb_res);
27591396Stmm	return (ENXIO);
27691396Stmm}
277