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 * SPDX-License-Identifier: BSD-2-Clause
6 *
7 * Copyright (c) 1998, 1999 The NetBSD Foundation, Inc.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to The NetBSD Foundation
11 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
12 * NASA Ames Research Center.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 * 1. Redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
24 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
25 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
26 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
27 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
30 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
31 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /*-
37 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
38 *
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
41 * are met:
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
49 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
50 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
51 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
52 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
53 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
54 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
55 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
56 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
57 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
58 */
59
60 #include <sys/cdefs.h>
61 /*
62 * driver for Level One's LXT-970 ethernet 10/100 PHY
63 * datasheet from www.level1.com
64 */
65
66 #include <sys/param.h>
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/socket.h>
70 #include <sys/errno.h>
71 #include <sys/module.h>
72 #include <sys/bus.h>
73
74 #include <net/if.h>
75 #include <net/if_media.h>
76
77 #include <dev/mii/mii.h>
78 #include <dev/mii/miivar.h>
79 #include "miidevs.h"
80
81 #include <dev/mii/lxtphyreg.h>
82
83 #include "miibus_if.h"
84
85 static int lxtphy_probe(device_t);
86 static int lxtphy_attach(device_t);
87
88 static device_method_t lxtphy_methods[] = {
89 /* device interface */
90 DEVMETHOD(device_probe, lxtphy_probe),
91 DEVMETHOD(device_attach, lxtphy_attach),
92 DEVMETHOD(device_detach, mii_phy_detach),
93 DEVMETHOD(device_shutdown, bus_generic_shutdown),
94 DEVMETHOD_END
95 };
96
97 static driver_t lxtphy_driver = {
98 "lxtphy",
99 lxtphy_methods,
100 sizeof(struct mii_softc)
101 };
102
103 DRIVER_MODULE(lxtphy, miibus, lxtphy_driver, 0, 0);
104
105 static int lxtphy_service(struct mii_softc *, struct mii_data *, int);
106 static void lxtphy_status(struct mii_softc *);
107 static void lxtphy_reset(struct mii_softc *);
108 static void lxtphy_set_tp(struct mii_softc *);
109 static void lxtphy_set_fx(struct mii_softc *);
110
111 static const struct mii_phydesc lxtphys[] = {
112 MII_PHY_DESC(xxLEVEL1, LXT970),
113 MII_PHY_END
114 };
115
116 static const struct mii_phy_funcs lxtphy_funcs = {
117 lxtphy_service,
118 lxtphy_status,
119 lxtphy_reset
120 };
121
122 static int
lxtphy_probe(device_t dev)123 lxtphy_probe(device_t dev)
124 {
125
126 return (mii_phy_dev_probe(dev, lxtphys, BUS_PROBE_DEFAULT));
127 }
128
129 static int
lxtphy_attach(device_t dev)130 lxtphy_attach(device_t dev)
131 {
132 struct mii_softc *sc;
133
134 sc = device_get_softc(dev);
135
136 mii_phy_dev_attach(dev, MIIF_NOMANPAUSE, &lxtphy_funcs, 0);
137
138 PHY_RESET(sc);
139
140 sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & sc->mii_capmask;
141 device_printf(dev, " ");
142
143 #define ADD(m) ifmedia_add(&sc->mii_pdata->mii_media, (m), 0, NULL)
144 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, 0, sc->mii_inst));
145 printf("100baseFX, ");
146 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_FX, IFM_FDX, sc->mii_inst));
147 printf("100baseFX-FDX, ");
148 #undef ADD
149
150 mii_phy_add_media(sc);
151 printf("\n");
152
153 MIIBUS_MEDIAINIT(sc->mii_dev);
154 return (0);
155 }
156
157 static int
lxtphy_service(struct mii_softc * sc,struct mii_data * mii,int cmd)158 lxtphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
159 {
160 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
161
162 switch (cmd) {
163 case MII_POLLSTAT:
164 break;
165
166 case MII_MEDIACHG:
167 if (IFM_SUBTYPE(ife->ifm_media) == IFM_100_FX)
168 lxtphy_set_fx(sc);
169 else
170 lxtphy_set_tp(sc);
171
172 mii_phy_setmedia(sc);
173 break;
174
175 case MII_TICK:
176 if (mii_phy_tick(sc) == EJUSTRETURN)
177 return (0);
178 break;
179 }
180
181 /* Update the media status. */
182 PHY_STATUS(sc);
183
184 /* Callback if something changed. */
185 mii_phy_update(sc, cmd);
186 return (0);
187 }
188
189 static void
lxtphy_status(struct mii_softc * sc)190 lxtphy_status(struct mii_softc *sc)
191 {
192 struct mii_data *mii = sc->mii_pdata;
193 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
194 int bmcr, bmsr, csr;
195
196 mii->mii_media_status = IFM_AVALID;
197 mii->mii_media_active = IFM_ETHER;
198
199 /*
200 * Get link status from the CSR; we need to read the CSR
201 * for media type anyhow, and the link status in the CSR
202 * doesn't latch, so fewer register reads are required.
203 */
204 csr = PHY_READ(sc, MII_LXTPHY_CSR);
205 if (csr & CSR_LINK)
206 mii->mii_media_status |= IFM_ACTIVE;
207
208 bmcr = PHY_READ(sc, MII_BMCR);
209 if (bmcr & BMCR_ISO) {
210 mii->mii_media_active |= IFM_NONE;
211 mii->mii_media_status = 0;
212 return;
213 }
214
215 if (bmcr & BMCR_LOOP)
216 mii->mii_media_active |= IFM_LOOP;
217
218 if (bmcr & BMCR_AUTOEN) {
219 bmsr = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
220 if ((bmsr & BMSR_ACOMP) == 0) {
221 /* Erg, still trying, I guess... */
222 mii->mii_media_active |= IFM_NONE;
223 return;
224 }
225 if (csr & CSR_SPEED)
226 mii->mii_media_active |= IFM_100_TX;
227 else
228 mii->mii_media_active |= IFM_10_T;
229 if (csr & CSR_DUPLEX)
230 mii->mii_media_active |=
231 IFM_FDX | mii_phy_flowstatus(sc);
232 else
233 mii->mii_media_active |= IFM_HDX;
234 } else
235 mii->mii_media_active = ife->ifm_media;
236 }
237
238 static void
lxtphy_reset(struct mii_softc * sc)239 lxtphy_reset(struct mii_softc *sc)
240 {
241
242 mii_phy_reset(sc);
243 PHY_WRITE(sc, MII_LXTPHY_IER,
244 PHY_READ(sc, MII_LXTPHY_IER) & ~IER_INTEN);
245 }
246
247 static void
lxtphy_set_tp(struct mii_softc * sc)248 lxtphy_set_tp(struct mii_softc *sc)
249 {
250 int cfg;
251
252 cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
253 cfg &= ~CONFIG_100BASEFX;
254 PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
255 }
256
257 static void
lxtphy_set_fx(struct mii_softc * sc)258 lxtphy_set_fx(struct mii_softc *sc)
259 {
260 int cfg;
261
262 cfg = PHY_READ(sc, MII_LXTPHY_CONFIG);
263 cfg |= CONFIG_100BASEFX;
264 PHY_WRITE(sc, MII_LXTPHY_CONFIG, cfg);
265 }
266