xref: /dragonfly/sys/dev/netif/mii_layer/rgephy.c (revision e5a5a436)
146ad174eSSepherosa Ziehau /*	$OpenBSD: rgephy.c,v 1.12 2006/06/27 05:36:58 brad Exp $	*/
246ad174eSSepherosa Ziehau 
346ad174eSSepherosa Ziehau /*
4eb2ada2eSSepherosa Ziehau  * Copyright (c) 2003
5eb2ada2eSSepherosa Ziehau  *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
6eb2ada2eSSepherosa Ziehau  *
7eb2ada2eSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
8eb2ada2eSSepherosa Ziehau  * modification, are permitted provided that the following conditions
9eb2ada2eSSepherosa Ziehau  * are met:
10eb2ada2eSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
11eb2ada2eSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
12eb2ada2eSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
13eb2ada2eSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
14eb2ada2eSSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
15eb2ada2eSSepherosa Ziehau  * 3. All advertising materials mentioning features or use of this software
16eb2ada2eSSepherosa Ziehau  *    must display the following acknowledgement:
17eb2ada2eSSepherosa Ziehau  *	This product includes software developed by Bill Paul.
18eb2ada2eSSepherosa Ziehau  * 4. Neither the name of the author nor the names of any co-contributors
19eb2ada2eSSepherosa Ziehau  *    may be used to endorse or promote products derived from this software
20eb2ada2eSSepherosa Ziehau  *    without specific prior written permission.
21eb2ada2eSSepherosa Ziehau  *
22eb2ada2eSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
23eb2ada2eSSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24eb2ada2eSSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25eb2ada2eSSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
26eb2ada2eSSepherosa Ziehau  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27eb2ada2eSSepherosa Ziehau  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28eb2ada2eSSepherosa Ziehau  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29eb2ada2eSSepherosa Ziehau  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30eb2ada2eSSepherosa Ziehau  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31eb2ada2eSSepherosa Ziehau  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
32eb2ada2eSSepherosa Ziehau  * THE POSSIBILITY OF SUCH DAMAGE.
33eb2ada2eSSepherosa Ziehau  *
34eb2ada2eSSepherosa Ziehau  * $FreeBSD: src/sys/dev/mii/rgephy.c,v 1.7 2005/09/30 19:39:27 imp Exp $
35eb2ada2eSSepherosa Ziehau  */
36eb2ada2eSSepherosa Ziehau 
37eb2ada2eSSepherosa Ziehau /*
387896c317SHasso Tepper  * Driver for the RealTek 8211B/8169S/8110S internal 10/100/1000 PHY.
39eb2ada2eSSepherosa Ziehau  */
40eb2ada2eSSepherosa Ziehau 
41eb2ada2eSSepherosa Ziehau #include <sys/param.h>
42eb2ada2eSSepherosa Ziehau #include <sys/systm.h>
43eb2ada2eSSepherosa Ziehau #include <sys/kernel.h>
44eb2ada2eSSepherosa Ziehau #include <sys/module.h>
45eb2ada2eSSepherosa Ziehau #include <sys/socket.h>
46eb2ada2eSSepherosa Ziehau #include <sys/bus.h>
47eb2ada2eSSepherosa Ziehau 
48eb2ada2eSSepherosa Ziehau #include <machine/clock.h>
49eb2ada2eSSepherosa Ziehau 
50eb2ada2eSSepherosa Ziehau #include <net/if.h>
51eb2ada2eSSepherosa Ziehau #include <net/if_arp.h>
52eb2ada2eSSepherosa Ziehau #include <net/if_media.h>
53eb2ada2eSSepherosa Ziehau 
54eb2ada2eSSepherosa Ziehau #include <dev/netif/mii_layer/mii.h>
55eb2ada2eSSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
56eb2ada2eSSepherosa Ziehau #include <dev/netif/mii_layer/rgephyreg.h>
57eb2ada2eSSepherosa Ziehau 
58eb2ada2eSSepherosa Ziehau #include "miibus_if.h"
59dcb4b80dSSascha Wildner #include "miidevs.h"
60eb2ada2eSSepherosa Ziehau 
61eb2ada2eSSepherosa Ziehau static int rgephy_probe(device_t);
62eb2ada2eSSepherosa Ziehau static int rgephy_attach(device_t);
63eb2ada2eSSepherosa Ziehau 
64eb2ada2eSSepherosa Ziehau static device_method_t rgephy_methods[] = {
65eb2ada2eSSepherosa Ziehau 	/* device interface */
66eb2ada2eSSepherosa Ziehau 	DEVMETHOD(device_probe,		rgephy_probe),
67eb2ada2eSSepherosa Ziehau 	DEVMETHOD(device_attach,	rgephy_attach),
68eb2ada2eSSepherosa Ziehau 	DEVMETHOD(device_detach,	ukphy_detach),
69eb2ada2eSSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
70d3c9c58eSSascha Wildner 	DEVMETHOD_END
71eb2ada2eSSepherosa Ziehau };
72eb2ada2eSSepherosa Ziehau 
7346ad174eSSepherosa Ziehau static const struct mii_phydesc rgephys[] = {
7446ad174eSSepherosa Ziehau 	MII_PHYDESC(REALTEK2,	RTL8169S),
7546ad174eSSepherosa Ziehau 	MII_PHYDESC(xxREALTEK,	RTL8169S),
76*318e2834SImre Vadasz 	MII_PHYDESC(xxREALTEK,	RTL8251),
7746ad174eSSepherosa Ziehau 	MII_PHYDESC_NULL
7846ad174eSSepherosa Ziehau };
7946ad174eSSepherosa Ziehau 
80eb2ada2eSSepherosa Ziehau static devclass_t rgephy_devclass;
81eb2ada2eSSepherosa Ziehau 
82eb2ada2eSSepherosa Ziehau static driver_t rgephy_driver = {
83eb2ada2eSSepherosa Ziehau 	"rgephy",
84eb2ada2eSSepherosa Ziehau 	rgephy_methods,
85eb2ada2eSSepherosa Ziehau 	sizeof(struct mii_softc)
86eb2ada2eSSepherosa Ziehau };
87eb2ada2eSSepherosa Ziehau 
88aa2b9d05SSascha Wildner DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, NULL, NULL);
89eb2ada2eSSepherosa Ziehau 
90eb2ada2eSSepherosa Ziehau static int	rgephy_service(struct mii_softc *, struct mii_data *, int);
91eb2ada2eSSepherosa Ziehau static void	rgephy_status(struct mii_softc *);
92eb2ada2eSSepherosa Ziehau static int	rgephy_mii_phy_auto(struct mii_softc *);
93eb2ada2eSSepherosa Ziehau static void	rgephy_reset(struct mii_softc *);
94eb2ada2eSSepherosa Ziehau static void	rgephy_loop(struct mii_softc *);
95eb2ada2eSSepherosa Ziehau static void	rgephy_load_dspcode(struct mii_softc *);
96eb2ada2eSSepherosa Ziehau 
97eb2ada2eSSepherosa Ziehau static int
rgephy_probe(device_t dev)98eb2ada2eSSepherosa Ziehau rgephy_probe(device_t dev)
99eb2ada2eSSepherosa Ziehau {
10046ad174eSSepherosa Ziehau 	struct mii_attach_args *ma = device_get_ivars(dev);
10146ad174eSSepherosa Ziehau 	const struct mii_phydesc *mpd;
102eb2ada2eSSepherosa Ziehau 
10346ad174eSSepherosa Ziehau 	mpd = mii_phy_match(ma, rgephys);
10446ad174eSSepherosa Ziehau 	if (mpd != NULL) {
10546ad174eSSepherosa Ziehau 		device_set_desc(dev, mpd->mpd_name);
10687884535SSepherosa Ziehau 		if (bootverbose)
10787884535SSepherosa Ziehau 			device_printf(dev, "rev: %d\n", MII_REV(ma->mii_id2));
108eb2ada2eSSepherosa Ziehau 		return (0);
109eb2ada2eSSepherosa Ziehau 	}
110eb2ada2eSSepherosa Ziehau 	return(ENXIO);
111eb2ada2eSSepherosa Ziehau }
112eb2ada2eSSepherosa Ziehau 
113eb2ada2eSSepherosa Ziehau static int
rgephy_attach(device_t dev)114eb2ada2eSSepherosa Ziehau rgephy_attach(device_t dev)
115eb2ada2eSSepherosa Ziehau {
116eb2ada2eSSepherosa Ziehau 	struct mii_softc *sc;
117eb2ada2eSSepherosa Ziehau 	struct mii_attach_args *ma;
118eb2ada2eSSepherosa Ziehau 	struct mii_data *mii;
119eb2ada2eSSepherosa Ziehau 
120eb2ada2eSSepherosa Ziehau 	sc = device_get_softc(dev);
121eb2ada2eSSepherosa Ziehau 	ma = device_get_ivars(dev);
122eb2ada2eSSepherosa Ziehau 	mii_softc_init(sc, ma);
123eb2ada2eSSepherosa Ziehau 	sc->mii_dev = device_get_parent(dev);
124eb2ada2eSSepherosa Ziehau 
125eb2ada2eSSepherosa Ziehau 	mii = device_get_softc(sc->mii_dev);
126eb2ada2eSSepherosa Ziehau 	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
127eb2ada2eSSepherosa Ziehau 
128eb2ada2eSSepherosa Ziehau 	sc->mii_inst = mii->mii_instance;
129eb2ada2eSSepherosa Ziehau 	sc->mii_service = rgephy_service;
13046ad174eSSepherosa Ziehau 	sc->mii_reset = rgephy_reset;
131eb2ada2eSSepherosa Ziehau 	sc->mii_pdata = mii;
132eb2ada2eSSepherosa Ziehau 
133eb2ada2eSSepherosa Ziehau 	sc->mii_flags |= MIIF_NOISOLATE;
134eb2ada2eSSepherosa Ziehau 	mii->mii_instance++;
135eb2ada2eSSepherosa Ziehau 
136eb2ada2eSSepherosa Ziehau 	rgephy_reset(sc);
137eb2ada2eSSepherosa Ziehau 
138eb2ada2eSSepherosa Ziehau 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
13946ad174eSSepherosa Ziehau 	if (sc->mii_capabilities & BMSR_EXTSTAT)
14046ad174eSSepherosa Ziehau 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
141eb2ada2eSSepherosa Ziehau 
142eb2ada2eSSepherosa Ziehau 	device_printf(dev, " ");
14346ad174eSSepherosa Ziehau 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
14446ad174eSSepherosa Ziehau 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
145e3869ec7SSascha Wildner 		kprintf("no media present");
14646ad174eSSepherosa Ziehau 	else
14746ad174eSSepherosa Ziehau 		mii_phy_add_media(sc);
148e3869ec7SSascha Wildner 	kprintf("\n");
149eb2ada2eSSepherosa Ziehau 
150eb2ada2eSSepherosa Ziehau 	MIIBUS_MEDIAINIT(sc->mii_dev);
151eb2ada2eSSepherosa Ziehau 	return(0);
152eb2ada2eSSepherosa Ziehau }
153eb2ada2eSSepherosa Ziehau 
154eb2ada2eSSepherosa Ziehau static int
rgephy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)155eb2ada2eSSepherosa Ziehau rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
156eb2ada2eSSepherosa Ziehau {
157eb2ada2eSSepherosa Ziehau 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
158eb2ada2eSSepherosa Ziehau 	int reg, speed, gig;
1597896c317SHasso Tepper 	uint16_t id2;
160eb2ada2eSSepherosa Ziehau 
161eb2ada2eSSepherosa Ziehau 	switch (cmd) {
162eb2ada2eSSepherosa Ziehau 	case MII_POLLSTAT:
163eb2ada2eSSepherosa Ziehau 		/*
164eb2ada2eSSepherosa Ziehau 		 * If we're not polling our PHY instance, just return.
165eb2ada2eSSepherosa Ziehau 		 */
166eb2ada2eSSepherosa Ziehau 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
167eb2ada2eSSepherosa Ziehau 			return (0);
168eb2ada2eSSepherosa Ziehau 		break;
169eb2ada2eSSepherosa Ziehau 
170eb2ada2eSSepherosa Ziehau 	case MII_MEDIACHG:
171eb2ada2eSSepherosa Ziehau 		/*
172eb2ada2eSSepherosa Ziehau 		 * If the media indicates a different PHY instance,
173eb2ada2eSSepherosa Ziehau 		 * isolate ourselves.
174eb2ada2eSSepherosa Ziehau 		 */
175eb2ada2eSSepherosa Ziehau 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
176eb2ada2eSSepherosa Ziehau 			reg = PHY_READ(sc, MII_BMCR);
177eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
178eb2ada2eSSepherosa Ziehau 			return (0);
179eb2ada2eSSepherosa Ziehau 		}
180eb2ada2eSSepherosa Ziehau 
181eb2ada2eSSepherosa Ziehau 		/*
182eb2ada2eSSepherosa Ziehau 		 * If the interface is not up, don't do anything.
183eb2ada2eSSepherosa Ziehau 		 */
184eb2ada2eSSepherosa Ziehau 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
185eb2ada2eSSepherosa Ziehau 			break;
186eb2ada2eSSepherosa Ziehau 
187eb2ada2eSSepherosa Ziehau 		rgephy_reset(sc);	/* XXX hardware bug work-around */
188eb2ada2eSSepherosa Ziehau 
189eb2ada2eSSepherosa Ziehau 		switch (IFM_SUBTYPE(ife->ifm_media)) {
190eb2ada2eSSepherosa Ziehau 		case IFM_AUTO:
191eb2ada2eSSepherosa Ziehau #ifdef foo
192eb2ada2eSSepherosa Ziehau 			/*
193eb2ada2eSSepherosa Ziehau 			 * If we're already in auto mode, just return.
194eb2ada2eSSepherosa Ziehau 			 */
195eb2ada2eSSepherosa Ziehau 			if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN)
196eb2ada2eSSepherosa Ziehau 				return (0);
197eb2ada2eSSepherosa Ziehau #endif
198eb2ada2eSSepherosa Ziehau 			rgephy_mii_phy_auto(sc);
199eb2ada2eSSepherosa Ziehau 			break;
200eb2ada2eSSepherosa Ziehau 		case IFM_1000_T:
201eb2ada2eSSepherosa Ziehau 			speed = RGEPHY_S1000;
202eb2ada2eSSepherosa Ziehau 			goto setit;
203eb2ada2eSSepherosa Ziehau 		case IFM_100_TX:
204eb2ada2eSSepherosa Ziehau 			speed = RGEPHY_S100;
205eb2ada2eSSepherosa Ziehau 			goto setit;
206eb2ada2eSSepherosa Ziehau 		case IFM_10_T:
207eb2ada2eSSepherosa Ziehau 			speed = RGEPHY_S10;
208eb2ada2eSSepherosa Ziehau setit:
209eb2ada2eSSepherosa Ziehau 			rgephy_loop(sc);
210eb2ada2eSSepherosa Ziehau 			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
211eb2ada2eSSepherosa Ziehau 				speed |= RGEPHY_BMCR_FDX;
212eb2ada2eSSepherosa Ziehau 				gig = RGEPHY_1000CTL_AFD;
213eb2ada2eSSepherosa Ziehau 			} else {
214eb2ada2eSSepherosa Ziehau 				gig = RGEPHY_1000CTL_AHD;
215eb2ada2eSSepherosa Ziehau 			}
216eb2ada2eSSepherosa Ziehau 
217eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0);
218eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, RGEPHY_MII_BMCR, speed);
219eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, RGEPHY_MII_ANAR, RGEPHY_SEL_TYPE);
220eb2ada2eSSepherosa Ziehau 
221eb2ada2eSSepherosa Ziehau 			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T)
222eb2ada2eSSepherosa Ziehau 				break;
223eb2ada2eSSepherosa Ziehau 
224eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig);
225eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, RGEPHY_MII_BMCR,
226eb2ada2eSSepherosa Ziehau 			    speed|RGEPHY_BMCR_AUTOEN|RGEPHY_BMCR_STARTNEG);
227eb2ada2eSSepherosa Ziehau 
228eb2ada2eSSepherosa Ziehau 			/*
229eb2ada2eSSepherosa Ziehau 			 * When settning the link manually, one side must
230eb2ada2eSSepherosa Ziehau 			 * be the master and the other the slave. However
231eb2ada2eSSepherosa Ziehau 			 * ifmedia doesn't give us a good way to specify
232eb2ada2eSSepherosa Ziehau 			 * this, so we fake it by using one of the LINK
233eb2ada2eSSepherosa Ziehau 			 * flags. If LINK0 is set, we program the PHY to
234eb2ada2eSSepherosa Ziehau 			 * be a master, otherwise it's a slave.
235eb2ada2eSSepherosa Ziehau 			 */
236eb2ada2eSSepherosa Ziehau 			if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
237eb2ada2eSSepherosa Ziehau 				PHY_WRITE(sc, RGEPHY_MII_1000CTL,
238eb2ada2eSSepherosa Ziehau 				    gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC);
239eb2ada2eSSepherosa Ziehau 			} else {
240eb2ada2eSSepherosa Ziehau 				PHY_WRITE(sc, RGEPHY_MII_1000CTL,
241eb2ada2eSSepherosa Ziehau 				    gig|RGEPHY_1000CTL_MSE);
242eb2ada2eSSepherosa Ziehau 			}
243eb2ada2eSSepherosa Ziehau 			break;
244eb2ada2eSSepherosa Ziehau #ifdef foo
245eb2ada2eSSepherosa Ziehau 		case IFM_NONE:
246eb2ada2eSSepherosa Ziehau 			PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
247eb2ada2eSSepherosa Ziehau 			break;
248eb2ada2eSSepherosa Ziehau #endif
249eb2ada2eSSepherosa Ziehau 		case IFM_100_T4:
250eb2ada2eSSepherosa Ziehau 		default:
251eb2ada2eSSepherosa Ziehau 			return (EINVAL);
252eb2ada2eSSepherosa Ziehau 		}
253eb2ada2eSSepherosa Ziehau 		break;
254eb2ada2eSSepherosa Ziehau 
255eb2ada2eSSepherosa Ziehau 	case MII_TICK:
256eb2ada2eSSepherosa Ziehau 		/*
257eb2ada2eSSepherosa Ziehau 		 * If we're not currently selected, just return.
258eb2ada2eSSepherosa Ziehau 		 */
259eb2ada2eSSepherosa Ziehau 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
260eb2ada2eSSepherosa Ziehau 			return (0);
261eb2ada2eSSepherosa Ziehau 
262eb2ada2eSSepherosa Ziehau 		/*
263eb2ada2eSSepherosa Ziehau 		 * Is the interface even up?
264eb2ada2eSSepherosa Ziehau 		 */
265eb2ada2eSSepherosa Ziehau 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
266eb2ada2eSSepherosa Ziehau 			return (0);
267eb2ada2eSSepherosa Ziehau 
268eb2ada2eSSepherosa Ziehau 		/*
269eb2ada2eSSepherosa Ziehau 		 * Only used for autonegotiation.
270eb2ada2eSSepherosa Ziehau 		 */
271eb2ada2eSSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
27246ad174eSSepherosa Ziehau 			break;
273eb2ada2eSSepherosa Ziehau 
274eb2ada2eSSepherosa Ziehau 		/*
275eb2ada2eSSepherosa Ziehau 		 * Check to see if we have link.  If we do, we don't
276eb2ada2eSSepherosa Ziehau 		 * need to restart the autonegotiation process.
277eb2ada2eSSepherosa Ziehau 		 *
278eb2ada2eSSepherosa Ziehau 		 * XXX Read the BMSR twice in case it's latched?
279eb2ada2eSSepherosa Ziehau 		 */
2807896c317SHasso Tepper 		id2 = PHY_READ(sc, MII_PHYIDR2);
2817896c317SHasso Tepper 
2827896c317SHasso Tepper 		if (MII_REV(id2) < 2) {
283eb2ada2eSSepherosa Ziehau 			reg = PHY_READ(sc, RE_GMEDIASTAT);
28412b5e22dSSepherosa Ziehau 			if (reg & RE_GMEDIASTAT_LINK) {
28512b5e22dSSepherosa Ziehau 				sc->mii_ticks = 0;
286eb2ada2eSSepherosa Ziehau 				break;
28712b5e22dSSepherosa Ziehau 			}
2887896c317SHasso Tepper 		} else {
2897896c317SHasso Tepper 			reg = PHY_READ(sc, RGEPHY_SR);
29012b5e22dSSepherosa Ziehau 			if (reg & RGEPHY_SR_LINK) {
29112b5e22dSSepherosa Ziehau 				sc->mii_ticks = 0;
2927896c317SHasso Tepper 				break;
2937896c317SHasso Tepper 			}
29412b5e22dSSepherosa Ziehau 		}
295eb2ada2eSSepherosa Ziehau 
296eb2ada2eSSepherosa Ziehau 		/*
29746ad174eSSepherosa Ziehau 		 * Only retry autonegotiation every mii_anegticks seconds.
298eb2ada2eSSepherosa Ziehau 		 */
29946ad174eSSepherosa Ziehau 		if (++sc->mii_ticks <= sc->mii_anegticks)
300eb2ada2eSSepherosa Ziehau 			break;
301eb2ada2eSSepherosa Ziehau 
302eb2ada2eSSepherosa Ziehau 		sc->mii_ticks = 0;
30346ad174eSSepherosa Ziehau 
30446ad174eSSepherosa Ziehau 		/*
30546ad174eSSepherosa Ziehau 		 * Although rgephy_mii_phy_auto() always returns EJUSTRETURN,
30646ad174eSSepherosa Ziehau 		 * we should not rely on that.
30746ad174eSSepherosa Ziehau 		 */
30846ad174eSSepherosa Ziehau 		if (rgephy_mii_phy_auto(sc) == EJUSTRETURN)
309eb2ada2eSSepherosa Ziehau 			return (0);
31046ad174eSSepherosa Ziehau 		break;
311eb2ada2eSSepherosa Ziehau 	}
312eb2ada2eSSepherosa Ziehau 
313eb2ada2eSSepherosa Ziehau 	/* Update the media status. */
314eb2ada2eSSepherosa Ziehau 	rgephy_status(sc);
315eb2ada2eSSepherosa Ziehau 
316eb2ada2eSSepherosa Ziehau 	/*
317eb2ada2eSSepherosa Ziehau 	 * Callback if something changed. Note that we need to poke
318eb2ada2eSSepherosa Ziehau 	 * the DSP on the RealTek PHYs if the media changes.
319eb2ada2eSSepherosa Ziehau 	 */
32046ad174eSSepherosa Ziehau 	if (sc->mii_media_active != mii->mii_media_active ||
32146ad174eSSepherosa Ziehau 	    sc->mii_media_status != mii->mii_media_status ||
32246ad174eSSepherosa Ziehau 	    cmd == MII_MEDIACHG)
323eb2ada2eSSepherosa Ziehau 		rgephy_load_dspcode(sc);
32446ad174eSSepherosa Ziehau 	mii_phy_update(sc, cmd);
325eb2ada2eSSepherosa Ziehau 	return (0);
326eb2ada2eSSepherosa Ziehau }
327eb2ada2eSSepherosa Ziehau 
328eb2ada2eSSepherosa Ziehau static void
rgephy_status(struct mii_softc * sc)329eb2ada2eSSepherosa Ziehau rgephy_status(struct mii_softc *sc)
330eb2ada2eSSepherosa Ziehau {
331eb2ada2eSSepherosa Ziehau 	struct mii_data *mii = sc->mii_pdata;
332eb2ada2eSSepherosa Ziehau 	int bmsr, bmcr;
3337896c317SHasso Tepper 	uint16_t id2;
334eb2ada2eSSepherosa Ziehau 
335eb2ada2eSSepherosa Ziehau 	mii->mii_media_status = IFM_AVALID;
336eb2ada2eSSepherosa Ziehau 	mii->mii_media_active = IFM_ETHER;
337eb2ada2eSSepherosa Ziehau 
3387896c317SHasso Tepper 	id2 = PHY_READ(sc, MII_PHYIDR2);
339eb2ada2eSSepherosa Ziehau 
3407896c317SHasso Tepper 	if (MII_REV(id2) < 2) {
3417896c317SHasso Tepper 		bmsr = PHY_READ(sc, RE_GMEDIASTAT);
342eb2ada2eSSepherosa Ziehau 		if (bmsr & RE_GMEDIASTAT_LINK)
343eb2ada2eSSepherosa Ziehau 			mii->mii_media_status |= IFM_ACTIVE;
3447896c317SHasso Tepper 	} else {
3457896c317SHasso Tepper 		bmsr = PHY_READ(sc, RGEPHY_SR);
3467896c317SHasso Tepper 		if (bmsr & RGEPHY_SR_LINK)
3477896c317SHasso Tepper 			mii->mii_media_status |= IFM_ACTIVE;
3487896c317SHasso Tepper 	}
3497896c317SHasso Tepper 
350eb2ada2eSSepherosa Ziehau 	bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
351eb2ada2eSSepherosa Ziehau 
352eb2ada2eSSepherosa Ziehau 	bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
353eb2ada2eSSepherosa Ziehau 
354eb2ada2eSSepherosa Ziehau 	if (bmcr & RGEPHY_BMCR_LOOP)
355eb2ada2eSSepherosa Ziehau 		mii->mii_media_active |= IFM_LOOP;
356eb2ada2eSSepherosa Ziehau 
357eb2ada2eSSepherosa Ziehau 	if (bmcr & RGEPHY_BMCR_AUTOEN) {
358eb2ada2eSSepherosa Ziehau 		if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) {
359eb2ada2eSSepherosa Ziehau 			/* Erg, still trying, I guess... */
360eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_NONE;
361eb2ada2eSSepherosa Ziehau 			return;
362eb2ada2eSSepherosa Ziehau 		}
363eb2ada2eSSepherosa Ziehau 	}
364eb2ada2eSSepherosa Ziehau 
3657896c317SHasso Tepper 	if (MII_REV(id2) < 2) {
366eb2ada2eSSepherosa Ziehau 		bmsr = PHY_READ(sc, RE_GMEDIASTAT);
3677896c317SHasso Tepper 		if (bmsr & RE_GMEDIASTAT_1000MBPS)
368eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_1000_T;
3697896c317SHasso Tepper 		else if (bmsr & RE_GMEDIASTAT_100MBPS)
370eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_100_TX;
3717896c317SHasso Tepper 		else if (bmsr & RE_GMEDIASTAT_10MBPS)
372eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_10_T;
3737896c317SHasso Tepper 		else
374eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_NONE;
375eb2ada2eSSepherosa Ziehau 		if (bmsr & RE_GMEDIASTAT_FDX)
376eb2ada2eSSepherosa Ziehau 			mii->mii_media_active |= IFM_FDX;
3777896c317SHasso Tepper 	} else {
3787896c317SHasso Tepper 		bmsr = PHY_READ(sc, RGEPHY_SR);
3797896c317SHasso Tepper 		if (RGEPHY_SR_SPEED(bmsr) == 2)
3807896c317SHasso Tepper 			mii->mii_media_active |= IFM_1000_T;
3817896c317SHasso Tepper 		else if (RGEPHY_SR_SPEED(bmsr) == 1)
3827896c317SHasso Tepper 			mii->mii_media_active |= IFM_100_TX;
3837896c317SHasso Tepper 		else if (RGEPHY_SR_SPEED(bmsr) == 0)
3847896c317SHasso Tepper 			mii->mii_media_active |= IFM_10_T;
3857896c317SHasso Tepper 		else
3867896c317SHasso Tepper 			mii->mii_media_active |= IFM_NONE;
3877896c317SHasso Tepper 		if (bmsr & RGEPHY_SR_FDX)
3887896c317SHasso Tepper 			mii->mii_media_active |= IFM_FDX;
3897896c317SHasso Tepper 	}
390eb2ada2eSSepherosa Ziehau }
391eb2ada2eSSepherosa Ziehau 
392eb2ada2eSSepherosa Ziehau static int
rgephy_mii_phy_auto(struct mii_softc * sc)39346ad174eSSepherosa Ziehau rgephy_mii_phy_auto(struct mii_softc *sc)
394eb2ada2eSSepherosa Ziehau {
3957896c317SHasso Tepper 	uint16_t id2;
3967896c317SHasso Tepper 
3977896c317SHasso Tepper 	id2 = PHY_READ(sc, MII_PHYIDR2);
3987896c317SHasso Tepper 	if (MII_REV(id2) < 2) {
39946ad174eSSepherosa Ziehau 		rgephy_loop(sc);
40046ad174eSSepherosa Ziehau 		rgephy_reset(sc);
4017896c317SHasso Tepper 	}
402eb2ada2eSSepherosa Ziehau 
40346ad174eSSepherosa Ziehau 	PHY_WRITE(sc, RGEPHY_MII_ANAR,
40446ad174eSSepherosa Ziehau 		  BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA);
405eb2ada2eSSepherosa Ziehau 	DELAY(1000);
40687884535SSepherosa Ziehau 	PHY_WRITE(sc, RGEPHY_MII_1000CTL,
40787884535SSepherosa Ziehau 	    RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD);
408eb2ada2eSSepherosa Ziehau 	DELAY(1000);
40946ad174eSSepherosa Ziehau 	PHY_WRITE(sc, RGEPHY_MII_BMCR,
410eb2ada2eSSepherosa Ziehau 	    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
411eb2ada2eSSepherosa Ziehau 	DELAY(100);
412eb2ada2eSSepherosa Ziehau 
413eb2ada2eSSepherosa Ziehau 	return (EJUSTRETURN);
414eb2ada2eSSepherosa Ziehau }
415eb2ada2eSSepherosa Ziehau 
416eb2ada2eSSepherosa Ziehau static void
rgephy_loop(struct mii_softc * sc)417eb2ada2eSSepherosa Ziehau rgephy_loop(struct mii_softc *sc)
418eb2ada2eSSepherosa Ziehau {
41946ad174eSSepherosa Ziehau 	uint32_t bmsr;
420eb2ada2eSSepherosa Ziehau 	int i;
4217896c317SHasso Tepper 	uint16_t id2;
422eb2ada2eSSepherosa Ziehau 
4237896c317SHasso Tepper 	id2 = PHY_READ(sc, MII_PHYIDR2);
424*318e2834SImre Vadasz 	if (MII_MODEL(id2) != MII_MODEL_xxREALTEK_RTL8251 &&
425*318e2834SImre Vadasz 	    MII_REV(id2) < 2) {
426eb2ada2eSSepherosa Ziehau 		PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
427eb2ada2eSSepherosa Ziehau 		DELAY(1000);
4287896c317SHasso Tepper 	}
429eb2ada2eSSepherosa Ziehau 
430eb2ada2eSSepherosa Ziehau 	for (i = 0; i < 15000; i++) {
431eb2ada2eSSepherosa Ziehau 		bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
432eb2ada2eSSepherosa Ziehau 		if (!(bmsr & RGEPHY_BMSR_LINK)) {
433eb2ada2eSSepherosa Ziehau #if 0
434eb2ada2eSSepherosa Ziehau 			device_printf(sc->mii_dev, "looped %d\n", i);
435eb2ada2eSSepherosa Ziehau #endif
436eb2ada2eSSepherosa Ziehau 			break;
437eb2ada2eSSepherosa Ziehau 		}
438eb2ada2eSSepherosa Ziehau 		DELAY(10);
439eb2ada2eSSepherosa Ziehau 	}
440eb2ada2eSSepherosa Ziehau }
441eb2ada2eSSepherosa Ziehau 
442eb2ada2eSSepherosa Ziehau #define PHY_SETBIT(x, y, z) \
443eb2ada2eSSepherosa Ziehau 	PHY_WRITE(x, y, (PHY_READ(x, y) | (z)))
444eb2ada2eSSepherosa Ziehau #define PHY_CLRBIT(x, y, z) \
445eb2ada2eSSepherosa Ziehau 	PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z)))
446eb2ada2eSSepherosa Ziehau 
447eb2ada2eSSepherosa Ziehau /*
448eb2ada2eSSepherosa Ziehau  * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of
449eb2ada2eSSepherosa Ziehau  * existing revisions of the 8169S/8110S chips need to be tuned in
45087884535SSepherosa Ziehau  * order to reliably negotiate a 1000Mbps link. This is only needed
45187884535SSepherosa Ziehau  * for rev 0 and rev 1 of the PHY. Later versions work without
45287884535SSepherosa Ziehau  * any fixups.
453eb2ada2eSSepherosa Ziehau  */
454eb2ada2eSSepherosa Ziehau static void
rgephy_load_dspcode(struct mii_softc * sc)455eb2ada2eSSepherosa Ziehau rgephy_load_dspcode(struct mii_softc *sc)
456eb2ada2eSSepherosa Ziehau {
457eb2ada2eSSepherosa Ziehau 	int val;
458eb2ada2eSSepherosa Ziehau 
459*318e2834SImre Vadasz 	if (sc->mii_model == MII_MODEL_xxREALTEK_RTL8251 || sc->mii_rev > 1)
46087884535SSepherosa Ziehau 		return;
46187884535SSepherosa Ziehau 
462eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 31, 0x0001);
463eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 21, 0x1000);
464eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 24, 0x65C7);
465eb2ada2eSSepherosa Ziehau 	PHY_CLRBIT(sc, 4, 0x0800);
466eb2ada2eSSepherosa Ziehau 	val = PHY_READ(sc, 4) & 0xFFF;
467eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 4, val);
468eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 3, 0x00A1);
469eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 2, 0x0008);
470eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 1, 0x1020);
471eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 0, 0x1000);
472eb2ada2eSSepherosa Ziehau 	PHY_SETBIT(sc, 4, 0x0800);
473eb2ada2eSSepherosa Ziehau 	PHY_CLRBIT(sc, 4, 0x0800);
474eb2ada2eSSepherosa Ziehau 	val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000;
475eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 4, val);
476eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 3, 0xFF41);
477eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 2, 0xDE60);
478eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 1, 0x0140);
479eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 0, 0x0077);
480eb2ada2eSSepherosa Ziehau 	val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000;
481eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 4, val);
482eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 3, 0xDF01);
483eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 2, 0xDF20);
484eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 1, 0xFF95);
485eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 0, 0xFA00);
486eb2ada2eSSepherosa Ziehau 	val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000;
487eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 4, val);
488eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 3, 0xFF41);
489eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 2, 0xDE20);
490eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 1, 0x0140);
491eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 0, 0x00BB);
492eb2ada2eSSepherosa Ziehau 	val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000;
493eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 4, val);
494eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 3, 0xDF01);
495eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 2, 0xDF20);
496eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 1, 0xFF95);
497eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 0, 0xBF00);
498eb2ada2eSSepherosa Ziehau 	PHY_SETBIT(sc, 4, 0x0800);
499eb2ada2eSSepherosa Ziehau 	PHY_CLRBIT(sc, 4, 0x0800);
500eb2ada2eSSepherosa Ziehau 	PHY_WRITE(sc, 31, 0x0000);
501eb2ada2eSSepherosa Ziehau 
502eb2ada2eSSepherosa Ziehau 	DELAY(40);
503eb2ada2eSSepherosa Ziehau }
504eb2ada2eSSepherosa Ziehau 
505eb2ada2eSSepherosa Ziehau static void
rgephy_reset(struct mii_softc * sc)506eb2ada2eSSepherosa Ziehau rgephy_reset(struct mii_softc *sc)
507eb2ada2eSSepherosa Ziehau {
5087896c317SHasso Tepper 	uint16_t id2;
5097896c317SHasso Tepper 
510eb2ada2eSSepherosa Ziehau 	mii_phy_reset(sc);
5117896c317SHasso Tepper 
5127896c317SHasso Tepper 	id2 = PHY_READ(sc, MII_PHYIDR2);
5137896c317SHasso Tepper 	if (MII_REV(id2) < 2) {
514eb2ada2eSSepherosa Ziehau 		DELAY(1000);
515eb2ada2eSSepherosa Ziehau 		PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_AUTOEN);
516eb2ada2eSSepherosa Ziehau 		DELAY(1000);
5177896c317SHasso Tepper 	}
518eb2ada2eSSepherosa Ziehau 	rgephy_load_dspcode(sc);
519eb2ada2eSSepherosa Ziehau }
520