4cf762e6675d731de143a35d4b32a66e6ec57900
[dragonfly.git] / sys / dev / netif / mii_layer / lxtphy.c
1 /*      $OpenBSD: lxtphy.c,v 1.14 2005/02/19 06:00:04 brad 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  */
42  
43 /*
44  * Copyright (c) 1997 Manuel Bouyer.  All rights reserved.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *      This product includes software developed by Manuel Bouyer.
57  * 4. The name of the author may not be used to endorse or promote products
58  *    derived from this software without specific prior written permission.
59  *
60  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
61  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
62  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
63  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
64  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
65  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
66  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
67  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
68  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
69  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70  */
71
72 /*
73  * driver for Level One's LXT-970/LXT-971 ethernet 10/100 PHY
74  * datasheet from www.level1.com
75  */
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/kernel.h>
80 #include <sys/socket.h>
81 #include <sys/errno.h>
82 #include <sys/module.h>
83 #include <sys/bus.h>
84
85 #include <net/if.h>
86 #include <net/if_media.h>
87
88 #include "mii.h"
89 #include "miivar.h"
90 #include "miidevs.h"
91
92 #include "lxtphyreg.h"
93
94 #include "miibus_if.h"
95
96 static int      lxtphy_probe(device_t);
97 static int      lxtphy_attach(device_t);
98
99 static int      lxtphy_service(struct mii_softc *, struct mii_data *, int);
100 static void     lxtphy_status(struct mii_softc *);
101 static void     lxtphy_reset(struct mii_softc *);
102 static void     lxtphy_set_tp(struct mii_softc *);
103 static void     lxtphy_set_fx(struct mii_softc *);
104
105 static device_method_t lxtphy_methods[] = {
106         /* device interface */
107         DEVMETHOD(device_probe,         lxtphy_probe),
108         DEVMETHOD(device_attach,        lxtphy_attach),
109         DEVMETHOD(device_detach,        ukphy_detach),
110         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
111         { 0, 0 }
112 };
113
114 static const struct mii_phydesc lxtphys[] = {
115         MII_PHYDESC_ARG(xxLEVEL1,       LXT970, lxtphy_status),
116         MII_PHYDESC_ARG(xxLEVEL1a,      LXT971, ukphy_status),
117         MII_PHYDESC_NULL
118 };
119
120 static devclass_t lxtphy_devclass;
121
122 static driver_t lxtphy_driver = {
123         "lxtphy",
124         lxtphy_methods,
125         sizeof(struct mii_softc)
126 };
127
128 DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, lxtphy_devclass, NULL, NULL);
129
130 static int
131 lxtphy_probe(device_t dev)
132 {
133         struct mii_attach_args *ma = device_get_ivars(dev);
134         const struct mii_phydesc *mpd;
135
136         mpd = mii_phy_match(ma, lxtphys);
137         if (mpd != NULL) {
138                 struct mii_softc *sc = device_get_softc(dev);
139
140                 sc->mii_status = mpd->mpd_priv;
141                 device_set_desc(dev, mpd->mpd_name);
142                 return (0);
143         }
144         return (ENXIO);
145 }
146
147 static int
148 lxtphy_attach(device_t dev)
149 {
150         struct mii_softc *sc;
151         struct mii_attach_args *ma;
152         struct mii_data *mii;
153
154         sc = device_get_softc(dev);
155         ma = device_get_ivars(dev);
156         mii_softc_init(sc, ma);
157         sc->mii_dev = device_get_parent(dev);
158         mii = device_get_softc(sc->mii_dev);
159         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
160
161         sc->mii_inst = mii->mii_instance;
162         sc->mii_service = lxtphy_service;
163         sc->mii_reset = lxtphy_reset;
164         sc->mii_pdata = mii;
165         sc->mii_flags |= MIIF_NOISOLATE;
166
167         lxtphy_reset(sc);
168
169         mii->mii_instance++;
170
171 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
172         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
173             MII_MEDIA_NONE);
174 #undef ADD
175
176         sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask;
177
178         device_printf(dev, " ");
179         if (sc->mii_capabilities & BMSR_MEDIAMASK)
180                 mii_phy_add_media(sc);
181         else
182                 kprintf("no media present");
183         kprintf("\n");
184
185         MIIBUS_MEDIAINIT(sc->mii_dev);
186         return(0);
187 }
188
189 static int
190 lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
191 {
192         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
193         int reg;
194
195         switch (cmd) {
196         case MII_POLLSTAT:
197                 /*
198                  * If we're not polling our PHY instance, just return.
199                  */
200                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
201                         return (0);
202                 break;
203
204         case MII_MEDIACHG:
205                 /*
206                  * If the media indicates a different PHY instance,
207                  * isolate ourselves.
208                  */
209                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
210                         reg = PHY_READ(sc, MII_BMCR);
211                         PHY_WRITE(sc, MII_BMCR, reg | BMCR_ISO);
212                         return (0);
213                 }
214
215                 /*
216                  * If the interface is not up, don't do anything.
217                  */
218                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
219                         break;
220
221                 if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX)
222                         lxtphy_set_fx(sc);
223                 else
224                         lxtphy_set_tp(sc);
225
226                 mii_phy_set_media(sc);
227                 break;
228
229         case MII_TICK:
230                 /*
231                  * If we're not currently selected, just return.
232                  */
233                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
234                         return (0);
235
236                 if (mii_phy_tick(sc) == EJUSTRETURN)
237                         return (0);
238                 break;
239         }
240
241         /* Update the media status. */
242         sc->mii_status(sc);
243
244         /* Callback if something changed. */
245         mii_phy_update(sc, cmd);
246         return (0);
247 }
248
249 static void
250 lxtphy_status(struct mii_softc *sc)
251 {
252         struct mii_data *mii = sc->mii_pdata;
253         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
254         int bmcr, bmsr, csr;
255
256         mii->mii_media_status = IFM_AVALID;
257         mii->mii_media_active = IFM_ETHER;
258
259         /*
260          * Get link status from the CSR; we need to read the CSR
261          * for media type anyhow, and the link status in the CSR
262          * doens't latch, so fewer register reads are required.
263          */
264         csr = PHY_READ(sc, MII_LXTPHY_CSR);
265         if (csr & CSR_LINK)
266                 mii->mii_media_status |= IFM_ACTIVE;
267
268         bmcr = PHY_READ(sc, MII_BMCR);
269         if (bmcr & BMCR_ISO) {
270                 mii->mii_media_active |= IFM_NONE;
271                 mii->mii_media_status = 0;
272                 return;
273         }
274
275         if (bmcr & BMCR_LOOP)
276                 mii->mii_media_active |= IFM_LOOP;
277
278         if (bmcr & BMCR_AUTOEN) {
279                 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
280                 if ((bmsr & BMSR_ACOMP) == 0) {
281                         /* Erg, still trying, I guess... */
282                         mii->mii_media_active |= IFM_NONE;
283                         return;
284                 }
285                 if (csr & CSR_SPEED)
286                         mii->mii_media_active |= IFM_100_TX;
287                 else
288                         mii->mii_media_active |= IFM_10_T;
289                 if (csr & CSR_DUPLEX)
290                         mii->mii_media_active |= IFM_FDX;
291         } else
292                 mii->mii_media_active = ife->ifm_media;
293 }
294
295 static void
296 lxtphy_set_tp(struct mii_softc *sc)
297 {
298         int cfg;
299
300         cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
301         cfg &= ~CONFIG_100BASEFX;
302         PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
303 }
304
305 static void
306 lxtphy_set_fx(struct mii_softc *sc)
307 {
308         int cfg;
309
310         cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
311         cfg |= CONFIG_100BASEFX;
312         PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
313 }
314
315 static void
316 lxtphy_reset(struct mii_softc *sc)
317 {
318         mii_phy_reset(sc);
319 #if 0
320         PHY_WRITE(sc, MII_LXTPHY_IER,
321                   PHY_READ(sc, MII_LXTPHY_IER) & ~IER_INTEN);
322 #endif
323 }