Deleted Added
full compact
tlphy.c (50461) tlphy.c (50480)
1/* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Manuel Bouyer.
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69/*
70 * Driver for Texas Instruments's ThunderLAN PHYs
71 */
72
73#include <sys/param.h>
74#include <sys/systm.h>
75#include <sys/kernel.h>
76#include <sys/socket.h>
77#include <sys/errno.h>
78#include <sys/module.h>
79#include <sys/bus.h>
80
81#include <machine/bus.h>
82#include <machine/clock.h>
83
84#include <net/if.h>
85#include <net/if_media.h>
86
87#include <dev/mii/mii.h>
88#include <dev/mii/miivar.h>
89#include <dev/mii/miidevs.h>
90
91#include <dev/mii/tlphyreg.h>
92
93#include "miibus_if.h"
94
95#if !defined(lint)
96static const char rcsid[] =
1/* $NetBSD: tlphy.c,v 1.18 1999/05/14 11:40:28 drochner Exp $ */
2
3/*-
4 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*
41 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
42 *
43 * Redistribution and use in source and binary forms, with or without
44 * modification, are permitted provided that the following conditions
45 * are met:
46 * 1. Redistributions of source code must retain the above copyright
47 * notice, this list of conditions and the following disclaimer.
48 * 2. Redistributions in binary form must reproduce the above copyright
49 * notice, this list of conditions and the following disclaimer in the
50 * documentation and/or other materials provided with the distribution.
51 * 3. All advertising materials mentioning features or use of this software
52 * must display the following acknowledgement:
53 * This product includes software developed by Manuel Bouyer.
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69/*
70 * Driver for Texas Instruments's ThunderLAN PHYs
71 */
72
73#include <sys/param.h>
74#include <sys/systm.h>
75#include <sys/kernel.h>
76#include <sys/socket.h>
77#include <sys/errno.h>
78#include <sys/module.h>
79#include <sys/bus.h>
80
81#include <machine/bus.h>
82#include <machine/clock.h>
83
84#include <net/if.h>
85#include <net/if_media.h>
86
87#include <dev/mii/mii.h>
88#include <dev/mii/miivar.h>
89#include <dev/mii/miidevs.h>
90
91#include <dev/mii/tlphyreg.h>
92
93#include "miibus_if.h"
94
95#if !defined(lint)
96static const char rcsid[] =
97 "$Id$";
97 "$FreeBSD: head/sys/dev/mii/tlphy.c 50480 1999-08-28 02:16:32Z peter $";
98#endif
99
100struct tlphy_softc {
101 struct mii_softc sc_mii; /* generic PHY */
102 int sc_need_acomp;
103};
104
105static int tlphy_probe __P((device_t));
106static int tlphy_attach __P((device_t));
107static int tlphy_detach __P((device_t));
108
109static device_method_t tlphy_methods[] = {
110 /* device interface */
111 DEVMETHOD(device_probe, tlphy_probe),
112 DEVMETHOD(device_attach, tlphy_attach),
113 DEVMETHOD(device_detach, tlphy_detach),
114 DEVMETHOD(device_shutdown, bus_generic_shutdown),
115 { 0, 0 }
116};
117
118static devclass_t tlphy_devclass;
119
120static driver_t tlphy_driver = {
121 "tlphy",
122 tlphy_methods,
123 sizeof(struct tlphy_softc)
124};
125
126DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0);
127
128int tlphy_service __P((struct mii_softc *, struct mii_data *, int));
129int tlphy_auto __P((struct tlphy_softc *, int));
130void tlphy_acomp __P((struct tlphy_softc *));
131void tlphy_status __P((struct tlphy_softc *));
132
133static int tlphy_probe(dev)
134 device_t dev;
135{
136 struct mii_attach_args *ma;
137
138 ma = device_get_ivars(dev);
139
140 if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxTI ||
141 MII_MODEL(ma->mii_id2) != MII_MODEL_xxTI_TLAN10T)
142 return (ENXIO);
143
144 device_set_desc(dev, MII_STR_xxTI_TLAN10T);
145
146 return (0);
147}
148
149static int tlphy_attach(dev)
150 device_t dev;
151{
152 struct tlphy_softc *sc;
153 struct mii_attach_args *ma;
154 struct mii_data *mii;
155 const char *sep = "";
156 int capmask = 0xFFFFFFFF;
157
158 sc = device_get_softc(dev);
159 ma = device_get_ivars(dev);
160 sc->sc_mii.mii_dev = device_get_parent(dev);
161 mii = device_get_softc(sc->sc_mii.mii_dev);
162 LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list);
163
164 sc->sc_mii.mii_inst = mii->mii_instance;
165 sc->sc_mii.mii_phy = ma->mii_phyno;
166 sc->sc_mii.mii_service = tlphy_service;
167 sc->sc_mii.mii_pdata = mii;
168
169 if (mii->mii_instance) {
170 struct mii_softc *other;
171 device_t *devlist;
172 int devs, i;
173
174 device_get_children(sc->sc_mii.mii_dev, &devlist, &devs);
175 for (i = 0; i < devs; i++) {
176 if (strcmp(device_get_name(devlist[i]), "tlphy")) {
177 other = device_get_softc(devlist[i]);
178 capmask &= ~other->mii_capabilities;
179 break;
180 }
181 }
182 }
183
184 mii->mii_instance++;
185
186 sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE;
187 mii_phy_reset(&sc->sc_mii);
188 sc->sc_mii.mii_flags |= MIIF_NOISOLATE;
189
190 /*
191 * Note that if we're on a device that also supports 100baseTX,
192 * we are not going to want to use the built-in 10baseT port,
193 * since there will be another PHY on the MII wired up to the
194 * UTP connector. The parent indicates this to us by specifying
195 * the TLPHY_MEDIA_NO_10_T bit.
196 */
197 sc->sc_mii.mii_capabilities =
198 PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/;
199
200#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
201
202 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst),
203 BMCR_ISO);
204
205 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP,
206 sc->sc_mii.mii_inst), BMCR_LOOP);
207
208#define PRINT(s) printf("%s%s", sep, s); sep = ", "
209
210 device_printf(dev, " ");
211 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0);
212 PRINT("10base2/BNC");
213 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0);
214 PRINT("10base5/AUI");
215
216 if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) {
217 printf(sep);
218 mii_add_media(mii, sc->sc_mii.mii_capabilities,
219 sc->sc_mii.mii_inst);
220 }
221
222 printf("\n");
223#undef ADD
224#undef PRINT
225 MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev);
226 return(0);
227}
228
229static int tlphy_detach(dev)
230 device_t dev;
231{
232 struct tlphy_softc *sc;
233 struct mii_data *mii;
234
235 sc = device_get_softc(dev);
236 mii = device_get_softc(device_get_parent(dev));
237 sc->sc_mii.mii_dev = NULL;
238 LIST_REMOVE(&sc->sc_mii, mii_list);
239
240 return(0);
241}
242
243int
244tlphy_service(self, mii, cmd)
245 struct mii_softc *self;
246 struct mii_data *mii;
247 int cmd;
248{
249 struct tlphy_softc *sc = (struct tlphy_softc *)self;
250 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
251 int reg;
252
253 if ((sc->sc_mii.mii_flags & MIIF_DOINGAUTO) == 0 && sc->sc_need_acomp)
254 tlphy_acomp(sc);
255
256 switch (cmd) {
257 case MII_POLLSTAT:
258 /*
259 * If we're not polling our PHY instance, just return.
260 */
261 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
262 return (0);
263 break;
264
265 case MII_MEDIACHG:
266 /*
267 * If the media indicates a different PHY instance,
268 * isolate ourselves.
269 */
270 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) {
271 reg = PHY_READ(&sc->sc_mii, MII_BMCR);
272 PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO);
273 return (0);
274 }
275
276 /*
277 * If the interface is not up, don't do anything.
278 */
279 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
280 break;
281
282 switch (IFM_SUBTYPE(ife->ifm_media)) {
283 case IFM_AUTO:
284 /*
285 * The ThunderLAN PHY doesn't self-configure after
286 * an autonegotiation cycle, so there's no such
287 * thing as "already in auto mode".
288 */
289 (void) tlphy_auto(sc, 1);
290 break;
291 case IFM_10_2:
292 case IFM_10_5:
293 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
294 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
295 DELAY(100000);
296 break;
297 default:
298 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
299 DELAY(100000);
300 PHY_WRITE(&sc->sc_mii, MII_ANAR,
301 mii_anar(ife->ifm_media));
302 PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data);
303 }
304 break;
305
306 case MII_TICK:
307 /*
308 * If we're not currently selected, just return.
309 */
310 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
311 return (0);
312
313 /*
314 * Only used for autonegotiation.
315 */
316 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
317 return (0);
318
319 /*
320 * Is the interface even up?
321 */
322 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
323 return (0);
324
325 /*
326 * Check to see if we have link. If we do, we don't
327 * need to restart the autonegotiation process. Read
328 * the BMSR twice in case it's latched.
329 *
330 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
331 */
332 reg = PHY_READ(&sc->sc_mii, MII_BMSR) |
333 PHY_READ(&sc->sc_mii, MII_BMSR);
334 if (reg & BMSR_LINK)
335 return (0);
336
337 /*
338 * Only retry autonegotiation every 5 seconds.
339 */
340 if (++sc->sc_mii.mii_ticks != 5)
341 return (0);
342
343 sc->sc_mii.mii_ticks = 0;
344 mii_phy_reset(&sc->sc_mii);
345 if (tlphy_auto(sc, 0) == EJUSTRETURN)
346 return (0);
347 break;
348 }
349
350 /* Update the media status. */
351 tlphy_status(sc);
352
353 /* Callback if something changed. */
354 if (sc->sc_mii.mii_active != mii->mii_media_active ||
355 cmd == MII_MEDIACHG) {
356 MIIBUS_STATCHG(sc->sc_mii.mii_dev);
357 sc->sc_mii.mii_active = mii->mii_media_active;
358 }
359 return (0);
360}
361
362void
363tlphy_status(sc)
364 struct tlphy_softc *sc;
365{
366 struct mii_data *mii = sc->sc_mii.mii_pdata;
367 int bmsr, bmcr, tlctrl;
368
369 mii->mii_media_status = IFM_AVALID;
370 mii->mii_media_active = IFM_ETHER;
371
372 bmcr = PHY_READ(&sc->sc_mii, MII_BMCR);
373 if (bmcr & BMCR_ISO) {
374 mii->mii_media_active |= IFM_NONE;
375 mii->mii_media_status = 0;
376 return;
377 }
378
379 tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL);
380 if (tlctrl & CTRL_AUISEL) {
381 mii->mii_media_status = 0;
382 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
383 return;
384 }
385
386 bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) |
387 PHY_READ(&sc->sc_mii, MII_BMSR);
388 if (bmsr & BMSR_LINK)
389 mii->mii_media_status |= IFM_ACTIVE;
390
391 if (bmcr & BMCR_LOOP)
392 mii->mii_media_active |= IFM_LOOP;
393
394 /*
395 * Grr, braindead ThunderLAN PHY doesn't have any way to
396 * tell which media is actually active. (Note it also
397 * doesn't self-configure after autonegotiation.) We
398 * just have to report what's in the BMCR.
399 */
400 if (bmcr & BMCR_FDX)
401 mii->mii_media_active |= IFM_FDX;
402 mii->mii_media_active |= IFM_10_T;
403}
404
405int
406tlphy_auto(sc, waitfor)
407 struct tlphy_softc *sc;
408 int waitfor;
409{
410 int error;
411
412 switch ((error = mii_phy_auto(&sc->sc_mii, waitfor))) {
413 case EIO:
414 /*
415 * Just assume we're not in full-duplex mode.
416 * XXX Check link and try AUI/BNC?
417 */
418 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
419 break;
420
421 case EJUSTRETURN:
422 /* Flag that we need to program when it completes. */
423 sc->sc_need_acomp = 1;
424 break;
425
426 default:
427 tlphy_acomp(sc);
428 }
429
430 return (error);
431}
432
433void
434tlphy_acomp(sc)
435 struct tlphy_softc *sc;
436{
437 int aner, anlpar;
438
439 sc->sc_need_acomp = 0;
440
441 /*
442 * Grr, braindead ThunderLAN PHY doesn't self-configure
443 * after autonegotiation. We have to do it ourselves
444 * based on the link partner status.
445 */
446
447 aner = PHY_READ(&sc->sc_mii, MII_ANER);
448 if (aner & ANER_LPAN) {
449 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) &
450 PHY_READ(&sc->sc_mii, MII_ANAR);
451 if (anlpar & ANAR_10_FD) {
452 PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX);
453 return;
454 }
455 }
456 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
457}
98#endif
99
100struct tlphy_softc {
101 struct mii_softc sc_mii; /* generic PHY */
102 int sc_need_acomp;
103};
104
105static int tlphy_probe __P((device_t));
106static int tlphy_attach __P((device_t));
107static int tlphy_detach __P((device_t));
108
109static device_method_t tlphy_methods[] = {
110 /* device interface */
111 DEVMETHOD(device_probe, tlphy_probe),
112 DEVMETHOD(device_attach, tlphy_attach),
113 DEVMETHOD(device_detach, tlphy_detach),
114 DEVMETHOD(device_shutdown, bus_generic_shutdown),
115 { 0, 0 }
116};
117
118static devclass_t tlphy_devclass;
119
120static driver_t tlphy_driver = {
121 "tlphy",
122 tlphy_methods,
123 sizeof(struct tlphy_softc)
124};
125
126DRIVER_MODULE(tlphy, miibus, tlphy_driver, tlphy_devclass, 0, 0);
127
128int tlphy_service __P((struct mii_softc *, struct mii_data *, int));
129int tlphy_auto __P((struct tlphy_softc *, int));
130void tlphy_acomp __P((struct tlphy_softc *));
131void tlphy_status __P((struct tlphy_softc *));
132
133static int tlphy_probe(dev)
134 device_t dev;
135{
136 struct mii_attach_args *ma;
137
138 ma = device_get_ivars(dev);
139
140 if (MII_OUI(ma->mii_id1, ma->mii_id2) != MII_OUI_xxTI ||
141 MII_MODEL(ma->mii_id2) != MII_MODEL_xxTI_TLAN10T)
142 return (ENXIO);
143
144 device_set_desc(dev, MII_STR_xxTI_TLAN10T);
145
146 return (0);
147}
148
149static int tlphy_attach(dev)
150 device_t dev;
151{
152 struct tlphy_softc *sc;
153 struct mii_attach_args *ma;
154 struct mii_data *mii;
155 const char *sep = "";
156 int capmask = 0xFFFFFFFF;
157
158 sc = device_get_softc(dev);
159 ma = device_get_ivars(dev);
160 sc->sc_mii.mii_dev = device_get_parent(dev);
161 mii = device_get_softc(sc->sc_mii.mii_dev);
162 LIST_INSERT_HEAD(&mii->mii_phys, &sc->sc_mii, mii_list);
163
164 sc->sc_mii.mii_inst = mii->mii_instance;
165 sc->sc_mii.mii_phy = ma->mii_phyno;
166 sc->sc_mii.mii_service = tlphy_service;
167 sc->sc_mii.mii_pdata = mii;
168
169 if (mii->mii_instance) {
170 struct mii_softc *other;
171 device_t *devlist;
172 int devs, i;
173
174 device_get_children(sc->sc_mii.mii_dev, &devlist, &devs);
175 for (i = 0; i < devs; i++) {
176 if (strcmp(device_get_name(devlist[i]), "tlphy")) {
177 other = device_get_softc(devlist[i]);
178 capmask &= ~other->mii_capabilities;
179 break;
180 }
181 }
182 }
183
184 mii->mii_instance++;
185
186 sc->sc_mii.mii_flags &= ~MIIF_NOISOLATE;
187 mii_phy_reset(&sc->sc_mii);
188 sc->sc_mii.mii_flags |= MIIF_NOISOLATE;
189
190 /*
191 * Note that if we're on a device that also supports 100baseTX,
192 * we are not going to want to use the built-in 10baseT port,
193 * since there will be another PHY on the MII wired up to the
194 * UTP connector. The parent indicates this to us by specifying
195 * the TLPHY_MEDIA_NO_10_T bit.
196 */
197 sc->sc_mii.mii_capabilities =
198 PHY_READ(&sc->sc_mii, MII_BMSR) & capmask /*ma->mii_capmask*/;
199
200#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
201
202 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->sc_mii.mii_inst),
203 BMCR_ISO);
204
205 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_LOOP,
206 sc->sc_mii.mii_inst), BMCR_LOOP);
207
208#define PRINT(s) printf("%s%s", sep, s); sep = ", "
209
210 device_printf(dev, " ");
211 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_2, 0, sc->sc_mii.mii_inst), 0);
212 PRINT("10base2/BNC");
213 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_5, 0, sc->sc_mii.mii_inst), 0);
214 PRINT("10base5/AUI");
215
216 if (sc->sc_mii.mii_capabilities & BMSR_MEDIAMASK) {
217 printf(sep);
218 mii_add_media(mii, sc->sc_mii.mii_capabilities,
219 sc->sc_mii.mii_inst);
220 }
221
222 printf("\n");
223#undef ADD
224#undef PRINT
225 MIIBUS_MEDIAINIT(sc->sc_mii.mii_dev);
226 return(0);
227}
228
229static int tlphy_detach(dev)
230 device_t dev;
231{
232 struct tlphy_softc *sc;
233 struct mii_data *mii;
234
235 sc = device_get_softc(dev);
236 mii = device_get_softc(device_get_parent(dev));
237 sc->sc_mii.mii_dev = NULL;
238 LIST_REMOVE(&sc->sc_mii, mii_list);
239
240 return(0);
241}
242
243int
244tlphy_service(self, mii, cmd)
245 struct mii_softc *self;
246 struct mii_data *mii;
247 int cmd;
248{
249 struct tlphy_softc *sc = (struct tlphy_softc *)self;
250 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
251 int reg;
252
253 if ((sc->sc_mii.mii_flags & MIIF_DOINGAUTO) == 0 && sc->sc_need_acomp)
254 tlphy_acomp(sc);
255
256 switch (cmd) {
257 case MII_POLLSTAT:
258 /*
259 * If we're not polling our PHY instance, just return.
260 */
261 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
262 return (0);
263 break;
264
265 case MII_MEDIACHG:
266 /*
267 * If the media indicates a different PHY instance,
268 * isolate ourselves.
269 */
270 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst) {
271 reg = PHY_READ(&sc->sc_mii, MII_BMCR);
272 PHY_WRITE(&sc->sc_mii, MII_BMCR, reg | BMCR_ISO);
273 return (0);
274 }
275
276 /*
277 * If the interface is not up, don't do anything.
278 */
279 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
280 break;
281
282 switch (IFM_SUBTYPE(ife->ifm_media)) {
283 case IFM_AUTO:
284 /*
285 * The ThunderLAN PHY doesn't self-configure after
286 * an autonegotiation cycle, so there's no such
287 * thing as "already in auto mode".
288 */
289 (void) tlphy_auto(sc, 1);
290 break;
291 case IFM_10_2:
292 case IFM_10_5:
293 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
294 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, CTRL_AUISEL);
295 DELAY(100000);
296 break;
297 default:
298 PHY_WRITE(&sc->sc_mii, MII_TLPHY_CTRL, 0);
299 DELAY(100000);
300 PHY_WRITE(&sc->sc_mii, MII_ANAR,
301 mii_anar(ife->ifm_media));
302 PHY_WRITE(&sc->sc_mii, MII_BMCR, ife->ifm_data);
303 }
304 break;
305
306 case MII_TICK:
307 /*
308 * If we're not currently selected, just return.
309 */
310 if (IFM_INST(ife->ifm_media) != sc->sc_mii.mii_inst)
311 return (0);
312
313 /*
314 * Only used for autonegotiation.
315 */
316 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
317 return (0);
318
319 /*
320 * Is the interface even up?
321 */
322 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
323 return (0);
324
325 /*
326 * Check to see if we have link. If we do, we don't
327 * need to restart the autonegotiation process. Read
328 * the BMSR twice in case it's latched.
329 *
330 * XXX WHAT ABOUT CHECKING LINK ON THE BNC/AUI?!
331 */
332 reg = PHY_READ(&sc->sc_mii, MII_BMSR) |
333 PHY_READ(&sc->sc_mii, MII_BMSR);
334 if (reg & BMSR_LINK)
335 return (0);
336
337 /*
338 * Only retry autonegotiation every 5 seconds.
339 */
340 if (++sc->sc_mii.mii_ticks != 5)
341 return (0);
342
343 sc->sc_mii.mii_ticks = 0;
344 mii_phy_reset(&sc->sc_mii);
345 if (tlphy_auto(sc, 0) == EJUSTRETURN)
346 return (0);
347 break;
348 }
349
350 /* Update the media status. */
351 tlphy_status(sc);
352
353 /* Callback if something changed. */
354 if (sc->sc_mii.mii_active != mii->mii_media_active ||
355 cmd == MII_MEDIACHG) {
356 MIIBUS_STATCHG(sc->sc_mii.mii_dev);
357 sc->sc_mii.mii_active = mii->mii_media_active;
358 }
359 return (0);
360}
361
362void
363tlphy_status(sc)
364 struct tlphy_softc *sc;
365{
366 struct mii_data *mii = sc->sc_mii.mii_pdata;
367 int bmsr, bmcr, tlctrl;
368
369 mii->mii_media_status = IFM_AVALID;
370 mii->mii_media_active = IFM_ETHER;
371
372 bmcr = PHY_READ(&sc->sc_mii, MII_BMCR);
373 if (bmcr & BMCR_ISO) {
374 mii->mii_media_active |= IFM_NONE;
375 mii->mii_media_status = 0;
376 return;
377 }
378
379 tlctrl = PHY_READ(&sc->sc_mii, MII_TLPHY_CTRL);
380 if (tlctrl & CTRL_AUISEL) {
381 mii->mii_media_status = 0;
382 mii->mii_media_active = mii->mii_media.ifm_cur->ifm_media;
383 return;
384 }
385
386 bmsr = PHY_READ(&sc->sc_mii, MII_BMSR) |
387 PHY_READ(&sc->sc_mii, MII_BMSR);
388 if (bmsr & BMSR_LINK)
389 mii->mii_media_status |= IFM_ACTIVE;
390
391 if (bmcr & BMCR_LOOP)
392 mii->mii_media_active |= IFM_LOOP;
393
394 /*
395 * Grr, braindead ThunderLAN PHY doesn't have any way to
396 * tell which media is actually active. (Note it also
397 * doesn't self-configure after autonegotiation.) We
398 * just have to report what's in the BMCR.
399 */
400 if (bmcr & BMCR_FDX)
401 mii->mii_media_active |= IFM_FDX;
402 mii->mii_media_active |= IFM_10_T;
403}
404
405int
406tlphy_auto(sc, waitfor)
407 struct tlphy_softc *sc;
408 int waitfor;
409{
410 int error;
411
412 switch ((error = mii_phy_auto(&sc->sc_mii, waitfor))) {
413 case EIO:
414 /*
415 * Just assume we're not in full-duplex mode.
416 * XXX Check link and try AUI/BNC?
417 */
418 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
419 break;
420
421 case EJUSTRETURN:
422 /* Flag that we need to program when it completes. */
423 sc->sc_need_acomp = 1;
424 break;
425
426 default:
427 tlphy_acomp(sc);
428 }
429
430 return (error);
431}
432
433void
434tlphy_acomp(sc)
435 struct tlphy_softc *sc;
436{
437 int aner, anlpar;
438
439 sc->sc_need_acomp = 0;
440
441 /*
442 * Grr, braindead ThunderLAN PHY doesn't self-configure
443 * after autonegotiation. We have to do it ourselves
444 * based on the link partner status.
445 */
446
447 aner = PHY_READ(&sc->sc_mii, MII_ANER);
448 if (aner & ANER_LPAN) {
449 anlpar = PHY_READ(&sc->sc_mii, MII_ANLPAR) &
450 PHY_READ(&sc->sc_mii, MII_ANAR);
451 if (anlpar & ANAR_10_FD) {
452 PHY_WRITE(&sc->sc_mii, MII_BMCR, BMCR_FDX);
453 return;
454 }
455 }
456 PHY_WRITE(&sc->sc_mii, MII_BMCR, 0);
457}