* Ansify function definitions.
[dragonfly.git] / sys / dev / netif / mii_layer / lxtphy.c
1 /*      OpenBSD: lxtphy.c,v 1.5 2000/08/26 20:04:17 nate Exp    */
2 /*      NetBSD: lxtphy.c,v 1.19 2000/02/02 23:34:57 thorpej Exp         */
3
4 /*-
5  * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10  * NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *      This product includes software developed by the NetBSD
23  *      Foundation, Inc. and its contributors.
24  * 4. Neither the name of The NetBSD Foundation nor the names of its
25  *    contributors may be used to endorse or promote products derived
26  *    from this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38  * POSSIBILITY OF SUCH DAMAGE.
39  *
40  * $FreeBSD: src/sys/dev/mii/lxtphy.c,v 1.1.2.1 2001/06/08 19:58:33 semenu Exp $
41  * $DragonFly: src/sys/dev/netif/mii_layer/lxtphy.c,v 1.8 2005/12/11 01:54:08 swildner Exp $
42  */
43  
44 /*
45  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
46  *
47  * Redistribution and use in source and binary forms, with or without
48  * modification, are permitted provided that the following conditions
49  * are met:
50  * 1. Redistributions of source code must retain the above copyright
51  *    notice, this list of conditions and the following disclaimer.
52  * 2. Redistributions in binary form must reproduce the above copyright
53  *    notice, this list of conditions and the following disclaimer in the
54  *    documentation and/or other materials provided with the distribution.
55  * 3. All advertising materials mentioning features or use of this software
56  *    must display the following acknowledgement:
57  *      This product includes software developed by Manuel Bouyer.
58  * 4. The name of the author may not be used to endorse or promote products
59  *    derived from this software without specific prior written permission.
60  *
61  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
62  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
63  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
64  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
65  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
66  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
67  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
68  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
69  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
70  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
71  */
72
73 /*
74  * driver for Level One's LXT-970 ethernet 10/100 PHY
75  * datasheet from www.level1.com
76  */
77
78 #include <sys/param.h>
79 #include <sys/systm.h>
80 #include <sys/kernel.h>
81 #include <sys/socket.h>
82 #include <sys/errno.h>
83 #include <sys/module.h>
84 #include <sys/bus.h>
85
86 #include <net/if.h>
87 #include <net/if_media.h>
88
89 #include "mii.h"
90 #include "miivar.h"
91 #include "miidevs.h"
92
93 #include "lxtphyreg.h"
94
95 #include "miibus_if.h"
96
97 static int lxtphy_probe         (device_t);
98 static int lxtphy_attach        (device_t);
99 static int lxtphy_detach        (device_t);
100
101 static device_method_t lxtphy_methods[] = {
102         /* device interface */
103         DEVMETHOD(device_probe,         lxtphy_probe),
104         DEVMETHOD(device_attach,        lxtphy_attach),
105         DEVMETHOD(device_detach,        lxtphy_detach),
106         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
107         { 0, 0 }
108 };
109
110 static devclass_t lxtphy_devclass;
111
112 static driver_t lxtphy_driver = {
113         "lxtphy",
114         lxtphy_methods,
115         sizeof(struct mii_softc)
116 };
117
118 DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, 0, 0);
119
120 static int      lxtphy_service (struct mii_softc *, struct mii_data *, int);
121 static void     lxtphy_status (struct mii_softc *);
122 static void     lxtphy_set_tp (struct mii_softc *);
123 static void     lxtphy_set_fx (struct mii_softc *);
124
125 static int
126 lxtphy_probe(device_t dev)
127 {
128         struct mii_attach_args *ma;
129
130         ma = device_get_ivars(dev);
131
132         if (MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxLEVEL1 &&
133             MII_MODEL(ma->mii_id2) == MII_MODEL_xxLEVEL1_LXT970) {
134                 device_set_desc(dev, MII_STR_xxLEVEL1_LXT970);
135         } else
136                 return (ENXIO);
137
138         return (0);
139 }
140
141 static int
142 lxtphy_attach(device_t dev)
143 {
144         struct mii_softc *sc;
145         struct mii_attach_args *ma;
146         struct mii_data *mii;
147
148         sc = device_get_softc(dev);
149         ma = device_get_ivars(dev);
150         mii_softc_init(sc, ma);
151         sc->mii_dev = device_get_parent(dev);
152         mii = device_get_softc(sc->mii_dev);
153         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
154
155         sc->mii_inst = mii->mii_instance;
156         sc->mii_service = lxtphy_service;
157         sc->mii_pdata = mii;
158         sc->mii_flags |= MIIF_NOISOLATE;
159
160         mii_phy_reset(sc);
161
162         mii->mii_instance++;
163
164         sc->mii_capabilities =
165             PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
166         device_printf(dev, " ");
167
168 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
169         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
170             BMCR_ISO);
171         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst),
172             BMCR_S100);
173         printf("100baseFX, ");
174         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst),
175             BMCR_S100|BMCR_FDX);
176         printf("100baseFX-FDX, ");
177 #undef ADD
178
179         if (sc->mii_capabilities & BMSR_MEDIAMASK)
180                 mii_add_media(sc, sc->mii_capabilities);
181         printf("\n");
182
183         MIIBUS_MEDIAINIT(sc->mii_dev);
184         return(0);
185 }
186
187
188 static int
189 lxtphy_detach(device_t dev)
190 {
191         struct mii_softc *sc;
192         struct mii_data *mii;
193
194         sc = device_get_softc(dev);
195         mii = device_get_softc(device_get_parent(dev));
196         sc->mii_dev = NULL;
197         LIST_REMOVE(sc, mii_list);
198
199         return(0);
200 }
201
202 static int
203 lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
204 {
205         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
206         int reg;
207
208         switch (cmd) {
209         case MII_POLLSTAT:
210                 /*
211                  * If we're not polling our PHY instance, just return.
212                  */
213                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
214                         return (0);
215                 break;
216
217         case MII_MEDIACHG:
218                 /*
219                  * If the media indicates a different PHY instance,
220                  * isolate ourselves.
221                  */
222                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
223                         reg = PHY_READ(sc, MII_BMCR);
224                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
225                         return (0);
226                 }
227
228                 /*
229                  * If the interface is not up, don't do anything.
230                  */
231                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
232                         break;
233
234                 switch (IFM_SUBTYPE(ife->ifm_media)) {
235                 case IFM_AUTO:
236                         /*
237                          * If we're already in auto mode, just return.
238                          */
239                         if (PHY_READ(sc, MII_BMCR) & BMCR_AUTOEN)
240                                 return (0);
241
242                         lxtphy_set_tp(sc);
243
244                         (void) mii_phy_auto(sc, 1);
245                         break;
246                 case IFM_100_T4:
247                         /*
248                          * XXX Not supported as a manual setting right now.
249                          */
250                         return (EINVAL);
251
252                 case IFM_100_FX:
253                         lxtphy_set_fx(sc);
254
255                 default:
256                         /*
257                          * BMCR data is stored in the ifmedia entry.
258                          */
259                         PHY_WRITE(sc, MII_ANAR,
260                             mii_anar(ife->ifm_media));
261                         PHY_WRITE(sc, MII_BMCR, ife->ifm_data);
262                 }
263                 break;
264
265         case MII_TICK:
266                 /*
267                  * If we're not currently selected, just return.
268                  */
269                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
270                         return (0);
271
272                 /*
273                  * Only used for autonegotiation.
274                  */
275                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO)
276                         return (0);
277
278                 /*
279                  * Is the interface even up?
280                  */
281                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
282                         return (0);
283
284                 /*
285                  * Check to see if we have link.  If we do, we don't
286                  * need to restart the autonegotiation process.  Read
287                  * the BMSR twice in case it's latched.
288                  */
289                 reg = PHY_READ(sc, MII_BMSR) |
290                     PHY_READ(sc, MII_BMSR);
291                 if (reg & BMSR_LINK)
292                         return (0);
293
294                 /*
295                  * Only retry autonegotiation every 5 seconds.
296                  */
297                 if (++sc->mii_ticks != 5)
298                         return (0);
299
300                 sc->mii_ticks = 0;
301                 mii_phy_reset(sc);
302                 if (mii_phy_auto(sc, 0) == EJUSTRETURN)
303                         return (0);
304                 break;
305         }
306
307         /* Update the media status. */
308         lxtphy_status(sc);
309
310         /* Callback if something changed. */
311         if (sc->mii_active != mii->mii_media_active || cmd == MII_MEDIACHG) {
312                 MIIBUS_STATCHG(sc->mii_dev);
313                 sc->mii_active = mii->mii_media_active;
314         }
315         return (0);
316 }
317
318 static void
319 lxtphy_status(struct mii_softc *sc)
320 {
321         struct mii_data *mii = sc->mii_pdata;
322         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
323         int bmcr, bmsr, csr;
324
325         mii->mii_media_status = IFM_AVALID;
326         mii->mii_media_active = IFM_ETHER;
327
328         /*
329          * Get link status from the CSR; we need to read the CSR
330          * for media type anyhow, and the link status in the CSR
331          * doens't latch, so fewer register reads are required.
332          */
333         csr = PHY_READ(sc, MII_LXTPHY_CSR);
334         if (csr & CSR_LINK)
335                 mii->mii_media_status |= IFM_ACTIVE;
336
337         bmcr = PHY_READ(sc, MII_BMCR);
338         if (bmcr & BMCR_ISO) {
339                 mii->mii_media_active |= IFM_NONE;
340                 mii->mii_media_status = 0;
341                 return;
342         }
343
344         if (bmcr & BMCR_LOOP)
345                 mii->mii_media_active |= IFM_LOOP;
346
347         if (bmcr & BMCR_AUTOEN) {
348                 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
349                 if ((bmsr & BMSR_ACOMP) == 0) {
350                         /* Erg, still trying, I guess... */
351                         mii->mii_media_active |= IFM_NONE;
352                         return;
353                 }
354                 if (csr & CSR_SPEED)
355                         mii->mii_media_active |= IFM_100_TX;
356                 else
357                         mii->mii_media_active |= IFM_10_T;
358                 if (csr & CSR_DUPLEX)
359                         mii->mii_media_active |= IFM_FDX;
360         } else
361                 mii->mii_media_active = ife->ifm_media;
362 }
363
364 static void
365 lxtphy_set_tp(struct mii_softc *sc)
366 {
367         int cfg;
368
369         cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
370         cfg &= ~CONFIG_100BASEFX;
371         PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
372 }
373
374 static void
375 lxtphy_set_fx(struct mii_softc *sc)
376 {
377         int cfg;
378
379         cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
380         cfg |= CONFIG_100BASEFX;
381         PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
382 }