xref: /dflybsd-src/sys/dev/netif/mii_layer/atphy.c (revision 502d982c7d2fa8a5f352ab7ee72e877d7b541538)
1c0b7be40SSepherosa Ziehau /*-
2c0b7be40SSepherosa Ziehau  * Copyright (c) 2008, Pyun YongHyeon <yongari@FreeBSD.org>
3c0b7be40SSepherosa Ziehau  * All rights reserved.
4c0b7be40SSepherosa Ziehau  *
5c0b7be40SSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
6c0b7be40SSepherosa Ziehau  * modification, are permitted provided that the following conditions
7c0b7be40SSepherosa Ziehau  * are met:
8c0b7be40SSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
9c0b7be40SSepherosa Ziehau  *    notice unmodified, this list of conditions, and the following
10c0b7be40SSepherosa Ziehau  *    disclaimer.
11c0b7be40SSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
12c0b7be40SSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in the
13c0b7be40SSepherosa Ziehau  *    documentation and/or other materials provided with the distribution.
14c0b7be40SSepherosa Ziehau  *
15c0b7be40SSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c0b7be40SSepherosa Ziehau  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c0b7be40SSepherosa Ziehau  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c0b7be40SSepherosa Ziehau  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c0b7be40SSepherosa Ziehau  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c0b7be40SSepherosa Ziehau  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c0b7be40SSepherosa Ziehau  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c0b7be40SSepherosa Ziehau  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c0b7be40SSepherosa Ziehau  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c0b7be40SSepherosa Ziehau  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c0b7be40SSepherosa Ziehau  * SUCH DAMAGE.
26c0b7be40SSepherosa Ziehau  */
27c0b7be40SSepherosa Ziehau 
28c0b7be40SSepherosa Ziehau /*
29c0b7be40SSepherosa Ziehau  * Driver for the Attansic/Atheros F1 10/100/1000 PHY.
30c0b7be40SSepherosa Ziehau  */
31c0b7be40SSepherosa Ziehau 
32c0b7be40SSepherosa Ziehau #include <sys/param.h>
33c0b7be40SSepherosa Ziehau #include <sys/bus.h>
34*6421ab1dSMatthew Dillon #include <sys/systm.h>
35c0b7be40SSepherosa Ziehau #include <sys/kernel.h>
36*6421ab1dSMatthew Dillon #include <sys/module.h>
37*6421ab1dSMatthew Dillon #include <sys/socket.h>
38c0b7be40SSepherosa Ziehau 
39c0b7be40SSepherosa Ziehau #include <net/if.h>
40c0b7be40SSepherosa Ziehau #include <net/if_media.h>
41c0b7be40SSepherosa Ziehau 
42c0b7be40SSepherosa Ziehau #include <dev/netif/mii_layer/mii.h>
43c0b7be40SSepherosa Ziehau #include <dev/netif/mii_layer/miivar.h>
44c0b7be40SSepherosa Ziehau #include <dev/netif/mii_layer/atphyreg.h>
45c0b7be40SSepherosa Ziehau 
46c0b7be40SSepherosa Ziehau #include "miibus_if.h"
47dcb4b80dSSascha Wildner #include "miidevs.h"
48c0b7be40SSepherosa Ziehau 
49c0b7be40SSepherosa Ziehau static int	atphy_probe(device_t);
50c0b7be40SSepherosa Ziehau static int	atphy_attach(device_t);
51c0b7be40SSepherosa Ziehau static int	atphy_service(struct mii_softc *, struct mii_data *, int);
52c0b7be40SSepherosa Ziehau static void	atphy_status(struct mii_softc *);
53c0b7be40SSepherosa Ziehau static void	atphy_reset(struct mii_softc *);
54c0b7be40SSepherosa Ziehau static uint16_t	atphy_anar(struct ifmedia_entry *);
55*6421ab1dSMatthew Dillon static int	atphy_setmedia(struct mii_softc *sc, int media);
56c0b7be40SSepherosa Ziehau 
57c0b7be40SSepherosa Ziehau static device_method_t atphy_methods[] = {
58c0b7be40SSepherosa Ziehau 	/* Device interface. */
59c0b7be40SSepherosa Ziehau 	DEVMETHOD(device_probe,		atphy_probe),
60c0b7be40SSepherosa Ziehau 	DEVMETHOD(device_attach,	atphy_attach),
61c0b7be40SSepherosa Ziehau 	DEVMETHOD(device_detach,        ukphy_detach),
62c0b7be40SSepherosa Ziehau 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
63d3c9c58eSSascha Wildner 	DEVMETHOD_END
64c0b7be40SSepherosa Ziehau };
65c0b7be40SSepherosa Ziehau 
66c0b7be40SSepherosa Ziehau static devclass_t atphy_devclass;
67c0b7be40SSepherosa Ziehau static driver_t atphy_driver = {
68c0b7be40SSepherosa Ziehau 	"atphy",
69c0b7be40SSepherosa Ziehau 	atphy_methods,
70c0b7be40SSepherosa Ziehau 	sizeof(struct mii_softc)
71c0b7be40SSepherosa Ziehau };
72c0b7be40SSepherosa Ziehau 
73aa2b9d05SSascha Wildner DRIVER_MODULE(atphy, miibus, atphy_driver, atphy_devclass, NULL, NULL);
74c0b7be40SSepherosa Ziehau 
75*6421ab1dSMatthew Dillon static const struct mii_phydesc atphys[] = {
76*6421ab1dSMatthew Dillon #if 0
77*6421ab1dSMatthew Dillon 	MII_PHYDESC(xxATHEROS,	F1),
78*6421ab1dSMatthew Dillon 	MII_PHYDESC(xxATHEROS,	F1_7),
79*6421ab1dSMatthew Dillon 	MII_PHYDESC(xxATHEROS,	AR8021),
80*6421ab1dSMatthew Dillon 	MII_PHYDESC(xxATHEROS,	F2),
81*6421ab1dSMatthew Dillon #endif
82*6421ab1dSMatthew Dillon 	MII_PHYDESC(ATHEROS,	F1),
83*6421ab1dSMatthew Dillon 	MII_PHYDESC(ATHEROS,    F1_7),
84*6421ab1dSMatthew Dillon 	MII_PHYDESC(ATHEROS,    F2),
85*6421ab1dSMatthew Dillon 	MII_PHYDESC_NULL
86*6421ab1dSMatthew Dillon };
87*6421ab1dSMatthew Dillon 
88*6421ab1dSMatthew Dillon #if 0
89*6421ab1dSMatthew Dillon static const struct mii_phy_funcs atphy_funcs = {
90*6421ab1dSMatthew Dillon 	atphy_service,
91*6421ab1dSMatthew Dillon 	atphy_status,
92*6421ab1dSMatthew Dillon 	atphy_reset
93*6421ab1dSMatthew Dillon };
94*6421ab1dSMatthew Dillon #endif
95*6421ab1dSMatthew Dillon 
96c0b7be40SSepherosa Ziehau static int
atphy_probe(device_t dev)97c0b7be40SSepherosa Ziehau atphy_probe(device_t dev)
98c0b7be40SSepherosa Ziehau {
99*6421ab1dSMatthew Dillon 	/*return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT));*/
100c0b7be40SSepherosa Ziehau 	struct mii_attach_args *ma = device_get_ivars(dev);
101c0b7be40SSepherosa Ziehau 	const struct mii_phydesc *mpd;
102c0b7be40SSepherosa Ziehau 
103c0b7be40SSepherosa Ziehau 	mpd = mii_phy_match(ma, atphys);
104c0b7be40SSepherosa Ziehau 	if (mpd != NULL) {
105c0b7be40SSepherosa Ziehau 		device_set_desc(dev, mpd->mpd_name);
106c0b7be40SSepherosa Ziehau 		return 0;
107c0b7be40SSepherosa Ziehau 	}
108c0b7be40SSepherosa Ziehau 	return ENXIO;
109c0b7be40SSepherosa Ziehau }
110c0b7be40SSepherosa Ziehau 
111c0b7be40SSepherosa Ziehau static int
atphy_attach(device_t dev)112c0b7be40SSepherosa Ziehau atphy_attach(device_t dev)
113c0b7be40SSepherosa Ziehau {
114*6421ab1dSMatthew Dillon 	/*mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &atphy_funcs, 1);*/
115*6421ab1dSMatthew Dillon 
116c0b7be40SSepherosa Ziehau 	struct mii_softc *sc;
117c0b7be40SSepherosa Ziehau 	struct mii_attach_args *ma;
118c0b7be40SSepherosa Ziehau 	struct mii_data *mii;
119c0b7be40SSepherosa Ziehau 
120c0b7be40SSepherosa Ziehau 	sc = device_get_softc(dev);
121c0b7be40SSepherosa Ziehau 	ma = device_get_ivars(dev);
122c0b7be40SSepherosa Ziehau 
123c0b7be40SSepherosa Ziehau 	mii_softc_init(sc, ma);
124c0b7be40SSepherosa Ziehau 	sc->mii_dev = device_get_parent(dev);
125c0b7be40SSepherosa Ziehau 	mii = device_get_softc(sc->mii_dev);
126c0b7be40SSepherosa Ziehau 	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
127c0b7be40SSepherosa Ziehau 
128c0b7be40SSepherosa Ziehau 	sc->mii_inst = mii->mii_instance;
129c0b7be40SSepherosa Ziehau 	sc->mii_service = atphy_service;
130c0b7be40SSepherosa Ziehau 	sc->mii_pdata = mii;
131c0b7be40SSepherosa Ziehau 	sc->mii_anegticks = MII_ANEGTICKS_GIGE;
132c0b7be40SSepherosa Ziehau 
133c0b7be40SSepherosa Ziehau 	mii->mii_instance++;
134c0b7be40SSepherosa Ziehau 
135c0b7be40SSepherosa Ziehau 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
136c0b7be40SSepherosa Ziehau 	if (sc->mii_capabilities & BMSR_EXTSTAT)
137c0b7be40SSepherosa Ziehau 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
138c0b7be40SSepherosa Ziehau 
139c0b7be40SSepherosa Ziehau 	device_printf(dev, " ");
140c0b7be40SSepherosa Ziehau 	if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
141c0b7be40SSepherosa Ziehau 	    (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
142c0b7be40SSepherosa Ziehau 		kprintf("no media present");
143c0b7be40SSepherosa Ziehau 	else
144c0b7be40SSepherosa Ziehau 		mii_phy_add_media(sc);
145c0b7be40SSepherosa Ziehau 	kprintf("\n");
146c0b7be40SSepherosa Ziehau 
1474aff1962SSepherosa Ziehau 	atphy_reset(sc);
1484aff1962SSepherosa Ziehau 
149c0b7be40SSepherosa Ziehau 	MIIBUS_MEDIAINIT(sc->mii_dev);
150*6421ab1dSMatthew Dillon 	return (0);
151c0b7be40SSepherosa Ziehau }
152c0b7be40SSepherosa Ziehau 
153c0b7be40SSepherosa Ziehau static int
atphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)154c0b7be40SSepherosa Ziehau atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
155c0b7be40SSepherosa Ziehau {
156c0b7be40SSepherosa Ziehau 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
157c0b7be40SSepherosa Ziehau 	uint16_t anar, bmcr, bmsr;
158c0b7be40SSepherosa Ziehau 
159c0b7be40SSepherosa Ziehau 	switch (cmd) {
160c0b7be40SSepherosa Ziehau 	case MII_POLLSTAT:
161c0b7be40SSepherosa Ziehau 		break;
162c0b7be40SSepherosa Ziehau 
163c0b7be40SSepherosa Ziehau 	case MII_MEDIACHG:
164c0b7be40SSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
165c0b7be40SSepherosa Ziehau 		    IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
166*6421ab1dSMatthew Dillon 			atphy_setmedia(sc, ife->ifm_media);
167c0b7be40SSepherosa Ziehau 			break;
168c0b7be40SSepherosa Ziehau 		}
169c0b7be40SSepherosa Ziehau 
170c0b7be40SSepherosa Ziehau 		bmcr = 0;
171c0b7be40SSepherosa Ziehau 		switch (IFM_SUBTYPE(ife->ifm_media)) {
172c0b7be40SSepherosa Ziehau 		case IFM_100_TX:
173c0b7be40SSepherosa Ziehau 			bmcr = BMCR_S100;
174c0b7be40SSepherosa Ziehau 			break;
175c0b7be40SSepherosa Ziehau 		case IFM_10_T:
176c0b7be40SSepherosa Ziehau 			bmcr = BMCR_S10;
177c0b7be40SSepherosa Ziehau 			break;
178c0b7be40SSepherosa Ziehau 		case IFM_NONE:
179c0b7be40SSepherosa Ziehau 			bmcr = PHY_READ(sc, MII_BMCR);
180c0b7be40SSepherosa Ziehau 			/*
181c0b7be40SSepherosa Ziehau 			 * XXX
182c0b7be40SSepherosa Ziehau 			 * Due to an unknown reason powering down PHY resulted
183*6421ab1dSMatthew Dillon 			 * in unexpected results such as inaccessibility of
184c0b7be40SSepherosa Ziehau 			 * hardware of freshly rebooted system. Disable
185c0b7be40SSepherosa Ziehau 			 * powering down PHY until I got more information for
186c0b7be40SSepherosa Ziehau 			 * Attansic/Atheros PHY hardwares.
187c0b7be40SSepherosa Ziehau 			 */
188c0b7be40SSepherosa Ziehau 			PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
189c0b7be40SSepherosa Ziehau 			goto done;
190c0b7be40SSepherosa Ziehau 		default:
191*6421ab1dSMatthew Dillon 			return (EINVAL);
192c0b7be40SSepherosa Ziehau 		}
193c0b7be40SSepherosa Ziehau 
194c0b7be40SSepherosa Ziehau 		anar = atphy_anar(ife);
195*6421ab1dSMatthew Dillon 		if ((ife->ifm_media & IFM_FDX) != 0) {
196c0b7be40SSepherosa Ziehau 			bmcr |= BMCR_FDX;
197*6421ab1dSMatthew Dillon #if defined(__FreeBSD__)
198*6421ab1dSMatthew Dillon 			if ((ife->ifm_media & IFM_FLOW) != 0 ||
199*6421ab1dSMatthew Dillon 			    (sc->mii_flags & MIIF_FORCEPAUSE) != 0)
200*6421ab1dSMatthew Dillon 				anar |= ANAR_PAUSE_TOWARDS;
201*6421ab1dSMatthew Dillon #else
202*6421ab1dSMatthew Dillon 			if ((ife->ifm_media & IFM_FLOW) != 0)
203*6421ab1dSMatthew Dillon 				anar |= ANAR_PAUSE_TOWARDS;
204*6421ab1dSMatthew Dillon #endif
205c0b7be40SSepherosa Ziehau 		}
206c0b7be40SSepherosa Ziehau 
207*6421ab1dSMatthew Dillon 		if ((sc->mii_extcapabilities & (EXTSR_1000TFDX |
208*6421ab1dSMatthew Dillon 		    EXTSR_1000THDX)) != 0)
209c0b7be40SSepherosa Ziehau 			PHY_WRITE(sc, MII_100T2CR, 0);
210c0b7be40SSepherosa Ziehau 		PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
211c0b7be40SSepherosa Ziehau 
212c0b7be40SSepherosa Ziehau 		/*
213c0b7be40SSepherosa Ziehau 		 * Reset the PHY so all changes take effect.
214c0b7be40SSepherosa Ziehau 		 */
215c0b7be40SSepherosa Ziehau 		PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN |
216c0b7be40SSepherosa Ziehau 		    BMCR_STARTNEG);
217c0b7be40SSepherosa Ziehau done:
218c0b7be40SSepherosa Ziehau 		break;
219c0b7be40SSepherosa Ziehau 
220c0b7be40SSepherosa Ziehau 	case MII_TICK:
221c0b7be40SSepherosa Ziehau 		/*
222c0b7be40SSepherosa Ziehau 		 * Only used for autonegotiation.
223c0b7be40SSepherosa Ziehau 		 */
224c0b7be40SSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
225c0b7be40SSepherosa Ziehau 			sc->mii_ticks = 0;
226c0b7be40SSepherosa Ziehau 			break;
227c0b7be40SSepherosa Ziehau 		}
228c0b7be40SSepherosa Ziehau 
229c0b7be40SSepherosa Ziehau 		/*
230*6421ab1dSMatthew Dillon 		 * Check for link.
231c0b7be40SSepherosa Ziehau 		 * Read the status register twice; BMSR_LINK is latch-low.
232c0b7be40SSepherosa Ziehau 		 */
233c0b7be40SSepherosa Ziehau 		bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
234c0b7be40SSepherosa Ziehau 		if (bmsr & BMSR_LINK) {
235c0b7be40SSepherosa Ziehau 			sc->mii_ticks = 0;
236c0b7be40SSepherosa Ziehau 			break;
237c0b7be40SSepherosa Ziehau 		}
238c0b7be40SSepherosa Ziehau 
239c0b7be40SSepherosa Ziehau 		/* Announce link loss right after it happens. */
240c0b7be40SSepherosa Ziehau 		if (sc->mii_ticks++ == 0)
241c0b7be40SSepherosa Ziehau 			break;
242c0b7be40SSepherosa Ziehau 		if (sc->mii_ticks <= sc->mii_anegticks)
243*6421ab1dSMatthew Dillon 			return (0);
244c0b7be40SSepherosa Ziehau 
245c0b7be40SSepherosa Ziehau 		sc->mii_ticks = 0;
246*6421ab1dSMatthew Dillon 		atphy_setmedia(sc, ife->ifm_media);
247c0b7be40SSepherosa Ziehau 		break;
248c0b7be40SSepherosa Ziehau 	}
249c0b7be40SSepherosa Ziehau 
250c0b7be40SSepherosa Ziehau 	/* Update the media status. */
251c0b7be40SSepherosa Ziehau 	atphy_status(sc);
252c0b7be40SSepherosa Ziehau 
253c0b7be40SSepherosa Ziehau 	/* Callback if something changed. */
254c0b7be40SSepherosa Ziehau 	mii_phy_update(sc, cmd);
255*6421ab1dSMatthew Dillon 	return (0);
256c0b7be40SSepherosa Ziehau }
257c0b7be40SSepherosa Ziehau 
258c0b7be40SSepherosa Ziehau static void
atphy_status(struct mii_softc * sc)259c0b7be40SSepherosa Ziehau atphy_status(struct mii_softc *sc)
260c0b7be40SSepherosa Ziehau {
261c0b7be40SSepherosa Ziehau 	struct mii_data *mii = sc->mii_pdata;
262c0b7be40SSepherosa Ziehau 	uint32_t bmsr, bmcr, ssr;
263c0b7be40SSepherosa Ziehau 
264c0b7be40SSepherosa Ziehau 	mii->mii_media_status = IFM_AVALID;
265c0b7be40SSepherosa Ziehau 	mii->mii_media_active = IFM_ETHER;
266c0b7be40SSepherosa Ziehau 
267c0b7be40SSepherosa Ziehau 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
268*6421ab1dSMatthew Dillon 	if ((bmsr & BMSR_LINK) != 0)
269c0b7be40SSepherosa Ziehau 		mii->mii_media_status |= IFM_ACTIVE;
270c0b7be40SSepherosa Ziehau 
271c0b7be40SSepherosa Ziehau 	bmcr = PHY_READ(sc, MII_BMCR);
272*6421ab1dSMatthew Dillon 	if ((bmcr & BMCR_ISO) != 0) {
273c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_NONE;
274c0b7be40SSepherosa Ziehau 		mii->mii_media_status = 0;
275c0b7be40SSepherosa Ziehau 		return;
276c0b7be40SSepherosa Ziehau 	}
277c0b7be40SSepherosa Ziehau 
278*6421ab1dSMatthew Dillon 	if ((bmcr & BMCR_LOOP) != 0)
279c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_LOOP;
280c0b7be40SSepherosa Ziehau 
281c0b7be40SSepherosa Ziehau 	ssr = PHY_READ(sc, ATPHY_SSR);
282c0b7be40SSepherosa Ziehau 	if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
283c0b7be40SSepherosa Ziehau 		/* Erg, still trying, I guess... */
284c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_NONE;
285c0b7be40SSepherosa Ziehau 		return;
286c0b7be40SSepherosa Ziehau 	}
287c0b7be40SSepherosa Ziehau 
288c0b7be40SSepherosa Ziehau 	switch (ssr & ATPHY_SSR_SPEED_MASK) {
289c0b7be40SSepherosa Ziehau 	case ATPHY_SSR_1000MBS:
290c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_1000_T;
291c0b7be40SSepherosa Ziehau 		/*
292*6421ab1dSMatthew Dillon 		 * atphy(4) has a valid link so reset mii_ticks.
293c0b7be40SSepherosa Ziehau 		 * Resetting mii_ticks is needed in order to
294c0b7be40SSepherosa Ziehau 		 * detect link loss after auto-negotiation.
295c0b7be40SSepherosa Ziehau 		 */
296c0b7be40SSepherosa Ziehau 		sc->mii_ticks = 0;
297c0b7be40SSepherosa Ziehau 		break;
298c0b7be40SSepherosa Ziehau 	case ATPHY_SSR_100MBS:
299c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_100_TX;
300c0b7be40SSepherosa Ziehau 		sc->mii_ticks = 0;
301c0b7be40SSepherosa Ziehau 		break;
302c0b7be40SSepherosa Ziehau 	case ATPHY_SSR_10MBS:
303c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_10_T;
304c0b7be40SSepherosa Ziehau 		sc->mii_ticks = 0;
305c0b7be40SSepherosa Ziehau 		break;
306c0b7be40SSepherosa Ziehau 	default:
307c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_NONE;
308c0b7be40SSepherosa Ziehau 		return;
309c0b7be40SSepherosa Ziehau 	}
310c0b7be40SSepherosa Ziehau 
311*6421ab1dSMatthew Dillon 	if ((ssr & ATPHY_SSR_DUPLEX) != 0)
312*6421ab1dSMatthew Dillon 		mii->mii_media_active |= IFM_FDX | mii_phy_flowstatus(sc);
313c0b7be40SSepherosa Ziehau 	else
314c0b7be40SSepherosa Ziehau 		mii->mii_media_active |= IFM_HDX;
315c0b7be40SSepherosa Ziehau 
316*6421ab1dSMatthew Dillon 	if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) &&
317*6421ab1dSMatthew Dillon 	    (PHY_READ(sc, MII_100T2SR) & GTSR_MS_RES) != 0)
318*6421ab1dSMatthew Dillon 		mii->mii_media_active |= IFM_ETH_MASTER;
319c0b7be40SSepherosa Ziehau }
320c0b7be40SSepherosa Ziehau 
321c0b7be40SSepherosa Ziehau static void
atphy_reset(struct mii_softc * sc)322c0b7be40SSepherosa Ziehau atphy_reset(struct mii_softc *sc)
323c0b7be40SSepherosa Ziehau {
324*6421ab1dSMatthew Dillon 	struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
325c0b7be40SSepherosa Ziehau 	uint32_t reg;
326c0b7be40SSepherosa Ziehau 	int i;
327c0b7be40SSepherosa Ziehau 
328c0b7be40SSepherosa Ziehau 	/* Take PHY out of power down mode. */
329c0b7be40SSepherosa Ziehau 	PHY_WRITE(sc, 29, 0x29);
330c0b7be40SSepherosa Ziehau 	PHY_WRITE(sc, 30, 0);
331c0b7be40SSepherosa Ziehau 
332c0b7be40SSepherosa Ziehau 	reg = PHY_READ(sc, ATPHY_SCR);
333c0b7be40SSepherosa Ziehau 	/* Enable automatic crossover. */
334c0b7be40SSepherosa Ziehau 	reg |= ATPHY_SCR_AUTO_X_MODE;
335c0b7be40SSepherosa Ziehau 	/* Disable power down. */
336c0b7be40SSepherosa Ziehau 	reg &= ~ATPHY_SCR_MAC_PDOWN;
337c0b7be40SSepherosa Ziehau 	/* Enable CRS on Tx. */
338c0b7be40SSepherosa Ziehau 	reg |= ATPHY_SCR_ASSERT_CRS_ON_TX;
339c0b7be40SSepherosa Ziehau 	/* Auto correction for reversed cable polarity. */
340c0b7be40SSepherosa Ziehau 	reg |= ATPHY_SCR_POLARITY_REVERSAL;
341c0b7be40SSepherosa Ziehau 	PHY_WRITE(sc, ATPHY_SCR, reg);
342c0b7be40SSepherosa Ziehau 
343c0b7be40SSepherosa Ziehau 	/* Workaround F1 bug to reset phy. */
344*6421ab1dSMatthew Dillon 	atphy_setmedia(sc, ife == NULL ? IFM_AUTO : ife->ifm_media);
345c0b7be40SSepherosa Ziehau 
346c0b7be40SSepherosa Ziehau 	for (i = 0; i < 1000; i++) {
347c0b7be40SSepherosa Ziehau 		DELAY(1);
348c0b7be40SSepherosa Ziehau 		if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
349c0b7be40SSepherosa Ziehau 			break;
350c0b7be40SSepherosa Ziehau 	}
351c0b7be40SSepherosa Ziehau }
352c0b7be40SSepherosa Ziehau 
353c0b7be40SSepherosa Ziehau static uint16_t
atphy_anar(struct ifmedia_entry * ife)354c0b7be40SSepherosa Ziehau atphy_anar(struct ifmedia_entry *ife)
355c0b7be40SSepherosa Ziehau {
356*6421ab1dSMatthew Dillon 	uint16_t anar;
357c0b7be40SSepherosa Ziehau 
358*6421ab1dSMatthew Dillon 	anar = 0;
359c0b7be40SSepherosa Ziehau 	switch (IFM_SUBTYPE(ife->ifm_media)) {
360c0b7be40SSepherosa Ziehau 	case IFM_AUTO:
361c0b7be40SSepherosa Ziehau 		anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
362*6421ab1dSMatthew Dillon 		return (anar);
363c0b7be40SSepherosa Ziehau 	case IFM_1000_T:
364*6421ab1dSMatthew Dillon 		return (anar);
365c0b7be40SSepherosa Ziehau 	case IFM_100_TX:
366c0b7be40SSepherosa Ziehau 		anar |= ANAR_TX;
367c0b7be40SSepherosa Ziehau 		break;
368c0b7be40SSepherosa Ziehau 	case IFM_10_T:
369c0b7be40SSepherosa Ziehau 		anar |= ANAR_10;
370c0b7be40SSepherosa Ziehau 		break;
371c0b7be40SSepherosa Ziehau 	default:
372*6421ab1dSMatthew Dillon 		return (0);
373c0b7be40SSepherosa Ziehau 	}
374c0b7be40SSepherosa Ziehau 
375*6421ab1dSMatthew Dillon 	if ((ife->ifm_media & IFM_FDX) != 0) {
376c0b7be40SSepherosa Ziehau 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX)
377c0b7be40SSepherosa Ziehau 			anar |= ANAR_TX_FD;
378c0b7be40SSepherosa Ziehau 		else
379c0b7be40SSepherosa Ziehau 			anar |= ANAR_10_FD;
380c0b7be40SSepherosa Ziehau 	}
381*6421ab1dSMatthew Dillon 
382*6421ab1dSMatthew Dillon 	return (anar);
383c0b7be40SSepherosa Ziehau }
384c0b7be40SSepherosa Ziehau 
385*6421ab1dSMatthew Dillon static int
atphy_setmedia(struct mii_softc * sc,int media)386*6421ab1dSMatthew Dillon atphy_setmedia(struct mii_softc *sc, int media)
387c0b7be40SSepherosa Ziehau {
388c0b7be40SSepherosa Ziehau 	uint16_t anar;
389c0b7be40SSepherosa Ziehau 
390*6421ab1dSMatthew Dillon 	anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities) | ANAR_CSMA;
391*6421ab1dSMatthew Dillon #if defined(__FreeBSD__)
392*6421ab1dSMatthew Dillon 	if ((IFM_SUBTYPE(media) == IFM_AUTO || (media & IFM_FDX) != 0) &&
393*6421ab1dSMatthew Dillon 	    ((media & IFM_FLOW) != 0 ||
394*6421ab1dSMatthew Dillon 	    (sc->mii_flags & MIIF_FORCEPAUSE) != 0))
395*6421ab1dSMatthew Dillon 		anar |= ANAR_PAUSE_TOWARDS;
396*6421ab1dSMatthew Dillon #else
397*6421ab1dSMatthew Dillon 	if ((IFM_SUBTYPE(media) == IFM_AUTO || (media & IFM_FDX) != 0) &&
398*6421ab1dSMatthew Dillon 	    ((media & IFM_FLOW) != 0))
399*6421ab1dSMatthew Dillon 		anar |= ANAR_PAUSE_TOWARDS;
400*6421ab1dSMatthew Dillon #endif
401*6421ab1dSMatthew Dillon 	PHY_WRITE(sc, MII_ANAR, anar);
402*6421ab1dSMatthew Dillon 	if ((sc->mii_extcapabilities &
403*6421ab1dSMatthew Dillon 	     (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0)
404c0b7be40SSepherosa Ziehau 		PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX |
405c0b7be40SSepherosa Ziehau 		    GTCR_ADV_1000THDX);
406*6421ab1dSMatthew Dillon 	else if (sc->mii_model == MII_MODEL_ATHEROS_F1) {
40701b73991SSepherosa Ziehau 		/*
40801b73991SSepherosa Ziehau 		 * AR8132 has 10/100 PHY and the PHY uses the same
40901b73991SSepherosa Ziehau 		 * model number of F1 gigabit PHY.  The PHY has no
41001b73991SSepherosa Ziehau 		 * ability to establish gigabit link so explicitly
41101b73991SSepherosa Ziehau 		 * disable 1000baseT configuration for the PHY.
41201b73991SSepherosa Ziehau 		 * Otherwise, there is a case that atphy(4) could
41301b73991SSepherosa Ziehau 		 * not establish a link against gigabit link partner
41401b73991SSepherosa Ziehau 		 * unless the link partner supports down-shifting.
41501b73991SSepherosa Ziehau 		 */
41601b73991SSepherosa Ziehau 		PHY_WRITE(sc, MII_100T2CR, 0);
417c0b7be40SSepherosa Ziehau 	}
418c0b7be40SSepherosa Ziehau 	PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG);
419*6421ab1dSMatthew Dillon 
420*6421ab1dSMatthew Dillon 	return (EJUSTRETURN);
421c0b7be40SSepherosa Ziehau }
422