xlphy.c revision 139749
150120Swpaul/*	$NetBSD: exphy.c,v 1.16 1999/04/23 04:24:32 thorpej Exp $	*/
250120Swpaul
350120Swpaul/*-
450120Swpaul * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
550120Swpaul * All rights reserved.
650120Swpaul *
750120Swpaul * This code is derived from software contributed to The NetBSD Foundation
850120Swpaul * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
950120Swpaul * NASA Ames Research Center, and by Frank van der Linden.
1050120Swpaul *
1150120Swpaul * Redistribution and use in source and binary forms, with or without
1250120Swpaul * modification, are permitted provided that the following conditions
1350120Swpaul * are met:
1450120Swpaul * 1. Redistributions of source code must retain the above copyright
1550120Swpaul *    notice, this list of conditions and the following disclaimer.
1650120Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1750120Swpaul *    notice, this list of conditions and the following disclaimer in the
1850120Swpaul *    documentation and/or other materials provided with the distribution.
1950120Swpaul * 3. All advertising materials mentioning features or use of this software
2050120Swpaul *    must display the following acknowledgement:
2150120Swpaul *	This product includes software developed by the NetBSD
2250120Swpaul *	Foundation, Inc. and its contributors.
2350120Swpaul * 4. Neither the name of The NetBSD Foundation nor the names of its
2450120Swpaul *    contributors may be used to endorse or promote products derived
2550120Swpaul *    from this software without specific prior written permission.
2650120Swpaul *
2750120Swpaul * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2850120Swpaul * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2950120Swpaul * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
3050120Swpaul * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
3150120Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
3250120Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3350120Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3450120Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3550120Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3650120Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3750120Swpaul * POSSIBILITY OF SUCH DAMAGE.
3850120Swpaul */
3950120Swpaul
40139749Simp/*-
4150120Swpaul * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
4250120Swpaul *
4350120Swpaul * Redistribution and use in source and binary forms, with or without
4450120Swpaul * modification, are permitted provided that the following conditions
4550120Swpaul * are met:
4650120Swpaul * 1. Redistributions of source code must retain the above copyright
4750120Swpaul *    notice, this list of conditions and the following disclaimer.
4850120Swpaul * 2. Redistributions in binary form must reproduce the above copyright
4950120Swpaul *    notice, this list of conditions and the following disclaimer in the
5050120Swpaul *    documentation and/or other materials provided with the distribution.
5150120Swpaul * 3. All advertising materials mentioning features or use of this software
5250120Swpaul *    must display the following acknowledgement:
5350120Swpaul *	This product includes software developed by Manuel Bouyer.
5450120Swpaul * 4. The name of the author may not be used to endorse or promote products
5550120Swpaul *    derived from this software without specific prior written permission.
5650120Swpaul *
5750120Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
5850120Swpaul * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
5950120Swpaul * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
6050120Swpaul * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
6150120Swpaul * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
6250120Swpaul * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
6350120Swpaul * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
6450120Swpaul * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6550120Swpaul * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
6650120Swpaul * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6750120Swpaul */
6850120Swpaul
69129844Smarius#include <sys/cdefs.h>
70129844Smarius__FBSDID("$FreeBSD: head/sys/dev/mii/exphy.c 139749 2005-01-06 01:43:34Z imp $");
71129844Smarius
7250120Swpaul/*
7350120Swpaul * driver for 3Com internal PHYs
7450120Swpaul */
7550120Swpaul
7650120Swpaul#include <sys/param.h>
7750120Swpaul#include <sys/systm.h>
7850120Swpaul#include <sys/kernel.h>
7950120Swpaul#include <sys/socket.h>
8050120Swpaul#include <sys/module.h>
8150120Swpaul#include <sys/bus.h>
8250120Swpaul
8350120Swpaul#include <net/if.h>
8450120Swpaul#include <net/if_media.h>
8550120Swpaul
8650120Swpaul#include <dev/mii/mii.h>
8750120Swpaul#include <dev/mii/miivar.h>
88109514Sobrien#include "miidevs.h"
8950120Swpaul
9050120Swpaul#include "miibus_if.h"
9150120Swpaul
92105135Salfredstatic int exphy_probe(device_t);
93105135Salfredstatic int exphy_attach(device_t);
9450120Swpaul
9550120Swpaulstatic device_method_t exphy_methods[] = {
9650120Swpaul	/* device interface */
9750120Swpaul	DEVMETHOD(device_probe,		exphy_probe),
9850120Swpaul	DEVMETHOD(device_attach,	exphy_attach),
9995722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
10050120Swpaul	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
10150120Swpaul	{ 0, 0 }
10250120Swpaul};
10350120Swpaul
10450120Swpaulstatic devclass_t exphy_devclass;
10550120Swpaul
10650120Swpaulstatic driver_t exphy_driver = {
10750120Swpaul	"xlphy",
10850120Swpaul	exphy_methods,
10950120Swpaul	sizeof(struct mii_softc)
11050120Swpaul};
11150120Swpaul
11250120SwpaulDRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0);
11350120Swpaul
11492739Salfredstatic int	exphy_service(struct mii_softc *, struct mii_data *, int);
11592739Salfredstatic void	exphy_reset(struct mii_softc *);
11650120Swpaul
117105135Salfredstatic int
118105135Salfredexphy_probe(dev)
11950120Swpaul	device_t		dev;
12050120Swpaul{
12150120Swpaul	struct mii_attach_args *ma;
12250120Swpaul	device_t		parent;
12350120Swpaul
12450120Swpaul	ma = device_get_ivars(dev);
12550120Swpaul	parent = device_get_parent(device_get_parent(dev));
12650120Swpaul
12750120Swpaul	/*
12850120Swpaul	 * Argh, 3Com PHY reports oui == 0 model == 0!
12950120Swpaul	 */
13050577Swpaul	if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
13150577Swpaul	    MII_MODEL(ma->mii_id2) != 0) &&
13250577Swpaul	    (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM ||
13399439Sbenno	    MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3C905C))
13450120Swpaul		return (ENXIO);
13550120Swpaul
13650120Swpaul	/*
13750120Swpaul	 * Make sure the parent is an `ex'.
13850120Swpaul	 */
13950120Swpaul	if (strcmp(device_get_name(parent), "xl") != 0)
14050120Swpaul		return (ENXIO);
14150120Swpaul
14250577Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0)
14350577Swpaul		device_set_desc(dev, "3Com internal media interface");
14450577Swpaul	else
14599439Sbenno		device_set_desc(dev, MII_STR_BROADCOM_3C905C);
14650120Swpaul
14750120Swpaul	return (0);
14850120Swpaul}
14950120Swpaul
150105135Salfredstatic int
151105135Salfredexphy_attach(dev)
15250120Swpaul	device_t		dev;
15350120Swpaul{
15450120Swpaul	struct mii_softc *sc;
15550120Swpaul	struct mii_attach_args *ma;
15650120Swpaul	struct mii_data *mii;
15750120Swpaul
15850120Swpaul	sc = device_get_softc(dev);
15950120Swpaul	ma = device_get_ivars(dev);
16050120Swpaul	sc->mii_dev = device_get_parent(dev);
16150120Swpaul	mii = device_get_softc(sc->mii_dev);
16250120Swpaul
16350120Swpaul	/*
16450120Swpaul	 * The 3Com PHY can never be isolated, so never allow non-zero
16550120Swpaul	 * instances!
16650120Swpaul	 */
16750120Swpaul	if (mii->mii_instance != 0) {
16850120Swpaul		device_printf(dev, "ignoring this PHY, non-zero instance\n");
16950120Swpaul		return(ENXIO);
17050120Swpaul	}
17150120Swpaul
17250758Swpaul	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
17350758Swpaul
17450758Swpaul	sc->mii_inst = mii->mii_instance;
17550758Swpaul	sc->mii_phy = ma->mii_phyno;
17650758Swpaul	sc->mii_service = exphy_service;
17750758Swpaul	sc->mii_pdata = mii;
17850120Swpaul	mii->mii_instance++;
17950120Swpaul
18050120Swpaul	sc->mii_flags |= MIIF_NOISOLATE;
18150120Swpaul
18250120Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
18350120Swpaul
18450120Swpaul#if 0 /* See above. */
18550120Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
18650120Swpaul	    BMCR_ISO);
18750120Swpaul#endif
18850120Swpaul
18950120Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
19050120Swpaul	    BMCR_LOOP|BMCR_S100);
19150120Swpaul
19250120Swpaul	exphy_reset(sc);
19350120Swpaul
19450120Swpaul	sc->mii_capabilities =
19550120Swpaul	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
19650120Swpaul	device_printf(dev, " ");
19795723Sphk	mii_phy_add_media(sc);
19850120Swpaul	printf("\n");
19950120Swpaul#undef ADD
20050120Swpaul	MIIBUS_MEDIAINIT(sc->mii_dev);
20150120Swpaul	return(0);
20250120Swpaul}
20350120Swpaul
20484145Sjlemonstatic int
20550120Swpaulexphy_service(sc, mii, cmd)
20650120Swpaul	struct mii_softc *sc;
20750120Swpaul	struct mii_data *mii;
20850120Swpaul	int cmd;
20950120Swpaul{
21050120Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
21150120Swpaul
21250120Swpaul	/*
21350120Swpaul	 * We can't isolate the 3Com PHY, so it has to be the only one!
21450120Swpaul	 */
21550120Swpaul	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
21650120Swpaul		panic("exphy_service: can't isolate 3Com PHY");
21750120Swpaul
21850120Swpaul	switch (cmd) {
21950120Swpaul	case MII_POLLSTAT:
22050120Swpaul		break;
22150120Swpaul
22250120Swpaul	case MII_MEDIACHG:
22350120Swpaul		/*
22450120Swpaul		 * If the interface is not up, don't do anything.
22550120Swpaul		 */
22650120Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
22750120Swpaul			break;
22850120Swpaul
22995723Sphk		mii_phy_setmedia(sc);
23050120Swpaul		break;
23150120Swpaul
23250120Swpaul	case MII_TICK:
23350120Swpaul		/*
23484145Sjlemon		 * Is the interface even up?
23550120Swpaul		 */
23684145Sjlemon		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
23750120Swpaul			return (0);
23850120Swpaul
23950120Swpaul		/*
24084145Sjlemon		 * Only used for autonegotiation.
24150120Swpaul		 */
24284145Sjlemon		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
24384145Sjlemon			break;
24450120Swpaul
24550120Swpaul		/*
24650120Swpaul		 * The 3Com PHY's autonegotiation doesn't need to be
24750120Swpaul		 * kicked; it continues in the background.
24850120Swpaul		 */
24950120Swpaul		break;
25050120Swpaul	}
25150120Swpaul
25250120Swpaul	/* Update the media status. */
25350120Swpaul	ukphy_status(sc);
25450120Swpaul
25550120Swpaul	/* Callback if something changed. */
25684145Sjlemon	mii_phy_update(sc, cmd);
25750120Swpaul	return (0);
25850120Swpaul}
25950120Swpaul
26084145Sjlemonstatic void
26195723Sphkexphy_reset(struct mii_softc *sc)
26250120Swpaul{
26350120Swpaul
26450120Swpaul	mii_phy_reset(sc);
26550120Swpaul
26650120Swpaul	/*
26750120Swpaul	 * XXX 3Com PHY doesn't set the BMCR properly after
26850120Swpaul	 * XXX reset, which breaks autonegotiation.
26950120Swpaul	 */
27050120Swpaul	PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX);
27150120Swpaul}
272