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