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$");
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 <dev/rl/if_rlreg.h>
61
62static int rgephy_probe(device_t);
63static int rgephy_attach(device_t);
64
65static device_method_t rgephy_methods[] = {
66	/* device interface */
67	DEVMETHOD(device_probe,		rgephy_probe),
68	DEVMETHOD(device_attach,	rgephy_attach),
69	DEVMETHOD(device_detach,	mii_phy_detach),
70	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
71	DEVMETHOD_END
72};
73
74static devclass_t rgephy_devclass;
75
76static driver_t rgephy_driver = {
77	"rgephy",
78	rgephy_methods,
79	sizeof(struct mii_softc)
80};
81
82DRIVER_MODULE(rgephy, miibus, rgephy_driver, rgephy_devclass, 0, 0);
83
84static int	rgephy_service(struct mii_softc *, struct mii_data *, int);
85static void	rgephy_status(struct mii_softc *);
86static int	rgephy_mii_phy_auto(struct mii_softc *, int);
87static void	rgephy_reset(struct mii_softc *);
88static int	rgephy_linkup(struct mii_softc *);
89static void	rgephy_loop(struct mii_softc *);
90static void	rgephy_load_dspcode(struct mii_softc *);
91
92static const struct mii_phydesc rgephys[] = {
93	MII_PHY_DESC(REALTEK, RTL8169S),
94	MII_PHY_DESC(REALTEK, RTL8251),
95	MII_PHY_END
96};
97
98static const struct mii_phy_funcs rgephy_funcs = {
99	rgephy_service,
100	rgephy_status,
101	rgephy_reset
102};
103
104static int
105rgephy_probe(device_t dev)
106{
107
108	return (mii_phy_dev_probe(dev, rgephys, BUS_PROBE_DEFAULT));
109}
110
111static int
112rgephy_attach(device_t dev)
113{
114	struct mii_softc *sc;
115	struct mii_attach_args *ma;
116	u_int flags;
117
118	sc = device_get_softc(dev);
119	ma = device_get_ivars(dev);
120	flags = 0;
121	if (strcmp(ma->mii_data->mii_ifp->if_dname, "re") == 0)
122		flags |= MIIF_PHYPRIV0;
123	mii_phy_dev_attach(dev, flags, &rgephy_funcs, 0);
124
125	/* RTL8169S do not report auto-sense; add manually. */
126	sc->mii_capabilities = (PHY_READ(sc, MII_BMSR) | BMSR_ANEG) &
127	    sc->mii_capmask;
128	if (sc->mii_capabilities & BMSR_EXTSTAT)
129		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
130	device_printf(dev, " ");
131	mii_phy_add_media(sc);
132	printf("\n");
133	/*
134	 * Allow IFM_FLAG0 to be set indicating that auto-negotiation with
135	 * manual configuration, which is used to work around issues with
136	 * certain setups by default, should not be triggered as it may in
137	 * turn cause harm in some edge cases.
138	 */
139	sc->mii_pdata->mii_media.ifm_mask |= IFM_FLAG0;
140
141	PHY_RESET(sc);
142
143	MIIBUS_MEDIAINIT(sc->mii_dev);
144	return (0);
145}
146
147static int
148rgephy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
149{
150	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
151	int speed, gig, anar;
152
153	switch (cmd) {
154	case MII_POLLSTAT:
155		break;
156
157	case MII_MEDIACHG:
158		/*
159		 * If the interface is not up, don't do anything.
160		 */
161		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
162			break;
163
164		PHY_RESET(sc);	/* XXX hardware bug work-around */
165
166		anar = PHY_READ(sc, RGEPHY_MII_ANAR);
167		anar &= ~(RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP |
168		    RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX |
169		    RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10);
170
171		switch (IFM_SUBTYPE(ife->ifm_media)) {
172		case IFM_AUTO:
173#ifdef foo
174			/*
175			 * If we're already in auto mode, just return.
176			 */
177			if (PHY_READ(sc, RGEPHY_MII_BMCR) & RGEPHY_BMCR_AUTOEN)
178				return (0);
179#endif
180			(void)rgephy_mii_phy_auto(sc, ife->ifm_media);
181			break;
182		case IFM_1000_T:
183			speed = RGEPHY_S1000;
184			goto setit;
185		case IFM_100_TX:
186			speed = RGEPHY_S100;
187			anar |= RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_TX;
188			goto setit;
189		case IFM_10_T:
190			speed = RGEPHY_S10;
191			anar |= RGEPHY_ANAR_10_FD | RGEPHY_ANAR_10;
192setit:
193			if ((ife->ifm_media & IFM_FLOW) != 0 &&
194			    (mii->mii_media.ifm_media & IFM_FLAG0) != 0)
195				return (EINVAL);
196
197			if ((ife->ifm_media & IFM_FDX) != 0) {
198				speed |= RGEPHY_BMCR_FDX;
199				gig = RGEPHY_1000CTL_AFD;
200				anar &= ~(RGEPHY_ANAR_TX | RGEPHY_ANAR_10);
201				if ((ife->ifm_media & IFM_FLOW) != 0 ||
202				    (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
203					anar |=
204					    RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP;
205			} else {
206				gig = RGEPHY_1000CTL_AHD;
207				anar &=
208				    ~(RGEPHY_ANAR_TX_FD | RGEPHY_ANAR_10_FD);
209			}
210			if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
211				gig |= RGEPHY_1000CTL_MSE;
212				if ((ife->ifm_media & IFM_ETH_MASTER) != 0)
213				    gig |= RGEPHY_1000CTL_MSC;
214			} else {
215				gig = 0;
216				anar &= ~RGEPHY_ANAR_ASP;
217			}
218			if ((mii->mii_media.ifm_media & IFM_FLAG0) == 0)
219				speed |=
220				    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG;
221			rgephy_loop(sc);
222			PHY_WRITE(sc, RGEPHY_MII_1000CTL, gig);
223			PHY_WRITE(sc, RGEPHY_MII_ANAR, anar);
224			PHY_WRITE(sc, RGEPHY_MII_BMCR, speed);
225			break;
226		case IFM_NONE:
227			PHY_WRITE(sc, MII_BMCR, BMCR_ISO | BMCR_PDOWN);
228			break;
229		default:
230			return (EINVAL);
231		}
232		break;
233
234	case MII_TICK:
235		/*
236		 * Is the interface even up?
237		 */
238		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
239			return (0);
240
241		/*
242		 * Only used for autonegotiation.
243		 */
244		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
245			sc->mii_ticks = 0;
246			break;
247		}
248
249		/*
250		 * Check to see if we have link.  If we do, we don't
251		 * need to restart the autonegotiation process.
252		 */
253		if (rgephy_linkup(sc) != 0) {
254			sc->mii_ticks = 0;
255			break;
256		}
257
258		/* Announce link loss right after it happens. */
259		if (sc->mii_ticks++ == 0)
260			break;
261
262		/* Only retry autonegotiation every mii_anegticks seconds. */
263		if (sc->mii_ticks <= sc->mii_anegticks)
264			return (0);
265
266		sc->mii_ticks = 0;
267		rgephy_mii_phy_auto(sc, ife->ifm_media);
268		break;
269	}
270
271	/* Update the media status. */
272	PHY_STATUS(sc);
273
274	/*
275	 * Callback if something changed. Note that we need to poke
276	 * the DSP on the RealTek PHYs if the media changes.
277	 *
278	 */
279	if (sc->mii_media_active != mii->mii_media_active ||
280	    sc->mii_media_status != mii->mii_media_status ||
281	    cmd == MII_MEDIACHG) {
282		rgephy_load_dspcode(sc);
283	}
284	mii_phy_update(sc, cmd);
285	return (0);
286}
287
288static int
289rgephy_linkup(struct mii_softc *sc)
290{
291	int linkup;
292	uint16_t reg;
293
294	linkup = 0;
295	if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 &&
296	    sc->mii_mpd_rev >= RGEPHY_8211B) {
297		if (sc->mii_mpd_rev == RGEPHY_8211F) {
298			reg = PHY_READ(sc, RGEPHY_F_MII_SSR);
299			if (reg & RGEPHY_F_SSR_LINK)
300				linkup++;
301		} else {
302			reg = PHY_READ(sc, RGEPHY_MII_SSR);
303			if (reg & RGEPHY_SSR_LINK)
304				linkup++;
305		}
306	} else {
307		reg = PHY_READ(sc, RL_GMEDIASTAT);
308		if (reg & RL_GMEDIASTAT_LINK)
309			linkup++;
310	}
311
312	return (linkup);
313}
314
315static void
316rgephy_status(struct mii_softc *sc)
317{
318	struct mii_data *mii = sc->mii_pdata;
319	int bmsr, bmcr;
320	uint16_t ssr;
321
322	mii->mii_media_status = IFM_AVALID;
323	mii->mii_media_active = IFM_ETHER;
324
325	if (rgephy_linkup(sc) != 0)
326		mii->mii_media_status |= IFM_ACTIVE;
327
328	bmsr = PHY_READ(sc, RGEPHY_MII_BMSR);
329	bmcr = PHY_READ(sc, RGEPHY_MII_BMCR);
330	if (bmcr & RGEPHY_BMCR_ISO) {
331		mii->mii_media_active |= IFM_NONE;
332		mii->mii_media_status = 0;
333		return;
334	}
335
336	if (bmcr & RGEPHY_BMCR_LOOP)
337		mii->mii_media_active |= IFM_LOOP;
338
339	if (bmcr & RGEPHY_BMCR_AUTOEN) {
340		if ((bmsr & RGEPHY_BMSR_ACOMP) == 0) {
341			/* Erg, still trying, I guess... */
342			mii->mii_media_active |= IFM_NONE;
343			return;
344		}
345	}
346
347	if ((sc->mii_flags & MIIF_PHYPRIV0) == 0 &&
348	    sc->mii_mpd_rev >= RGEPHY_8211B) {
349		if (sc->mii_mpd_rev == RGEPHY_8211F) {
350			ssr = PHY_READ(sc, RGEPHY_F_MII_SSR);
351			switch (ssr & RGEPHY_F_SSR_SPD_MASK) {
352			case RGEPHY_F_SSR_S1000:
353				mii->mii_media_active |= IFM_1000_T;
354				break;
355			case RGEPHY_F_SSR_S100:
356				mii->mii_media_active |= IFM_100_TX;
357				break;
358			case RGEPHY_F_SSR_S10:
359				mii->mii_media_active |= IFM_10_T;
360				break;
361			default:
362				mii->mii_media_active |= IFM_NONE;
363				break;
364			}
365			if (ssr & RGEPHY_F_SSR_FDX)
366				mii->mii_media_active |= IFM_FDX;
367			else
368				mii->mii_media_active |= IFM_HDX;
369
370		} else {
371			ssr = PHY_READ(sc, RGEPHY_MII_SSR);
372			switch (ssr & RGEPHY_SSR_SPD_MASK) {
373			case RGEPHY_SSR_S1000:
374				mii->mii_media_active |= IFM_1000_T;
375				break;
376			case RGEPHY_SSR_S100:
377				mii->mii_media_active |= IFM_100_TX;
378				break;
379			case RGEPHY_SSR_S10:
380				mii->mii_media_active |= IFM_10_T;
381				break;
382			default:
383				mii->mii_media_active |= IFM_NONE;
384				break;
385			}
386			if (ssr & RGEPHY_SSR_FDX)
387				mii->mii_media_active |= IFM_FDX;
388			else
389				mii->mii_media_active |= IFM_HDX;
390		}
391	} else {
392		bmsr = PHY_READ(sc, RL_GMEDIASTAT);
393		if (bmsr & RL_GMEDIASTAT_1000MBPS)
394			mii->mii_media_active |= IFM_1000_T;
395		else if (bmsr & RL_GMEDIASTAT_100MBPS)
396			mii->mii_media_active |= IFM_100_TX;
397		else if (bmsr & RL_GMEDIASTAT_10MBPS)
398			mii->mii_media_active |= IFM_10_T;
399		else
400			mii->mii_media_active |= IFM_NONE;
401		if (bmsr & RL_GMEDIASTAT_FDX)
402			mii->mii_media_active |= IFM_FDX;
403		else
404			mii->mii_media_active |= IFM_HDX;
405	}
406
407	if ((mii->mii_media_active & IFM_FDX) != 0)
408		mii->mii_media_active |= mii_phy_flowstatus(sc);
409
410	if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) &&
411	    (PHY_READ(sc, RGEPHY_MII_1000STS) & RGEPHY_1000STS_MSR) != 0)
412		mii->mii_media_active |= IFM_ETH_MASTER;
413}
414
415static int
416rgephy_mii_phy_auto(struct mii_softc *sc, int media)
417{
418	int anar;
419
420	rgephy_loop(sc);
421	PHY_RESET(sc);
422
423	anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
424	if ((media & IFM_FLOW) != 0 || (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
425		anar |= RGEPHY_ANAR_PC | RGEPHY_ANAR_ASP;
426	PHY_WRITE(sc, RGEPHY_MII_ANAR, anar);
427	DELAY(1000);
428	PHY_WRITE(sc, RGEPHY_MII_1000CTL,
429	    RGEPHY_1000CTL_AHD | RGEPHY_1000CTL_AFD);
430	DELAY(1000);
431	PHY_WRITE(sc, RGEPHY_MII_BMCR,
432	    RGEPHY_BMCR_AUTOEN | RGEPHY_BMCR_STARTNEG);
433	DELAY(100);
434
435	return (EJUSTRETURN);
436}
437
438static void
439rgephy_loop(struct mii_softc *sc)
440{
441	int i;
442
443	if (sc->mii_mpd_model != MII_MODEL_REALTEK_RTL8251 &&
444	    sc->mii_mpd_rev < RGEPHY_8211B) {
445		PHY_WRITE(sc, RGEPHY_MII_BMCR, RGEPHY_BMCR_PDOWN);
446		DELAY(1000);
447	}
448
449	for (i = 0; i < 15000; i++) {
450		if (!(PHY_READ(sc, RGEPHY_MII_BMSR) & RGEPHY_BMSR_LINK)) {
451#if 0
452			device_printf(sc->mii_dev, "looped %d\n", i);
453#endif
454			break;
455		}
456		DELAY(10);
457	}
458}
459
460#define PHY_SETBIT(x, y, z) \
461	PHY_WRITE(x, y, (PHY_READ(x, y) | (z)))
462#define PHY_CLRBIT(x, y, z) \
463	PHY_WRITE(x, y, (PHY_READ(x, y) & ~(z)))
464
465/*
466 * Initialize RealTek PHY per the datasheet. The DSP in the PHYs of
467 * existing revisions of the 8169S/8110S chips need to be tuned in
468 * order to reliably negotiate a 1000Mbps link. This is only needed
469 * for rev 0 and rev 1 of the PHY. Later versions work without
470 * any fixups.
471 */
472static void
473rgephy_load_dspcode(struct mii_softc *sc)
474{
475	int val;
476
477	if (sc->mii_mpd_model == MII_MODEL_REALTEK_RTL8251 ||
478	    sc->mii_mpd_rev >= RGEPHY_8211B)
479		return;
480
481	PHY_WRITE(sc, 31, 0x0001);
482	PHY_WRITE(sc, 21, 0x1000);
483	PHY_WRITE(sc, 24, 0x65C7);
484	PHY_CLRBIT(sc, 4, 0x0800);
485	val = PHY_READ(sc, 4) & 0xFFF;
486	PHY_WRITE(sc, 4, val);
487	PHY_WRITE(sc, 3, 0x00A1);
488	PHY_WRITE(sc, 2, 0x0008);
489	PHY_WRITE(sc, 1, 0x1020);
490	PHY_WRITE(sc, 0, 0x1000);
491	PHY_SETBIT(sc, 4, 0x0800);
492	PHY_CLRBIT(sc, 4, 0x0800);
493	val = (PHY_READ(sc, 4) & 0xFFF) | 0x7000;
494	PHY_WRITE(sc, 4, val);
495	PHY_WRITE(sc, 3, 0xFF41);
496	PHY_WRITE(sc, 2, 0xDE60);
497	PHY_WRITE(sc, 1, 0x0140);
498	PHY_WRITE(sc, 0, 0x0077);
499	val = (PHY_READ(sc, 4) & 0xFFF) | 0xA000;
500	PHY_WRITE(sc, 4, val);
501	PHY_WRITE(sc, 3, 0xDF01);
502	PHY_WRITE(sc, 2, 0xDF20);
503	PHY_WRITE(sc, 1, 0xFF95);
504	PHY_WRITE(sc, 0, 0xFA00);
505	val = (PHY_READ(sc, 4) & 0xFFF) | 0xB000;
506	PHY_WRITE(sc, 4, val);
507	PHY_WRITE(sc, 3, 0xFF41);
508	PHY_WRITE(sc, 2, 0xDE20);
509	PHY_WRITE(sc, 1, 0x0140);
510	PHY_WRITE(sc, 0, 0x00BB);
511	val = (PHY_READ(sc, 4) & 0xFFF) | 0xF000;
512	PHY_WRITE(sc, 4, val);
513	PHY_WRITE(sc, 3, 0xDF01);
514	PHY_WRITE(sc, 2, 0xDF20);
515	PHY_WRITE(sc, 1, 0xFF95);
516	PHY_WRITE(sc, 0, 0xBF00);
517	PHY_SETBIT(sc, 4, 0x0800);
518	PHY_CLRBIT(sc, 4, 0x0800);
519	PHY_WRITE(sc, 31, 0x0000);
520
521	DELAY(40);
522}
523
524static void
525rgephy_reset(struct mii_softc *sc)
526{
527	uint16_t pcr, ssr;
528
529	switch (sc->mii_mpd_rev) {
530	case RGEPHY_8211F:
531		pcr = PHY_READ(sc, RGEPHY_F_MII_PCR1);
532		if ((pcr & RGEPHY_F_PCR1_MDI_MM) != 0) {
533			pcr &= ~RGEPHY_F_PCR1_MDI_MM;
534			PHY_WRITE(sc, RGEPHY_F_MII_PCR1, pcr);
535		}
536		break;
537	case RGEPHY_8211C:
538		if ((sc->mii_flags & MIIF_PHYPRIV0) == 0) {
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		/* FALLTHROUGH */
547	default:
548		if (sc->mii_mpd_rev >= RGEPHY_8211B) {
549			pcr = PHY_READ(sc, RGEPHY_MII_PCR);
550			if ((pcr & RGEPHY_PCR_MDIX_AUTO) == 0) {
551				pcr &= ~RGEPHY_PCR_MDI_MASK;
552				pcr |= RGEPHY_PCR_MDIX_AUTO;
553				PHY_WRITE(sc, RGEPHY_MII_PCR, pcr);
554			}
555		}
556		break;
557	}
558
559	mii_phy_reset(sc);
560	DELAY(1000);
561	rgephy_load_dspcode(sc);
562}
563