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