xref: /freebsd/sys/dev/mii/atphy.c (revision d2cd2263348c82766571de8f4f492a459aeae01f)
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 *);
85d1307e81SPyun YongHyeon static int	atphy_auto(struct mii_softc *);
86d1307e81SPyun YongHyeon 
87d1307e81SPyun YongHyeon static const struct mii_phydesc atphys[] = {
88d1307e81SPyun YongHyeon 	MII_PHY_DESC(ATHEROS, F1),
89ba26d470SStanislav Sedov 	MII_PHY_DESC(ATHEROS, F2),
90d1307e81SPyun YongHyeon 	MII_PHY_END
91d1307e81SPyun YongHyeon };
92d1307e81SPyun YongHyeon 
93d1307e81SPyun YongHyeon static int
94d1307e81SPyun YongHyeon atphy_probe(device_t dev)
95d1307e81SPyun YongHyeon {
96d1307e81SPyun YongHyeon 
97d1307e81SPyun YongHyeon 	return (mii_phy_dev_probe(dev, atphys, BUS_PROBE_DEFAULT));
98d1307e81SPyun YongHyeon }
99d1307e81SPyun YongHyeon 
100d1307e81SPyun YongHyeon static int
101d1307e81SPyun YongHyeon atphy_attach(device_t dev)
102d1307e81SPyun YongHyeon {
103d1307e81SPyun YongHyeon 	struct atphy_softc *asc;
104d1307e81SPyun YongHyeon 	struct mii_softc *sc;
105d1307e81SPyun YongHyeon 	struct mii_attach_args *ma;
106d1307e81SPyun YongHyeon 	struct mii_data *mii;
107d1307e81SPyun YongHyeon 
108d1307e81SPyun YongHyeon 	asc = device_get_softc(dev);
109d1307e81SPyun YongHyeon 	sc = &asc->mii_sc;
110d1307e81SPyun YongHyeon 	ma = device_get_ivars(dev);
111d1307e81SPyun YongHyeon 	sc->mii_dev = device_get_parent(dev);
112d1307e81SPyun YongHyeon 	mii = device_get_softc(sc->mii_dev);
113d1307e81SPyun YongHyeon 	LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
114d1307e81SPyun YongHyeon 
115d1307e81SPyun YongHyeon 	sc->mii_inst = mii->mii_instance;
116d1307e81SPyun YongHyeon 	sc->mii_phy = ma->mii_phyno;
117d1307e81SPyun YongHyeon 	sc->mii_service = atphy_service;
118d1307e81SPyun YongHyeon 	sc->mii_pdata = mii;
119d1307e81SPyun YongHyeon 	sc->mii_anegticks = MII_ANEGTICKS_GIGE;
120d1307e81SPyun YongHyeon 
121d1307e81SPyun YongHyeon 	mii->mii_instance++;
122d1307e81SPyun YongHyeon 
123d1307e81SPyun YongHyeon 	asc->mii_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
124d1307e81SPyun YongHyeon 	asc->mii_model = MII_MODEL(ma->mii_id2);
125d1307e81SPyun YongHyeon 	asc->mii_rev = MII_REV(ma->mii_id2);
126d1307e81SPyun YongHyeon 	if (bootverbose)
127d1307e81SPyun YongHyeon 		device_printf(dev, "OUI 0x%06x, model 0x%04x, rev. %d\n",
128d1307e81SPyun YongHyeon 		    asc->mii_oui, asc->mii_model, asc->mii_rev);
129d1307e81SPyun YongHyeon 
130d1307e81SPyun YongHyeon 	atphy_reset(sc);
131d1307e81SPyun YongHyeon 
132d1307e81SPyun YongHyeon 	sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
133d1307e81SPyun YongHyeon 	if (sc->mii_capabilities & BMSR_EXTSTAT)
134d1307e81SPyun YongHyeon 		sc->mii_extcapabilities = PHY_READ(sc, MII_EXTSR);
135d1307e81SPyun YongHyeon 	device_printf(dev, " ");
136d1307e81SPyun YongHyeon 	mii_phy_add_media(sc);
137d1307e81SPyun YongHyeon 	printf("\n");
138d1307e81SPyun YongHyeon 
139d1307e81SPyun YongHyeon 	MIIBUS_MEDIAINIT(sc->mii_dev);
140d1307e81SPyun YongHyeon 	return(0);
141d1307e81SPyun YongHyeon }
142d1307e81SPyun YongHyeon 
143d1307e81SPyun YongHyeon static int
144d1307e81SPyun YongHyeon atphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
145d1307e81SPyun YongHyeon {
146d1307e81SPyun YongHyeon 	struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
147d1307e81SPyun YongHyeon 	uint16_t anar, bmcr, bmsr;
148d1307e81SPyun YongHyeon 
149d1307e81SPyun YongHyeon 	switch (cmd) {
150d1307e81SPyun YongHyeon 	case MII_POLLSTAT:
151d1307e81SPyun YongHyeon 		/*
152d1307e81SPyun YongHyeon 		 * If we're not polling our PHY instance, just return.
153d1307e81SPyun YongHyeon 		 */
154d1307e81SPyun YongHyeon 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
155d1307e81SPyun YongHyeon 			return (0);
156d1307e81SPyun YongHyeon 		break;
157d1307e81SPyun YongHyeon 
158d1307e81SPyun YongHyeon 	case MII_MEDIACHG:
159d1307e81SPyun YongHyeon 		/*
160d1307e81SPyun YongHyeon 		 * If the media indicates a different PHY instance,
161d1307e81SPyun YongHyeon 		 * isolate ourselves.
162d1307e81SPyun YongHyeon 		 */
163d1307e81SPyun YongHyeon 		if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
164d1307e81SPyun YongHyeon 			bmcr = PHY_READ(sc, MII_BMCR);
165d1307e81SPyun YongHyeon 			PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
166d1307e81SPyun YongHyeon 			return (0);
167d1307e81SPyun YongHyeon 		}
168d1307e81SPyun YongHyeon 
169d1307e81SPyun YongHyeon 		/*
170d1307e81SPyun YongHyeon 		 * If the interface is not up, don't do anything.
171d1307e81SPyun YongHyeon 		 */
172d1307e81SPyun YongHyeon 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
173d1307e81SPyun YongHyeon 			break;
174d1307e81SPyun YongHyeon 
175d1307e81SPyun YongHyeon 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO ||
176d1307e81SPyun YongHyeon 		    IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
177d1307e81SPyun YongHyeon 			atphy_auto(sc);
178d1307e81SPyun YongHyeon 			break;
179d1307e81SPyun YongHyeon 		}
180d1307e81SPyun YongHyeon 
181d1307e81SPyun YongHyeon 		bmcr = 0;
182d1307e81SPyun YongHyeon 		switch (IFM_SUBTYPE(ife->ifm_media)) {
183d1307e81SPyun YongHyeon 		case IFM_100_TX:
184d1307e81SPyun YongHyeon 			bmcr = BMCR_S100;
185d1307e81SPyun YongHyeon 			break;
186d1307e81SPyun YongHyeon 		case IFM_10_T:
187d1307e81SPyun YongHyeon 			bmcr = BMCR_S10;
188d1307e81SPyun YongHyeon 			break;
189d1307e81SPyun YongHyeon 		case IFM_NONE:
190d1307e81SPyun YongHyeon 			bmcr = PHY_READ(sc, MII_BMCR);
191d1307e81SPyun YongHyeon 			/*
192d1307e81SPyun YongHyeon 			 * XXX
193d1307e81SPyun YongHyeon 			 * Due to an unknown reason powering down PHY resulted
194d1307e81SPyun YongHyeon 			 * in unexpected results such as inaccessbility of
195d1307e81SPyun YongHyeon 			 * hardware of freshly rebooted system. Disable
196d1307e81SPyun YongHyeon 			 * powering down PHY until I got more information for
197d1307e81SPyun YongHyeon 			 * Attansic/Atheros PHY hardwares.
198d1307e81SPyun YongHyeon 			 */
199d1307e81SPyun YongHyeon 			PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
200d1307e81SPyun YongHyeon 			goto done;
201d1307e81SPyun YongHyeon 		default:
202d1307e81SPyun YongHyeon 			return (EINVAL);
203d1307e81SPyun YongHyeon 		}
204d1307e81SPyun YongHyeon 
205d1307e81SPyun YongHyeon 		anar = atphy_anar(ife);
206d1307e81SPyun YongHyeon 		if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
207d1307e81SPyun YongHyeon 			bmcr |= BMCR_FDX;
208d1307e81SPyun YongHyeon 			/* Enable pause. */
209d1307e81SPyun YongHyeon 			anar |= (3 << 10);
210d1307e81SPyun YongHyeon 		}
211d1307e81SPyun YongHyeon 
212d1307e81SPyun YongHyeon 		if ((sc->mii_extcapabilities & (EXTSR_1000TFDX |
213d1307e81SPyun YongHyeon 		    EXTSR_1000THDX)) != 0)
214d1307e81SPyun YongHyeon 			PHY_WRITE(sc, MII_100T2CR, 0);
215d1307e81SPyun YongHyeon 		PHY_WRITE(sc, MII_ANAR, anar | ANAR_CSMA);
216d1307e81SPyun YongHyeon 
217d1307e81SPyun YongHyeon 		/*
218d1307e81SPyun YongHyeon 		 * Reset the PHY so all changes take effect.
219d1307e81SPyun YongHyeon 		 */
220d2cd2263SPyun YongHyeon 		PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET | BMCR_AUTOEN |
221d2cd2263SPyun YongHyeon 		    BMCR_STARTNEG);
222d1307e81SPyun YongHyeon done:
223d1307e81SPyun YongHyeon 		break;
224d1307e81SPyun YongHyeon 
225d1307e81SPyun YongHyeon 	case MII_TICK:
226d1307e81SPyun YongHyeon 		/*
227d1307e81SPyun YongHyeon 		 * If we're not currently selected, just return.
228d1307e81SPyun YongHyeon 		 */
229d1307e81SPyun YongHyeon 		if (IFM_INST(ife->ifm_media) != sc->mii_inst)
230d1307e81SPyun YongHyeon 			return (0);
231d1307e81SPyun YongHyeon 
232d1307e81SPyun YongHyeon 		/*
233d1307e81SPyun YongHyeon 		 * Is the interface even up?
234d1307e81SPyun YongHyeon 		 */
235d1307e81SPyun YongHyeon 		if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
236d1307e81SPyun YongHyeon 			return (0);
237d1307e81SPyun YongHyeon 
238d1307e81SPyun YongHyeon 		/*
239d1307e81SPyun YongHyeon 		 * Only used for autonegotiation.
240d1307e81SPyun YongHyeon 		 */
241d1307e81SPyun YongHyeon 		if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
242d1307e81SPyun YongHyeon 			sc->mii_ticks = 0;
243d1307e81SPyun YongHyeon 			break;
244d1307e81SPyun YongHyeon 		}
245d1307e81SPyun YongHyeon 
246d1307e81SPyun YongHyeon 		/*
247d1307e81SPyun YongHyeon 		 * check for link.
248d1307e81SPyun YongHyeon 		 * Read the status register twice; BMSR_LINK is latch-low.
249d1307e81SPyun YongHyeon 		 */
250d1307e81SPyun YongHyeon 		bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
251d1307e81SPyun YongHyeon 		if (bmsr & BMSR_LINK) {
252d1307e81SPyun YongHyeon 			sc->mii_ticks = 0;
253d1307e81SPyun YongHyeon 			break;
254d1307e81SPyun YongHyeon 		}
255d1307e81SPyun YongHyeon 
256d1307e81SPyun YongHyeon 		/* Announce link loss right after it happens. */
257d1307e81SPyun YongHyeon 		if (sc->mii_ticks++ == 0)
258d1307e81SPyun YongHyeon 			break;
259d1307e81SPyun YongHyeon 		if (sc->mii_ticks <= sc->mii_anegticks)
260d1307e81SPyun YongHyeon 			return (0);
261d1307e81SPyun YongHyeon 
262d1307e81SPyun YongHyeon 		sc->mii_ticks = 0;
263d1307e81SPyun YongHyeon 		atphy_auto(sc);
264d1307e81SPyun YongHyeon 		break;
265d1307e81SPyun YongHyeon 	}
266d1307e81SPyun YongHyeon 
267d1307e81SPyun YongHyeon 	/* Update the media status. */
268d1307e81SPyun YongHyeon 	atphy_status(sc);
269d1307e81SPyun YongHyeon 
270d1307e81SPyun YongHyeon 	/* Callback if something changed. */
271d1307e81SPyun YongHyeon 	mii_phy_update(sc, cmd);
272d1307e81SPyun YongHyeon 	return (0);
273d1307e81SPyun YongHyeon }
274d1307e81SPyun YongHyeon 
275d1307e81SPyun YongHyeon static void
276d1307e81SPyun YongHyeon atphy_status(struct mii_softc *sc)
277d1307e81SPyun YongHyeon {
278d1307e81SPyun YongHyeon 	struct mii_data *mii = sc->mii_pdata;
279d1307e81SPyun YongHyeon 	uint32_t bmsr, bmcr, ssr;
280d1307e81SPyun YongHyeon 
281d1307e81SPyun YongHyeon 	mii->mii_media_status = IFM_AVALID;
282d1307e81SPyun YongHyeon 	mii->mii_media_active = IFM_ETHER;
283d1307e81SPyun YongHyeon 
284d1307e81SPyun YongHyeon 	bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
285d1307e81SPyun YongHyeon 	if ((bmsr & BMSR_LINK) != 0)
286d1307e81SPyun YongHyeon 		mii->mii_media_status |= IFM_ACTIVE;
287d1307e81SPyun YongHyeon 
288d1307e81SPyun YongHyeon 	bmcr = PHY_READ(sc, MII_BMCR);
289d1307e81SPyun YongHyeon 	if ((bmcr & BMCR_ISO) != 0) {
290d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_NONE;
291d1307e81SPyun YongHyeon 		mii->mii_media_status = 0;
292d1307e81SPyun YongHyeon 		return;
293d1307e81SPyun YongHyeon 	}
294d1307e81SPyun YongHyeon 
295d1307e81SPyun YongHyeon 	if ((bmcr & BMCR_LOOP) != 0)
296d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_LOOP;
297d1307e81SPyun YongHyeon 
298d1307e81SPyun YongHyeon 	ssr = PHY_READ(sc, ATPHY_SSR);
299d1307e81SPyun YongHyeon 	if ((ssr & ATPHY_SSR_SPD_DPLX_RESOLVED) == 0) {
300d1307e81SPyun YongHyeon 		/* Erg, still trying, I guess... */
301d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_NONE;
302d1307e81SPyun YongHyeon 		return;
303d1307e81SPyun YongHyeon 	}
304d1307e81SPyun YongHyeon 
305d1307e81SPyun YongHyeon 	switch (ssr & ATPHY_SSR_SPEED_MASK) {
306d1307e81SPyun YongHyeon 	case ATPHY_SSR_1000MBS:
307d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_1000_T;
308d1307e81SPyun YongHyeon 		/*
309d1307e81SPyun YongHyeon 		 * atphy(4) got a valid link so reset mii_ticks.
310d1307e81SPyun YongHyeon 		 * Resetting mii_ticks is needed in order to
311d1307e81SPyun YongHyeon 		 * detect link loss after auto-negotiation.
312d1307e81SPyun YongHyeon 		 */
313d1307e81SPyun YongHyeon 		sc->mii_ticks = 0;
314d1307e81SPyun YongHyeon 		break;
315d1307e81SPyun YongHyeon 	case ATPHY_SSR_100MBS:
316d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_100_TX;
317d1307e81SPyun YongHyeon 		sc->mii_ticks = 0;
318d1307e81SPyun YongHyeon 		break;
319d1307e81SPyun YongHyeon 	case ATPHY_SSR_10MBS:
320d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_10_T;
321d1307e81SPyun YongHyeon 		sc->mii_ticks = 0;
322d1307e81SPyun YongHyeon 		break;
323d1307e81SPyun YongHyeon 	default:
324d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_NONE;
325d1307e81SPyun YongHyeon 		return;
326d1307e81SPyun YongHyeon 	}
327d1307e81SPyun YongHyeon 
328d1307e81SPyun YongHyeon 	if ((ssr & ATPHY_SSR_DUPLEX) != 0)
329d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_FDX;
330d1307e81SPyun YongHyeon 	else
331d1307e81SPyun YongHyeon 		mii->mii_media_active |= IFM_HDX;
332d1307e81SPyun YongHyeon 
333d1307e81SPyun YongHyeon 	/* XXX Master/Slave, Flow-control */
334d1307e81SPyun YongHyeon }
335d1307e81SPyun YongHyeon 
336d1307e81SPyun YongHyeon static void
337d1307e81SPyun YongHyeon atphy_reset(struct mii_softc *sc)
338d1307e81SPyun YongHyeon {
339d1307e81SPyun YongHyeon 	struct atphy_softc *asc;
340d1307e81SPyun YongHyeon 	uint32_t reg;
341d1307e81SPyun YongHyeon 	int i;
342d1307e81SPyun YongHyeon 
343d1307e81SPyun YongHyeon 	asc = (struct atphy_softc *)sc;
344d1307e81SPyun YongHyeon 
345d1307e81SPyun YongHyeon 	/* Take PHY out of power down mode. */
346d1307e81SPyun YongHyeon 	PHY_WRITE(sc, 29, 0x29);
347d1307e81SPyun YongHyeon 	PHY_WRITE(sc, 30, 0);
348d1307e81SPyun YongHyeon 
349d1307e81SPyun YongHyeon 	reg = PHY_READ(sc, ATPHY_SCR);
350d1307e81SPyun YongHyeon 	/* Enable automatic crossover. */
351d1307e81SPyun YongHyeon 	reg |= ATPHY_SCR_AUTO_X_MODE;
352d1307e81SPyun YongHyeon 	/* Disable power down. */
353d1307e81SPyun YongHyeon 	reg &= ~ATPHY_SCR_MAC_PDOWN;
354d1307e81SPyun YongHyeon 	/* Enable CRS on Tx. */
355d1307e81SPyun YongHyeon 	reg |= ATPHY_SCR_ASSERT_CRS_ON_TX;
356d1307e81SPyun YongHyeon 	/* Auto correction for reversed cable polarity. */
357d1307e81SPyun YongHyeon 	reg |= ATPHY_SCR_POLARITY_REVERSAL;
358d1307e81SPyun YongHyeon 	PHY_WRITE(sc, ATPHY_SCR, reg);
359d1307e81SPyun YongHyeon 
360d1307e81SPyun YongHyeon 	/* Workaround F1 bug to reset phy. */
361d1307e81SPyun YongHyeon 	atphy_auto(sc);
362d1307e81SPyun YongHyeon 
363d1307e81SPyun YongHyeon 	for (i = 0; i < 1000; i++) {
364d1307e81SPyun YongHyeon 		DELAY(1);
365d1307e81SPyun YongHyeon 		if ((PHY_READ(sc, MII_BMCR) & BMCR_RESET) == 0)
366d1307e81SPyun YongHyeon 			break;
367d1307e81SPyun YongHyeon 	}
368d1307e81SPyun YongHyeon }
369d1307e81SPyun YongHyeon 
370d1307e81SPyun YongHyeon static uint16_t
371d1307e81SPyun YongHyeon atphy_anar(struct ifmedia_entry *ife)
372d1307e81SPyun YongHyeon {
373d1307e81SPyun YongHyeon 	uint16_t anar;
374d1307e81SPyun YongHyeon 
375d1307e81SPyun YongHyeon 	anar = 0;
376d1307e81SPyun YongHyeon 	switch (IFM_SUBTYPE(ife->ifm_media)) {
377d1307e81SPyun YongHyeon 	case IFM_AUTO:
378d1307e81SPyun YongHyeon 		anar |= ANAR_TX_FD | ANAR_TX | ANAR_10_FD | ANAR_10;
379d1307e81SPyun YongHyeon 		return (anar);
380d1307e81SPyun YongHyeon 	case IFM_1000_T:
381d1307e81SPyun YongHyeon 		return (anar);
382d1307e81SPyun YongHyeon 	case IFM_100_TX:
383d1307e81SPyun YongHyeon 		anar |= ANAR_TX;
384d1307e81SPyun YongHyeon 		break;
385d1307e81SPyun YongHyeon 	case IFM_10_T:
386d1307e81SPyun YongHyeon 		anar |= ANAR_10;
387d1307e81SPyun YongHyeon 		break;
388d1307e81SPyun YongHyeon 	default:
389d1307e81SPyun YongHyeon 		return (0);
390d1307e81SPyun YongHyeon 	}
391d1307e81SPyun YongHyeon 
392d1307e81SPyun YongHyeon 	if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
393d1307e81SPyun YongHyeon 		if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_TX)
394d1307e81SPyun YongHyeon 			anar |= ANAR_TX_FD;
395d1307e81SPyun YongHyeon 		else
396d1307e81SPyun YongHyeon 			anar |= ANAR_10_FD;
397d1307e81SPyun YongHyeon 	}
398d1307e81SPyun YongHyeon 
399d1307e81SPyun YongHyeon 	return (anar);
400d1307e81SPyun YongHyeon }
401d1307e81SPyun YongHyeon 
402d1307e81SPyun YongHyeon static int
403d1307e81SPyun YongHyeon atphy_auto(struct mii_softc *sc)
404d1307e81SPyun YongHyeon {
405d1307e81SPyun YongHyeon 	uint16_t anar;
406d1307e81SPyun YongHyeon 
407d1307e81SPyun YongHyeon 	anar = BMSR_MEDIA_TO_ANAR(sc->mii_capabilities);
408d1307e81SPyun YongHyeon 	PHY_WRITE(sc, MII_ANAR, anar | (3 << 10) | ANAR_CSMA);
409d1307e81SPyun YongHyeon 	if ((sc->mii_extcapabilities & (EXTSR_1000TFDX | EXTSR_1000THDX)) != 0)
410d1307e81SPyun YongHyeon 		PHY_WRITE(sc, MII_100T2CR, GTCR_ADV_1000TFDX |
411d1307e81SPyun YongHyeon 		    GTCR_ADV_1000THDX);
412d1307e81SPyun YongHyeon 	PHY_WRITE(sc, MII_BMCR, BMCR_RESET | BMCR_AUTOEN | BMCR_STARTNEG);
413d1307e81SPyun YongHyeon 
414d1307e81SPyun YongHyeon 	return (EJUSTRETURN);
415d1307e81SPyun YongHyeon }
416