e1000phy.c revision 109514
175353Smjacob/* $FreeBSD: head/sys/dev/mii/e1000phy.c 109514 2003-01-19 02:59:34Z obrien $ */
275353Smjacob/*
375353Smjacob * Principal Author: Parag Patel
475353Smjacob * Copyright (c) 2001
575353Smjacob * All rights reserved.
675353Smjacob *
775353Smjacob * Redistribution and use in source and binary forms, with or without
875353Smjacob * modification, are permitted provided that the following conditions
975353Smjacob * are met:
1075353Smjacob * 1. Redistributions of source code must retain the above copyright
1175353Smjacob *    notice unmodified, this list of conditions, and the following
1275353Smjacob *    disclaimer.
1375353Smjacob * 2. Redistributions in binary form must reproduce the above copyright
1475353Smjacob *    notice, this list of conditions and the following disclaimer in the
1575353Smjacob *    documentation and/or other materials provided with the distribution.
1675353Smjacob *
1775353Smjacob * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1875353Smjacob * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1975353Smjacob * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2075353Smjacob * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2175353Smjacob * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2275353Smjacob * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2375353Smjacob * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2475353Smjacob * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2575353Smjacob * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2675353Smjacob * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2775353Smjacob * SUCH DAMAGE.
2875353Smjacob *
2975353Smjacob * Additonal Copyright (c) 2001 by Traakan Software under same licence.
3075353Smjacob * Secondary Author: Matthew Jacob
3175353Smjacob */
3275353Smjacob
3375353Smjacob/*
3475353Smjacob * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
3575353Smjacob */
3675353Smjacob
3775353Smjacob#include <sys/param.h>
3875353Smjacob#include <sys/systm.h>
3975353Smjacob#include <sys/kernel.h>
4075353Smjacob#include <sys/socket.h>
4175353Smjacob#include <sys/bus.h>
4275353Smjacob
4375353Smjacob#include <machine/clock.h>
4475353Smjacob
4575353Smjacob#include <net/if.h>
4675353Smjacob#include <net/if_media.h>
4775353Smjacob
4875353Smjacob#include <dev/mii/mii.h>
4975353Smjacob#include <dev/mii/miivar.h>
50109514Sobrien#include "miidevs.h"
5175353Smjacob
5275353Smjacob#include <dev/mii/e1000phyreg.h>
5375353Smjacob
5475353Smjacob#include "miibus_if.h"
5575353Smjacob
5675353Smjacobstatic int e1000phy_probe(device_t);
5775353Smjacobstatic int e1000phy_attach(device_t);
5875353Smjacob
5975353Smjacobstatic device_method_t e1000phy_methods[] = {
6075353Smjacob	/* device interface */
6175353Smjacob	DEVMETHOD(device_probe,		e1000phy_probe),
6275353Smjacob	DEVMETHOD(device_attach,	e1000phy_attach),
6395722Sphk	DEVMETHOD(device_detach,	mii_phy_detach),
6475353Smjacob	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
6575353Smjacob	{ 0, 0 }
6675353Smjacob};
6775353Smjacob
6875353Smjacobstatic devclass_t e1000phy_devclass;
6975353Smjacobstatic driver_t e1000phy_driver = {
7075353Smjacob	"e1000phy", e1000phy_methods, sizeof (struct mii_softc)
7175353Smjacob};
7275353SmjacobDRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0);
7375353Smjacob
7484145Sjlemonstatic int	e1000phy_service(struct mii_softc *, struct mii_data *, int);
7584145Sjlemonstatic void	e1000phy_status(struct mii_softc *);
7684145Sjlemonstatic void	e1000phy_reset(struct mii_softc *);
7796026Sphkstatic int	e1000phy_mii_phy_auto(struct mii_softc *);
7875353Smjacob
7975353Smjacobstatic int e1000phy_debug = 0;
8075353Smjacob
8175353Smjacobstatic int
8275353Smjacobe1000phy_probe(device_t	dev)
8375353Smjacob{
8475353Smjacob	struct mii_attach_args *ma;
8575353Smjacob	u_int32_t id;
8675353Smjacob
8775353Smjacob	ma = device_get_ivars(dev);
8875353Smjacob	id = ((ma->mii_id1 << 16) | ma->mii_id2) & E1000_ID_MASK;
8975353Smjacob
9075353Smjacob	if (id != E1000_ID_88E1000 && id != E1000_ID_88E1000S) {
9175353Smjacob		return ENXIO;
9275353Smjacob	}
9375353Smjacob
9475353Smjacob	device_set_desc(dev, MII_STR_MARVELL_E1000);
9575353Smjacob	return 0;
9675353Smjacob}
9775353Smjacob
9875353Smjacobstatic int
9975353Smjacobe1000phy_attach(device_t dev)
10075353Smjacob{
10175353Smjacob	struct mii_softc *sc;
10275353Smjacob	struct mii_attach_args *ma;
10375353Smjacob	struct mii_data *mii;
10475353Smjacob
10575353Smjacob	getenv_int("e1000phy_debug", &e1000phy_debug);
10675353Smjacob
10775353Smjacob	sc = device_get_softc(dev);
10875353Smjacob	ma = device_get_ivars(dev);
10975353Smjacob	sc->mii_dev = device_get_parent(dev);
11075353Smjacob	mii = device_get_softc(sc->mii_dev);
11175353Smjacob	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
11275353Smjacob
11375353Smjacob	sc->mii_inst = mii->mii_instance;
11475353Smjacob	sc->mii_phy = ma->mii_phyno;
11575353Smjacob	sc->mii_service = e1000phy_service;
11675353Smjacob	sc->mii_pdata = mii;
11775353Smjacob
11875353Smjacob	sc->mii_flags |= MIIF_NOISOLATE;
11975353Smjacob	mii->mii_instance++;
12075353Smjacob	e1000phy_reset(sc);
12175353Smjacob
12284144Sjlemon	device_printf(dev, " ");
12384144Sjlemon
12475353Smjacob#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
12584144Sjlemon/*
12675353Smjacob	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
12775353Smjacob	    E1000_CR_ISOLATE);
12884144Sjlemon*/
12984144Sjlemon	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
13084144Sjlemon	    E1000_CR_SPEED_10);
13184144Sjlemon	printf("10baseT, ");
13284144Sjlemon	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
13384144Sjlemon	    E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX);
13484144Sjlemon	printf("10baseT-FDX, ");
13584144Sjlemon	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
13684144Sjlemon	    E1000_CR_SPEED_100);
13784144Sjlemon	printf("100baseTX, ");
13884144Sjlemon	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
13984144Sjlemon	    E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX);
14084144Sjlemon	printf("100baseTX-FDX, ");
14175353Smjacob	/*
14284144Sjlemon	 * 1000BT-simplex not supported; driver must ignore this entry,
14384144Sjlemon	 * but it must be present in order to manually set full-duplex.
14484144Sjlemon	 */
14595673Sphk	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0, sc->mii_inst),
14684144Sjlemon	    E1000_CR_SPEED_1000);
14795673Sphk	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX, sc->mii_inst),
14884144Sjlemon	    E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX);
14984144Sjlemon	printf("1000baseTX-FDX, ");
15075353Smjacob	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
15184144Sjlemon	printf("auto\n");
15275353Smjacob#undef ADD
15375353Smjacob
15475353Smjacob	MIIBUS_MEDIAINIT(sc->mii_dev);
15575353Smjacob	return(0);
15675353Smjacob}
15775353Smjacob
15875353Smjacobstatic void
15975353Smjacobe1000phy_reset(struct mii_softc *sc)
16075353Smjacob{
16175353Smjacob	u_int32_t reg;
16275353Smjacob	int i;
16375353Smjacob
16475353Smjacob	/* initialize custom E1000 registers to magic values */
16575353Smjacob	reg = PHY_READ(sc, E1000_SCR);
16675353Smjacob	reg &= ~E1000_SCR_AUTO_X_MODE;
16775353Smjacob	PHY_WRITE(sc, E1000_SCR, reg);
16875353Smjacob
16975353Smjacob	/* normal PHY reset */
17075353Smjacob	/*mii_phy_reset(sc);*/
17175353Smjacob	reg = PHY_READ(sc, E1000_CR);
17275353Smjacob	reg |= E1000_CR_RESET;
17375353Smjacob	PHY_WRITE(sc, E1000_CR, reg);
17475353Smjacob
17575353Smjacob	for (i = 0; i < 500; i++) {
17675353Smjacob		DELAY(1);
17775353Smjacob		reg = PHY_READ(sc, E1000_CR);
17875353Smjacob		if (!(reg & E1000_CR_RESET))
17975353Smjacob			break;
18075353Smjacob	}
18175353Smjacob
18275353Smjacob	/* set more custom E1000 registers to magic values */
18375353Smjacob	reg = PHY_READ(sc, E1000_SCR);
18475353Smjacob	reg |= E1000_SCR_ASSERT_CRS_ON_TX;
18575353Smjacob	PHY_WRITE(sc, E1000_SCR, reg);
18675353Smjacob
18775353Smjacob	reg = PHY_READ(sc, E1000_ESCR);
18875353Smjacob	reg |= E1000_ESCR_TX_CLK_25;
18975353Smjacob	PHY_WRITE(sc, E1000_ESCR, reg);
19075353Smjacob
19175353Smjacob	/* even more magic to reset DSP? */
19275353Smjacob	PHY_WRITE(sc, 29, 0x1d);
19375353Smjacob	PHY_WRITE(sc, 30, 0xc1);
19475353Smjacob	PHY_WRITE(sc, 30, 0x00);
19575353Smjacob}
19675353Smjacob
19784145Sjlemonstatic int
19875353Smjacobe1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
19975353Smjacob{
20075353Smjacob	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
20175353Smjacob	int reg;
20275353Smjacob
20375353Smjacob	switch (cmd) {
20475353Smjacob	case MII_POLLSTAT:
20575353Smjacob		/*
20675353Smjacob		 * If we're not polling our PHY instance, just return.
20775353Smjacob		 */
20875353Smjacob		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
20975353Smjacob			return (0);
21075353Smjacob		break;
21175353Smjacob
21275353Smjacob	case MII_MEDIACHG:
21375353Smjacob		/*
21475353Smjacob		 * If the media indicates a different PHY instance,
21575353Smjacob		 * isolate ourselves.
21675353Smjacob		 */
21775353Smjacob		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
21875353Smjacob			reg = PHY_READ(sc, E1000_CR);
21975353Smjacob			PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE);
22075353Smjacob			return (0);
22175353Smjacob		}
22275353Smjacob
22375353Smjacob		/*
22475353Smjacob		 * If the interface is not up, don't do anything.
22575353Smjacob		 */
22675353Smjacob		if ((mii->mii_ifp->if_flags & IFF_UP) == 0) {
22775353Smjacob			break;
22875353Smjacob		}
22975353Smjacob
23075353Smjacob		switch (IFM_SUBTYPE(ife->ifm_media)) {
23175353Smjacob		case IFM_AUTO:
23275353Smjacob			e1000phy_reset(sc);
23396026Sphk			(void)e1000phy_mii_phy_auto(sc);
23475353Smjacob			break;
23575353Smjacob
23695673Sphk		case IFM_1000_T:
23775353Smjacob			e1000phy_reset(sc);
23875353Smjacob
23975353Smjacob			/* TODO - any other way to force 1000BT? */
24096026Sphk			(void)e1000phy_mii_phy_auto(sc);
24175353Smjacob			break;
24275353Smjacob
24375353Smjacob		case IFM_100_TX:
24475353Smjacob			e1000phy_reset(sc);
24575353Smjacob
24675353Smjacob			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
24775353Smjacob				PHY_WRITE(sc, E1000_CR,
24875353Smjacob				    E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_100);
24975353Smjacob				PHY_WRITE(sc, E1000_AR, E1000_AR_100TX_FD);
25075353Smjacob			} else {
25175353Smjacob				PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_100);
25275353Smjacob				PHY_WRITE(sc, E1000_AR, E1000_AR_100TX);
25375353Smjacob			}
25475353Smjacob			break;
25575353Smjacob
25675353Smjacob		case IFM_10_T:
25775353Smjacob			e1000phy_reset(sc);
25875353Smjacob
25975353Smjacob			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
26075353Smjacob				PHY_WRITE(sc, E1000_CR,
26175353Smjacob				    E1000_CR_FULL_DUPLEX | E1000_CR_SPEED_10);
26275353Smjacob				PHY_WRITE(sc, E1000_AR, E1000_AR_10T_FD);
26375353Smjacob			} else {
26475353Smjacob				PHY_WRITE(sc, E1000_CR, E1000_CR_SPEED_10);
26575353Smjacob				PHY_WRITE(sc, E1000_AR, E1000_AR_10T);
26675353Smjacob			}
26775353Smjacob
26875353Smjacob			break;
26975353Smjacob
27075353Smjacob		default:
27175353Smjacob			return (EINVAL);
27275353Smjacob		}
27375353Smjacob
27475353Smjacob		break;
27575353Smjacob
27675353Smjacob	case MII_TICK:
27775353Smjacob		/*
27875353Smjacob		 * If we're not currently selected, just return.
27975353Smjacob		 */
28075353Smjacob		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
28175353Smjacob			return (0);
28275353Smjacob		}
28375353Smjacob
28475353Smjacob		/*
28584145Sjlemon		 * Is the interface even up?
28675353Smjacob		 */
28784145Sjlemon		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
28875353Smjacob			return (0);
28975353Smjacob
29075353Smjacob		/*
29184145Sjlemon		 * Only used for autonegotiation.
29275353Smjacob		 */
29384145Sjlemon		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
29484145Sjlemon			break;
29575353Smjacob
29675353Smjacob		/*
29784145Sjlemon		 * check for link.
29884145Sjlemon		 * Read the status register twice; BMSR_LINK is latch-low.
29975353Smjacob		 */
30084145Sjlemon		reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
30184145Sjlemon		if (reg & BMSR_LINK)
30284145Sjlemon			break;
30375353Smjacob
30475353Smjacob		/*
30584145Sjlemon		 * Only retry autonegotiation every 5 seconds.
30675353Smjacob		 */
30784145Sjlemon		if (++sc->mii_ticks != 5)
30884145Sjlemon			return (0);
30975353Smjacob
31084145Sjlemon		sc->mii_ticks = 0;
31175353Smjacob		e1000phy_reset(sc);
31296026Sphk		e1000phy_mii_phy_auto(sc);
31396026Sphk		return (0);
31475353Smjacob	}
31575353Smjacob
31675353Smjacob	/* Update the media status. */
31775353Smjacob	e1000phy_status(sc);
31875353Smjacob
31975353Smjacob	/* Callback if something changed. */
32084145Sjlemon	mii_phy_update(sc, cmd);
32175353Smjacob	return (0);
32275353Smjacob}
32375353Smjacob
32484145Sjlemonstatic void
32575353Smjacobe1000phy_status(struct mii_softc *sc)
32675353Smjacob{
32775353Smjacob	struct mii_data *mii = sc->mii_pdata;
32875353Smjacob	int bmsr, bmcr, esr, ssr, isr, ar, lpar;
32975353Smjacob
33075353Smjacob	mii->mii_media_status = IFM_AVALID;
33175353Smjacob	mii->mii_media_active = IFM_ETHER;
33275353Smjacob
33375353Smjacob	bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR);
33475353Smjacob	esr = PHY_READ(sc, E1000_ESR);
33575353Smjacob	bmcr = PHY_READ(sc, E1000_CR);
33675353Smjacob	ssr = PHY_READ(sc, E1000_SSR);
33775353Smjacob	isr = PHY_READ(sc, E1000_ISR);
33875353Smjacob	ar = PHY_READ(sc, E1000_AR);
33975353Smjacob	lpar = PHY_READ(sc, E1000_LPAR);
34075353Smjacob
34175353Smjacob	if (bmsr & E1000_SR_LINK_STATUS)
34275353Smjacob		mii->mii_media_status |= IFM_ACTIVE;
34375353Smjacob
34475353Smjacob	if (bmcr & E1000_CR_LOOPBACK)
34575353Smjacob		mii->mii_media_active |= IFM_LOOP;
34675353Smjacob
34796026Sphk	if ((!(bmsr & E1000_SR_AUTO_NEG_COMPLETE) || !(ssr & E1000_SSR_LINK) ||
34875353Smjacob	    !(ssr & E1000_SSR_SPD_DPLX_RESOLVED))) {
34975353Smjacob		/* Erg, still trying, I guess... */
35075353Smjacob		mii->mii_media_active |= IFM_NONE;
35175353Smjacob		return;
35275353Smjacob	}
35375353Smjacob
35475353Smjacob	if (ssr & E1000_SSR_1000MBS)
35595673Sphk		mii->mii_media_active |= IFM_1000_T;
35675353Smjacob	else if (ssr & E1000_SSR_100MBS)
35775353Smjacob		mii->mii_media_active |= IFM_100_TX;
35875353Smjacob	else
35975353Smjacob		mii->mii_media_active |= IFM_10_T;
36075353Smjacob
36175353Smjacob	if (ssr & E1000_SSR_DUPLEX)
36275353Smjacob		mii->mii_media_active |= IFM_FDX;
36375353Smjacob	else
36475353Smjacob		mii->mii_media_active |= IFM_HDX;
36575353Smjacob
36675353Smjacob	/* FLAG0==rx-flow-control FLAG1==tx-flow-control */
36775353Smjacob	if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) {
36875353Smjacob		mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
36975353Smjacob	} else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
37075353Smjacob	    (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
37175353Smjacob		mii->mii_media_active |= IFM_FLAG1;
37275353Smjacob	} else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
37375353Smjacob	    !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
37475353Smjacob		mii->mii_media_active |= IFM_FLAG0;
37575353Smjacob	}
37675353Smjacob}
37775353Smjacob
37875353Smjacobstatic int
37996026Sphke1000phy_mii_phy_auto(struct mii_softc *mii)
38075353Smjacob{
38175353Smjacob
38296026Sphk	PHY_WRITE(mii, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD |
38396026Sphk	    E1000_AR_100TX | E1000_AR_100TX_FD |
38496026Sphk	    E1000_AR_PAUSE | E1000_AR_ASM_DIR);
38596026Sphk	PHY_WRITE(mii, E1000_1GCR, E1000_1GCR_1000T_FD);
38696026Sphk	PHY_WRITE(mii, E1000_CR,
38796026Sphk	    E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG);
38875353Smjacob
38975353Smjacob	return (EJUSTRETURN);
39075353Smjacob}
391