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