makphy.c revision 1.57 1 /* $NetBSD: makphy.c,v 1.57 2019/02/27 18:21:04 jakllsch Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999, 2000, 2001 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 *
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 /*
34 * Copyright (c) 1997 Manuel Bouyer. All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 * notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55 */
56
57 /*
58 * Driver for the Marvell 88E1000 ``Alaska'' 10/100/1000 PHY.
59 */
60
61 #include <sys/cdefs.h>
62 __KERNEL_RCSID(0, "$NetBSD: makphy.c,v 1.57 2019/02/27 18:21:04 jakllsch Exp $");
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/kernel.h>
67 #include <sys/device.h>
68 #include <sys/socket.h>
69 #include <sys/errno.h>
70
71 #include <net/if.h>
72 #include <net/if_media.h>
73
74 #include <dev/mii/mii.h>
75 #include <dev/mii/miivar.h>
76 #include <dev/mii/miidevs.h>
77
78 #include <dev/mii/makphyreg.h>
79
80 static int makphymatch(device_t, cfdata_t, void *);
81 static void makphyattach(device_t, device_t, void *);
82
83 CFATTACH_DECL_NEW(makphy, sizeof(struct mii_softc),
84 makphymatch, makphyattach, mii_phy_detach, mii_phy_activate);
85
86 static int makphy_service(struct mii_softc *, struct mii_data *, int);
87 static void makphy_status(struct mii_softc *);
88 static void makphy_reset(struct mii_softc *);
89
90 static const struct mii_phy_funcs makphy_funcs = {
91 makphy_service, makphy_status, makphy_reset,
92 };
93
94 static const struct mii_phydesc makphys[] = {
95 MII_PHY_DESC(MARVELL, E1000_0),
96 MII_PHY_DESC(MARVELL, E1000_3),
97 MII_PHY_DESC(MARVELL, E1000_5),
98 MII_PHY_DESC(MARVELL, E1000_6),
99 MII_PHY_DESC(xxMARVELL, E1000_3),
100 MII_PHY_DESC(xxMARVELL, E1000_5),
101 MII_PHY_DESC(xxMARVELL, E1000S),
102 MII_PHY_DESC(xxMARVELL, E1011),
103 MII_PHY_DESC(xxMARVELL, E1101),
104 MII_PHY_DESC(xxMARVELL, E1111),
105 MII_PHY_DESC(xxMARVELL, E1112),
106 MII_PHY_DESC(xxMARVELL, E1116),
107 MII_PHY_DESC(xxMARVELL, E1116R),
108 MII_PHY_DESC(xxMARVELL, E1118),
109 MII_PHY_DESC(xxMARVELL, E1145),
110 MII_PHY_DESC(xxMARVELL, E1149),
111 MII_PHY_DESC(xxMARVELL, E1149R),
112 MII_PHY_DESC(xxMARVELL, E1240),
113 MII_PHY_DESC(xxMARVELL, E1318S),
114 MII_PHY_DESC(xxMARVELL, E1512),
115 MII_PHY_DESC(xxMARVELL, E1543),
116 MII_PHY_DESC(xxMARVELL, E3016),
117 MII_PHY_DESC(xxMARVELL, E3082),
118 MII_PHY_DESC(xxMARVELL, PHYG65G),
119 MII_PHY_END,
120 };
121
122 #define MAKARG_PDOWN true /* Power DOWN */
123 #define MAKARG_PUP false /* Power UP */
124
125 static bool
126 makphy_isi210(device_t parent, struct mii_attach_args *ma)
127 {
128
129 /* I21[01]'s model number is 0 */
130 if ((MII_OUI(ma->mii_id1, ma->mii_id2) == MII_OUI_xxMARVELL)
131 && (MII_MODEL(ma->mii_id2) == MII_MODEL_xxMARVELL_I210)
132 && (device_is_a(parent, "wm")))
133 return true;
134 return false;
135 }
136
137 static int
138 makphymatch(device_t parent, cfdata_t match, void *aux)
139 {
140 struct mii_attach_args *ma = aux;
141
142 if (mii_phy_match(ma, makphys) != NULL)
143 return 10;
144
145 if (makphy_isi210(parent, ma))
146 return 10;
147
148 return 0;
149 }
150
151 static void
152 makphyattach(device_t parent, device_t self, void *aux)
153 {
154 struct mii_softc *sc = device_private(self);
155 struct mii_attach_args *ma = aux;
156 struct mii_data *mii = ma->mii_data;
157 const struct mii_phydesc *mpd;
158 const char *name;
159 uint16_t reg;
160
161 mpd = mii_phy_match(ma, makphys);
162 aprint_naive(": Media interface\n");
163 if (mpd)
164 name = mpd->mpd_name;
165 else if (makphy_isi210(parent, ma))
166 name = MII_STR_xxMARVELL_I210;
167 else
168 panic("Unknown PHY");
169 aprint_normal(": %s, rev. %d\n", name, MII_REV(ma->mii_id2));
170
171 sc->mii_dev = self;
172 sc->mii_mpd_oui = MII_OUI(ma->mii_id1, ma->mii_id2);
173 sc->mii_mpd_model = MII_MODEL(ma->mii_id2);
174 sc->mii_mpd_rev = MII_REV(ma->mii_id2);
175 sc->mii_inst = mii->mii_instance;
176 sc->mii_phy = ma->mii_phyno;
177 sc->mii_funcs = &makphy_funcs;
178 sc->mii_pdata = mii;
179 sc->mii_flags = ma->mii_flags;
180 sc->mii_anegticks = MII_ANEGTICKS;
181
182 /* Make sure page 0 is selected. */
183 PHY_WRITE(sc, MAKPHY_EADR, 0);
184
185 switch (sc->mii_mpd_model) {
186 case MII_MODEL_xxMARVELL_E1011:
187 case MII_MODEL_xxMARVELL_E1112:
188 PHY_READ(sc, MAKPHY_ESSR, ®);
189 if (reg & ESSR_FIBER_LINK)
190 sc->mii_flags |= MIIF_HAVEFIBER;
191 break;
192 default:
193 break;
194 }
195
196 PHY_RESET(sc);
197
198 PHY_READ(sc, MII_BMSR, &sc->mii_capabilities);
199 sc->mii_capabilities &= ma->mii_capmask;
200 if (sc->mii_capabilities & BMSR_EXTSTAT)
201 PHY_READ(sc, MII_EXTSR, &sc->mii_extcapabilities);
202
203 aprint_normal_dev(self, "");
204 if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
205 (sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0)
206 aprint_error("no media present");
207 else
208 mii_phy_add_media(sc);
209 aprint_normal("\n");
210 }
211
212 static void
213 makphy_reset(struct mii_softc *sc)
214 {
215 uint16_t reg;
216
217 mii_phy_reset(sc);
218
219 /*
220 * Initialize PHY Specific Control Register.
221 */
222 PHY_READ(sc, MAKPHY_PSCR, ®);
223
224 /* Assert CRS on transmit. */
225 switch (sc->mii_mpd_model) {
226 case MII_MODEL_MARVELL_E1000_0:
227 case MII_MODEL_MARVELL_E1000_3:
228 case MII_MODEL_MARVELL_E1000_5:
229 case MII_MODEL_MARVELL_E1000_6:
230 case MII_MODEL_xxMARVELL_E1000S:
231 case MII_MODEL_xxMARVELL_E1011:
232 case MII_MODEL_xxMARVELL_E1111:
233 reg |= PSCR_CRS_ON_TX;
234 break;
235 default: /* No PSCR_CRS_ON_TX bit */
236 break;
237 }
238
239 /* Enable scrambler if necessary. */
240 if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016)
241 reg &= ~E3016_PSCR_SCRAMBLE_DIS;
242
243 /*
244 * Store next page in the Link Partner Next Page register for
245 * compatibility with 802.3ab.
246 */
247 if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016)
248 reg |= E3016_PSCR_REG8NXTPG;
249
250 PHY_WRITE(sc, MAKPHY_PSCR, reg);
251
252 /* Configure LEDs if they were left unconfigured. */
253 if (sc->mii_mpd_model == MII_MODEL_xxMARVELL_E3016) {
254 PHY_READ(sc, 0x16, ®);
255 if (reg == 0) {
256 reg = (0x0b << 8) | (0x05 << 4) | 0x04; /* XXX */
257 PHY_WRITE(sc, 0x16, reg);
258 }
259 }
260
261 mii_phy_reset(sc);
262 }
263
264 static void
265 makphy_pdown(struct mii_softc *sc, bool pdown)
266 {
267 uint16_t bmcr, new;
268 bool need_reset = false;
269
270 /*
271 * XXX
272 * PSCR (register 16) should be modified on some chips.
273 */
274
275 PHY_READ(sc, MII_BMCR, &bmcr);
276 if (pdown)
277 new = bmcr | BMCR_PDOWN;
278 else
279 new = bmcr & ~BMCR_PDOWN;
280 if (bmcr != new)
281 need_reset = true;
282
283 if (need_reset)
284 new |= BMCR_RESET;
285 PHY_WRITE(sc, MII_BMCR, new);
286 }
287
288 static int
289 makphy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
290 {
291 struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
292 uint16_t bmcr;
293
294 if (!device_is_active(sc->mii_dev))
295 return ENXIO;
296
297 switch (cmd) {
298 case MII_POLLSTAT:
299 /*
300 * If we're not polling our PHY instance, just return.
301 */
302 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
303 return 0;
304 break;
305
306 case MII_MEDIACHG:
307 /*
308 * If the media indicates a different PHY instance,
309 * isolate ourselves.
310 */
311 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
312 PHY_READ(sc, MII_BMCR, &bmcr);
313 PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_ISO);
314 return 0;
315 }
316
317 /*
318 * If the interface is not up, don't do anything.
319 */
320 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
321 break;
322
323 /* Try to power up the PHY in case it's down */
324 if (IFM_SUBTYPE(ife->ifm_media) != IFM_NONE)
325 makphy_pdown(sc, MAKARG_PUP);
326
327 mii_phy_setmedia(sc);
328
329 /*
330 * If autonegitation is not enabled, we need a
331 * software reset for the settings to take effect.
332 */
333 if (IFM_SUBTYPE(ife->ifm_media) == IFM_NONE)
334 makphy_pdown(sc, MAKARG_PDOWN);
335 else if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
336 PHY_READ(sc, MII_BMCR, &bmcr);
337 PHY_WRITE(sc, MII_BMCR, bmcr | BMCR_RESET);
338 }
339 break;
340
341 case MII_TICK:
342 /*
343 * If we're not currently selected, just return.
344 */
345 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
346 return 0;
347
348 if (mii_phy_tick(sc) == EJUSTRETURN)
349 return 0;
350 break;
351
352 case MII_DOWN:
353 mii_phy_down(sc);
354 return 0;
355 }
356
357 /* Update the media status. */
358 mii_phy_status(sc);
359
360 /* Callback if something changed. */
361 mii_phy_update(sc, cmd);
362 return 0;
363 }
364
365 static void
366 makphy_status(struct mii_softc *sc)
367 {
368 struct mii_data *mii = sc->mii_pdata;
369 uint16_t bmcr, gsr, pssr;
370
371 mii->mii_media_status = IFM_AVALID;
372 mii->mii_media_active = IFM_ETHER;
373
374 PHY_READ(sc, MII_BMCR, &bmcr);
375 /* XXX FIXME: Use different page for Fiber on newer chips */
376 PHY_READ(sc, MAKPHY_PSSR, &pssr);
377
378 if (pssr & PSSR_LINK)
379 mii->mii_media_status |= IFM_ACTIVE;
380
381 if (bmcr & BMCR_LOOP)
382 mii->mii_media_active |= IFM_LOOP;
383
384 if (bmcr & BMCR_ISO) {
385 mii->mii_media_active |= IFM_NONE;
386 mii->mii_media_status = 0;
387 return;
388 }
389
390 if ((bmcr & BMCR_AUTOEN) != 0) {
391 /*
392 * Check Speed and Duplex Resolved bit.
393 * Note that this bit is always 1 when autonego is not enabled.
394 */
395 if (!(pssr & PSSR_RESOLVED)) {
396 /* Erg, still trying, I guess... */
397 mii->mii_media_active |= IFM_NONE;
398 return;
399 }
400 } else {
401 if ((pssr & PSSR_LINK) == 0) {
402 mii->mii_media_active |= IFM_NONE;
403 return;
404 }
405 }
406
407 /* XXX FIXME: Use different page for Fiber on newer chips */
408 if (sc->mii_flags & MIIF_IS_1000X) {
409 mii->mii_media_active |= IFM_1000_SX;
410 } else {
411 switch (PSSR_SPEED_get(pssr)) {
412 case SPEED_1000:
413 mii->mii_media_active |= IFM_1000_T;
414 break;
415 case SPEED_100:
416 mii->mii_media_active |= IFM_100_TX;
417 break;
418 case SPEED_10:
419 mii->mii_media_active |= IFM_10_T;
420 break;
421 default: /* Undefined (reserved) value */
422 mii->mii_media_active |= IFM_NONE;
423 mii->mii_media_status = 0;
424 return;
425 }
426 }
427
428 if (pssr & PSSR_DUPLEX)
429 mii->mii_media_active |= mii_phy_flowstatus(sc) | IFM_FDX;
430 else
431 mii->mii_media_active |= IFM_HDX;
432
433 if (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) {
434 PHY_READ(sc, MII_100T2SR, &gsr);
435 if (gsr & GTSR_MS_RES)
436 mii->mii_media_active |= IFM_ETH_MASTER;
437 }
438 }
439