xlphy.c revision 109514
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
4050120Swpaul/*
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
6950120Swpaul/*
7050120Swpaul * driver for 3Com internal PHYs
7150120Swpaul */
7250120Swpaul
7350120Swpaul#include <sys/param.h>
7450120Swpaul#include <sys/systm.h>
7550120Swpaul#include <sys/kernel.h>
7650120Swpaul#include <sys/socket.h>
7750120Swpaul#include <sys/module.h>
7850120Swpaul#include <sys/bus.h>
7950120Swpaul
8050120Swpaul#include <net/if.h>
8150120Swpaul#include <net/if_media.h>
8250120Swpaul
8350120Swpaul#include <dev/mii/mii.h>
8450120Swpaul#include <dev/mii/miivar.h>
85109514Sobrien#include "miidevs.h"
8650120Swpaul
8750120Swpaul#include "miibus_if.h"
8850120Swpaul
8950120Swpaul#if !defined(lint)
9050120Swpaulstatic const char rcsid[] =
9150758Swpaul  "$FreeBSD: head/sys/dev/mii/exphy.c 109514 2003-01-19 02:59:34Z obrien $";
9250120Swpaul#endif
9350120Swpaul
94105135Salfredstatic int exphy_probe(device_t);
95105135Salfredstatic int exphy_attach(device_t);
9650120Swpaul
9750120Swpaulstatic device_method_t exphy_methods[] = {
9850120Swpaul	/* device interface */
9950120Swpaul	DEVMETHOD(device_probe,		exphy_probe),
10050120Swpaul	DEVMETHOD(device_attach,	exphy_attach),
10195722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
10250120Swpaul	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
10350120Swpaul	{ 0, 0 }
10450120Swpaul};
10550120Swpaul
10650120Swpaulstatic devclass_t exphy_devclass;
10750120Swpaul
10850120Swpaulstatic driver_t exphy_driver = {
10950120Swpaul	"xlphy",
11050120Swpaul	exphy_methods,
11150120Swpaul	sizeof(struct mii_softc)
11250120Swpaul};
11350120Swpaul
11450120SwpaulDRIVER_MODULE(xlphy, miibus, exphy_driver, exphy_devclass, 0, 0);
11550120Swpaul
11692739Salfredstatic int	exphy_service(struct mii_softc *, struct mii_data *, int);
11792739Salfredstatic void	exphy_reset(struct mii_softc *);
11850120Swpaul
119105135Salfredstatic int
120105135Salfredexphy_probe(dev)
12150120Swpaul	device_t		dev;
12250120Swpaul{
12350120Swpaul	struct mii_attach_args *ma;
12450120Swpaul	device_t		parent;
12550120Swpaul
12650120Swpaul	ma = device_get_ivars(dev);
12750120Swpaul	parent = device_get_parent(device_get_parent(dev));
12850120Swpaul
12950120Swpaul	/*
13050120Swpaul	 * Argh, 3Com PHY reports oui == 0 model == 0!
13150120Swpaul	 */
13250577Swpaul	if ((MII_OUI(ma->mii_id1, ma->mii_id2) != 0 ||
13350577Swpaul	    MII_MODEL(ma->mii_id2) != 0) &&
13450577Swpaul	    (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_BROADCOM ||
13599439Sbenno	    MII_MODEL(ma->mii_id2) != MII_MODEL_BROADCOM_3C905C))
13650120Swpaul		return (ENXIO);
13750120Swpaul
13850120Swpaul	/*
13950120Swpaul	 * Make sure the parent is an `ex'.
14050120Swpaul	 */
14150120Swpaul	if (strcmp(device_get_name(parent), "xl") != 0)
14250120Swpaul		return (ENXIO);
14350120Swpaul
14450577Swpaul	if (MII_OUI(ma->mii_id1, ma->mii_id2) == 0)
14550577Swpaul		device_set_desc(dev, "3Com internal media interface");
14650577Swpaul	else
14799439Sbenno		device_set_desc(dev, MII_STR_BROADCOM_3C905C);
14850120Swpaul
14950120Swpaul	return (0);
15050120Swpaul}
15150120Swpaul
152105135Salfredstatic int
153105135Salfredexphy_attach(dev)
15450120Swpaul	device_t		dev;
15550120Swpaul{
15650120Swpaul	struct mii_softc *sc;
15750120Swpaul	struct mii_attach_args *ma;
15850120Swpaul	struct mii_data *mii;
15950120Swpaul
16050120Swpaul	sc = device_get_softc(dev);
16150120Swpaul	ma = device_get_ivars(dev);
16250120Swpaul	sc->mii_dev = device_get_parent(dev);
16350120Swpaul	mii = device_get_softc(sc->mii_dev);
16450120Swpaul
16550120Swpaul	/*
16650120Swpaul	 * The 3Com PHY can never be isolated, so never allow non-zero
16750120Swpaul	 * instances!
16850120Swpaul	 */
16950120Swpaul	if (mii->mii_instance != 0) {
17050120Swpaul		device_printf(dev, "ignoring this PHY, non-zero instance\n");
17150120Swpaul		return(ENXIO);
17250120Swpaul	}
17350120Swpaul
17450758Swpaul	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
17550758Swpaul
17650758Swpaul	sc->mii_inst = mii->mii_instance;
17750758Swpaul	sc->mii_phy = ma->mii_phyno;
17850758Swpaul	sc->mii_service = exphy_service;
17950758Swpaul	sc->mii_pdata = mii;
18050120Swpaul	mii->mii_instance++;
18150120Swpaul
18250120Swpaul	sc->mii_flags |= MIIF_NOISOLATE;
18350120Swpaul
18450120Swpaul#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
18550120Swpaul
18650120Swpaul#if 0 /* See above. */
18750120Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
18850120Swpaul	    BMCR_ISO);
18950120Swpaul#endif
19050120Swpaul
19150120Swpaul	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
19250120Swpaul	    BMCR_LOOP|BMCR_S100);
19350120Swpaul
19450120Swpaul	exphy_reset(sc);
19550120Swpaul
19650120Swpaul	sc->mii_capabilities =
19750120Swpaul	    PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
19850120Swpaul	device_printf(dev, " ");
19995723Sphk	mii_phy_add_media(sc);
20050120Swpaul	printf("\n");
20150120Swpaul#undef ADD
20250120Swpaul	MIIBUS_MEDIAINIT(sc->mii_dev);
20350120Swpaul	return(0);
20450120Swpaul}
20550120Swpaul
20684145Sjlemonstatic int
20750120Swpaulexphy_service(sc, mii, cmd)
20850120Swpaul	struct mii_softc *sc;
20950120Swpaul	struct mii_data *mii;
21050120Swpaul	int cmd;
21150120Swpaul{
21250120Swpaul	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
21350120Swpaul
21450120Swpaul	/*
21550120Swpaul	 * We can't isolate the 3Com PHY, so it has to be the only one!
21650120Swpaul	 */
21750120Swpaul	if (IFM_INST(ife->ifm_media) != sc->mii_inst)
21850120Swpaul		panic("exphy_service: can't isolate 3Com PHY");
21950120Swpaul
22050120Swpaul	switch (cmd) {
22150120Swpaul	case MII_POLLSTAT:
22250120Swpaul		break;
22350120Swpaul
22450120Swpaul	case MII_MEDIACHG:
22550120Swpaul		/*
22650120Swpaul		 * If the interface is not up, don't do anything.
22750120Swpaul		 */
22850120Swpaul		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
22950120Swpaul			break;
23050120Swpaul
23195723Sphk		mii_phy_setmedia(sc);
23250120Swpaul		break;
23350120Swpaul
23450120Swpaul	case MII_TICK:
23550120Swpaul		/*
23684145Sjlemon		 * Is the interface even up?
23750120Swpaul		 */
23884145Sjlemon		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
23950120Swpaul			return (0);
24050120Swpaul
24150120Swpaul		/*
24284145Sjlemon		 * Only used for autonegotiation.
24350120Swpaul		 */
24484145Sjlemon		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
24584145Sjlemon			break;
24650120Swpaul
24750120Swpaul		/*
24850120Swpaul		 * The 3Com PHY's autonegotiation doesn't need to be
24950120Swpaul		 * kicked; it continues in the background.
25050120Swpaul		 */
25150120Swpaul		break;
25250120Swpaul	}
25350120Swpaul
25450120Swpaul	/* Update the media status. */
25550120Swpaul	ukphy_status(sc);
25650120Swpaul
25750120Swpaul	/* Callback if something changed. */
25884145Sjlemon	mii_phy_update(sc, cmd);
25950120Swpaul	return (0);
26050120Swpaul}
26150120Swpaul
26284145Sjlemonstatic void
26395723Sphkexphy_reset(struct mii_softc *sc)
26450120Swpaul{
26550120Swpaul
26650120Swpaul	mii_phy_reset(sc);
26750120Swpaul
26850120Swpaul	/*
26950120Swpaul	 * XXX 3Com PHY doesn't set the BMCR properly after
27050120Swpaul	 * XXX reset, which breaks autonegotiation.
27150120Swpaul	 */
27250120Swpaul	PHY_WRITE(sc, MII_BMCR, BMCR_S100|BMCR_AUTOEN|BMCR_FDX);
27350120Swpaul}
274