rgephy.c revision 180178
1/*-
2 * Copyright (c) 2003
3 *	Bill Paul <wpaul@windriver.com>.  All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by Bill Paul.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
30 * THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: head/sys/dev/mii/rgephy.c 180178 2008-07-02 08:10:18Z yongari $");
35
36/*
37 * Driver for the RealTek 8169S/8110S/8211B/8211C internal 10/100/1000 PHY.
38 */
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/module.h>
44#include <sys/socket.h>
45#include <sys/bus.h>
46
47#include <net/if.h>
48#include <net/if_arp.h>
49#include <net/if_media.h>
50
51#include <dev/mii/mii.h>
52#include <dev/mii/miivar.h>
53#include "miidevs.h"
54
55#include <dev/mii/rgephyreg.h>
56
57#include "miibus_if.h"
58
59#include <machine/bus.h>
60#include <pci/if_rlreg.h>
61
62static int rgephy_probe(device_t);
63static int rgephy_attach(device_t);
64
65struct rgephy_softc {
66	struct mii_softc mii_sc;
67	int mii_model;
68	int mii_revision;
69};
70
71static device_method_t rgephy_methods[] = {
72	/* device interface */
73	DEVMETHOD(device_probe,		rgephy_probe),
74	DEVMETHOD(device_attach,	rgephy_attach),
75	DEVMETHOD(device_detach,	mii_phy_detach),
76	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
77	{ 0, 0 }
78};
79
80static devclass_t rgephy_devclass;
81
82static driver_t rgephy_driver = {
83	"rgephy",
84	rgephy_methods,
85	sizeof(struct rgephy_softc)
86};
87
88DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0);
89
90static int	rgephy_service(struct mii_softc *, struct mii_data *, int);
91static void	rgephy_status(struct mii_softc *);
92static int	rgephy_mii_phy_auto(struct mii_softc *);
93static void	rgephy_reset(struct mii_softc *);
94static void	rgephy_loop(struct mii_softc *);
95static void	rgephy_load_dspcode(struct mii_softc *);
96
97static const struct mii_phydesc rgephys[] = {
98	MII_PHY_DESC(xxREALTEK, RTL8169S),
99	MII_PHY_END
100};
101
102static int
103rgephy_probe(device_t dev)
104{
105
106	return (mii_phy_dev_probe(dev, rgephys, BUS_PROBE_DEFAULT));
107}
108
109static int
110rgephy_attach(device_t dev)
111{
112	struct rgephy_softc *rsc;
113	struct mii_softc *sc;
114	struct mii_attach_args *ma;
115	struct mii_data *mii;
116	const char *sep = "";
117
118	rsc = device_get_softc(dev);
119	sc = &rsc->mii_sc;
120	ma = device_get_ivars(dev);
121	sc->mii_dev = device_get_parent(dev);
122	mii = device_get_softc(sc->mii_dev);
123	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
124
125	sc->mii_inst = mii->mii_instance;
126	sc->mii_phy = ma->mii_phyno;
127	sc->mii_service = rgephy_service;
128	sc->mii_pdata = mii;
129
130	mii->mii_instance++;
131
132	rsc->mii_model = MII_MODEL(ma->mii_id2);
133	rsc->mii_revision = MII_REV(ma->mii_id2);
134
135#define	ADD(m, c)	ifmedia_add(&mii->mii_media, (m), (c), NULL)
136#define PRINT(s)	printf("%s%s", sep, s); sep = ", "
137
138#if 0
139	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_LOOP, sc->mii_inst),
140	    BMCR_LOOP|BMCR_S100);
141#endif
142
143	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
144	sc->mii_capabilities &= ~BMSR_ANEG;
145	if (sc->mii_capabilities & BMSR_EXTSTAT)
146		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
147
148	device_printf(dev, " ");
149	mii_phy_add_media(sc);
150	/* RTL8169S do not report auto-sense; add manually. */
151	ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), MII_NMEDIA);
152	sep = ", ";
153	PRINT("auto");
154	printf("\n");
155#undef ADD
156#undef PRINT
157
158	rgephy_reset(sc);
159	MIIBUS_MEDIAINIT(sc->mii_dev);
160	return (0);
161}
162
163static int
164rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
165{
166	struct rgephy_softc *rsc;
167	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
168	int reg, speed, gig, anar;
169
170	rsc = (struct rgephy_softc *)sc;
171
172	switch (cmd) {
173	case MII_POLLSTAT:
174		/*
175		 * If we're not polling our PHY instance, just return.
176		 */
177		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
178			return (0);
179		break;
180
181	case MII_MEDIACHG:
182		/*
183		 * If the media indicates a different PHY instance,
184		 * isolate ourselves.
185		 */
186		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
187			reg = PHY_READ(sc, MII_BMCR);
188			PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
189			return (0);
190		}
191
192		/*
193		 * If the interface is not up, don't do anything.
194		 */
195		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
196			break;
197
198		rgephy_reset(sc);	/* XXX hardware bug work-around */
199
200		anar = PHY_READ(sc, RGEPHY_MII_ANAR);
201		anar &= ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX |
202		    RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10);
203
204		switch (IFM_SUBTYPE(ife->ifm_media)) {
205		case IFM_AUTO:
206#ifdef foo
207			/*
208			 * If we're already in auto mode, just return.
209			 */
210			if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN)
211				return (0);
212#endif
213			(void) rgephy_mii_phy_auto(sc);
214			break;
215		case IFM_1000_T:
216			speed = RGEPHY_S1000;
217			goto setit;
218		case IFM_100_TX:
219			speed = RGEPHY_S100;
220			anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX;
221			goto setit;
222		case IFM_10_T:
223			speed = RGEPHY_S10;
224			anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10;
225setit:
226			rgephy_loop(sc);
227			if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) {
228				speed |= RGEPHY_BMCR_FDX;
229				gig = RGEPHY_1000CTL_AFD;
230				anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10);
231			} else {
232				gig = RGEPHY_1000CTL_AHD;
233				anar &=
234				    ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD);
235			}
236
237			if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) {
238				PHY_WRITE(sc, RGEPHY_MII_1000CTL, 0);
239				PHY_WRITE(sc, RGEPHY_MII_ANAR, anar);
240				PHY_WRITE(sc, RGEPHY_MII_BMCR, speed |
241				    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
242				break;
243			}
244
245			/*
246			 * When setting the link manually, one side must
247			 * be the master and the other the slave. However
248			 * ifmedia doesn't give us a good way to specify
249			 * this, so we fake it by using one of the LINK
250			 * flags. If LINK0 is set, we program the PHY to
251			 * be a master, otherwise it's a slave.
252			 */
253			if ((mii->mii_ifp->if_flags & IFF_LINK0)) {
254				PHY_WRITE(sc, RGEPHY_MII_1000CTL,
255				    gig|RGEPHY_1000CTL_MSE|RGEPHY_1000CTL_MSC);
256			} else {
257				PHY_WRITE(sc, RGEPHY_MII_1000CTL,
258				    gig|RGEPHY_1000CTL_MSE);
259			}
260			PHY_WRITE(sc, RGEPHY_MII_BMCR, speed |
261			    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
262			break;
263		case IFM_NONE:
264			PHY_WRITE(sc, MII_BMCR, BMCR_ISO|BMCR_PDOWN);
265			break;
266		case IFM_100_T4:
267		default:
268			return (EINVAL);
269		}
270		break;
271
272	case MII_TICK:
273		/*
274		 * If we're not currently selected, just return.
275		 */
276		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
277			return (0);
278
279		/*
280		 * Is the interface even up?
281		 */
282		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
283			return (0);
284
285		/*
286		 * Only used for autonegotiation.
287		 */
288		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
289			sc->mii_ticks = 0;
290			break;
291		}
292
293		/*
294		 * Check to see if we have link.  If we do, we don't
295		 * need to restart the autonegotiation process.  Read
296		 * the BMSR twice in case it's latched.
297		 */
298		if (rsc->mii_revision >= 2) {
299			/* RTL8211B(L) */
300			reg = PHY_READ(sc, RGEPHY_MII_SSR);
301			if (reg & RGEPHY_SSR_LINK) {
302				sc->mii_ticks = 0;
303				break;
304			}
305		} else {
306			reg = PHY_READ(sc, RL_GMEDIASTAT);
307			if (reg & RL_GMEDIASTAT_LINK) {
308				sc->mii_ticks = 0;
309				break;
310			}
311		}
312
313		/* Announce link loss right after it happens. */
314		if (sc->mii_ticks++ == 0)
315			break;
316
317		/* Only retry autonegotiation every mii_anegticks seconds. */
318		if (sc->mii_ticks <= sc->mii_anegticks)
319			return (0);
320
321		sc->mii_ticks = 0;
322		rgephy_mii_phy_auto(sc);
323		break;
324	}
325
326	/* Update the media status. */
327	rgephy_status(sc);
328
329	/*
330	 * Callback if something changed. Note that we need to poke
331	 * the DSP on the RealTek PHYs if the media changes.
332	 *
333	 */
334	if (sc->mii_media_active != mii->mii_media_active ||
335	    sc->mii_media_status != mii->mii_media_status ||
336	    cmd == MII_MEDIACHG) {
337		rgephy_load_dspcode(sc);
338	}
339	mii_phy_update(sc, cmd);
340	return (0);
341}
342
343static void
344rgephy_status(struct mii_softc *sc)
345{
346	struct rgephy_softc *rsc;
347	struct mii_data *mii = sc->mii_pdata;
348	int bmsr, bmcr;
349	uint16_t ssr;
350
351	mii->mii_media_status = IFM_AVALID;
352	mii->mii_media_active = IFM_ETHER;
353
354	rsc = (struct rgephy_softc *)sc;
355	if (rsc->mii_revision >= 2) {
356		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
357		if (ssr & RGEPHY_SSR_LINK)
358			mii->mii_media_status |= IFM_ACTIVE;
359	} else {
360		bmsr = PHY_READ(sc, RL_GMEDIASTAT);
361		if (bmsr & RL_GMEDIASTAT_LINK)
362			mii->mii_media_status |= IFM_ACTIVE;
363	}
364
365	PHY_READ(sc, RGEPHY_MII_BMSR);
366	bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
367
368	bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
369	if (bmcr & RGEPHY_BMCR_ISO) {
370		mii->mii_media_active |= IFM_NONE;
371		mii->mii_media_status = 0;
372		return;
373	}
374
375	if (bmcr & RGEPHY_BMCR_LOOP)
376		mii->mii_media_active |= IFM_LOOP;
377
378	if (bmcr & RGEPHY_BMCR_AUTOEN) {
379		if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) {
380			/* Erg, still trying, I guess... */
381			mii->mii_media_active |= IFM_NONE;
382			return;
383		}
384	}
385
386	if (rsc->mii_revision >= 2) {
387		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
388		switch (ssr & RGEPHY_SSR_SPD_MASK) {
389		case RGEPHY_SSR_S1000:
390			mii->mii_media_active |= IFM_1000_T;
391			break;
392		case RGEPHY_SSR_S100:
393			mii->mii_media_active |= IFM_100_TX;
394			break;
395		case RGEPHY_SSR_S10:
396			mii->mii_media_active |= IFM_10_T;
397			break;
398		default:
399			mii->mii_media_active |= IFM_NONE;
400			break;
401		}
402		if (ssr & RGEPHY_SSR_FDX)
403			mii->mii_media_active |= IFM_FDX;
404		else
405			mii->mii_media_active |= IFM_HDX;
406	} else {
407		bmsr = PHY_READ(sc, RL_GMEDIASTAT);
408		if (bmsr & RL_GMEDIASTAT_1000MBPS)
409			mii->mii_media_active |= IFM_1000_T;
410		else if (bmsr & RL_GMEDIASTAT_100MBPS)
411			mii->mii_media_active |= IFM_100_TX;
412		else if (bmsr & RL_GMEDIASTAT_10MBPS)
413			mii->mii_media_active |= IFM_10_T;
414		else
415			mii->mii_media_active |= IFM_NONE;
416		if (bmsr & RL_GMEDIASTAT_FDX)
417			mii->mii_media_active |= IFM_FDX;
418		else
419			mii->mii_media_active |= IFM_HDX;
420	}
421}
422
423static int
424rgephy_mii_phy_auto(struct mii_softc *mii)
425{
426
427	rgephy_loop(mii);
428	rgephy_reset(mii);
429
430	PHY_WRITE(mii, RGEPHY_MII_ANAR,
431	    BMSR_MEDIA_TO_ANAR(mii->mii_capabilities) | ANAR_CSMA);
432	DELAY(1000);
433	PHY_WRITE(mii, RGEPHY_MII_1000CTL,
434            RGEPHY_1000CTL_AHD|RGEPHY_1000CTL_AFD);
435	DELAY(1000);
436	PHY_WRITE(mii, RGEPHY_MII_BMCR,
437	    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
438	DELAY(100);
439
440	return (EJUSTRETURN);
441}
442
443static void
444rgephy_loop(struct mii_softc *sc)
445{
446	struct rgephy_softc *rsc;
447	int i;
448
449	rsc = (struct rgephy_softc *)sc;
450	if (rsc->mii_revision < 2) {
451		PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
452		DELAY(1000);
453	}
454
455	for (i = 0; i < 15000; i++) {
456		if (!(PHY_READ(sc, RGEPHY_MII_BMSR) & RGEPHY_BMSR_LINK)) {
457#if 0
458			device_printf(sc->mii_dev, "looped %d\n", i);
459#endif
460			break;
461		}
462		DELAY(10);
463	}
464}
465
466#define PHY_SETBIT(x, y, z) \
467	PHY_WRITE(x, y, (PHY_READ(x, y) | (z)))
468#define PHY_CLRBIT(x, y, z) \
469	PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z)))
470
471/*
472 * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of
473 * existing revisions of the 8169S/8110S chips need to be tuned in
474 * order to reliably negotiate a 1000Mbps link. This is only needed
475 * for rev 0 and rev 1 of the PHY. Later versions work without
476 * any fixups.
477 */
478static void
479rgephy_load_dspcode(struct mii_softc *sc)
480{
481	struct rgephy_softc *rsc;
482	int val;
483
484	rsc = (struct rgephy_softc *)sc;
485	if (rsc->mii_revision >= 2)
486		return;
487
488	PHY_WRITE(sc, 31, 0x0001);
489	PHY_WRITE(sc, 21, 0x1000);
490	PHY_WRITE(sc, 24, 0x65C7);
491	PHY_CLRBIT(sc, 4, 0x0800);
492	val = PHY_READ(sc, 4) & 0xFFF;
493	PHY_WRITE(sc, 4, val);
494	PHY_WRITE(sc, 3, 0x00A1);
495	PHY_WRITE(sc, 2, 0x0008);
496	PHY_WRITE(sc, 1, 0x1020);
497	PHY_WRITE(sc, 0, 0x1000);
498	PHY_SETBIT(sc, 4, 0x0800);
499	PHY_CLRBIT(sc, 4, 0x0800);
500	val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000;
501	PHY_WRITE(sc, 4, val);
502	PHY_WRITE(sc, 3, 0xFF41);
503	PHY_WRITE(sc, 2, 0xDE60);
504	PHY_WRITE(sc, 1, 0x0140);
505	PHY_WRITE(sc, 0, 0x0077);
506	val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000;
507	PHY_WRITE(sc, 4, val);
508	PHY_WRITE(sc, 3, 0xDF01);
509	PHY_WRITE(sc, 2, 0xDF20);
510	PHY_WRITE(sc, 1, 0xFF95);
511	PHY_WRITE(sc, 0, 0xFA00);
512	val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000;
513	PHY_WRITE(sc, 4, val);
514	PHY_WRITE(sc, 3, 0xFF41);
515	PHY_WRITE(sc, 2, 0xDE20);
516	PHY_WRITE(sc, 1, 0x0140);
517	PHY_WRITE(sc, 0, 0x00BB);
518	val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000;
519	PHY_WRITE(sc, 4, val);
520	PHY_WRITE(sc, 3, 0xDF01);
521	PHY_WRITE(sc, 2, 0xDF20);
522	PHY_WRITE(sc, 1, 0xFF95);
523	PHY_WRITE(sc, 0, 0xBF00);
524	PHY_SETBIT(sc, 4, 0x0800);
525	PHY_CLRBIT(sc, 4, 0x0800);
526	PHY_WRITE(sc, 31, 0x0000);
527
528	DELAY(40);
529}
530
531static void
532rgephy_reset(struct mii_softc *sc)
533{
534	struct rgephy_softc *rsc;
535	uint16_t ssr;
536
537	rsc = (struct rgephy_softc *)sc;
538	if (rsc->mii_revision == 3) {
539		/* RTL8211C(L) */
540		ssr = PHY_READ(sc, RGEPHY_MII_SSR);
541		if ((ssr & RGEPHY_SSR_ALDPS) != 0) {
542			ssr &= ~RGEPHY_SSR_ALDPS;
543			PHY_WRITE(sc, RGEPHY_MII_SSR, ssr);
544		}
545	}
546
547	mii_phy_reset(sc);
548	DELAY(1000);
549	rgephy_load_dspcode(sc);
550}
551