]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/dev/mii/e1000phy.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / dev / mii / e1000phy.c
1 /*-
2  * Principal Author: Parag Patel
3  * Copyright (c) 2001
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice unmodified, this list of conditions, and the following
11  *    disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  * Additonal Copyright (c) 2001 by Traakan Software under same licence.
29  * Secondary Author: Matthew Jacob
30  */
31
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
34
35 /*
36  * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
37  */
38
39 /*
40  * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and
41  * 1000baseSX PHY.
42  * Nathan Binkert <nate@openbsd.org>
43  * Jung-uk Kim <jkim@niksun.com>
44  */
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/module.h>
50 #include <sys/socket.h>
51 #include <sys/bus.h>
52
53
54 #include <net/if.h>
55 #include <net/if_media.h>
56
57 #include <dev/mii/mii.h>
58 #include <dev/mii/miivar.h>
59 #include "miidevs.h"
60
61 #include <dev/mii/e1000phyreg.h>
62
63 #include "miibus_if.h"
64
65 static int      e1000phy_probe(device_t);
66 static int      e1000phy_attach(device_t);
67
68 struct e1000phy_softc {
69         struct mii_softc mii_sc;
70         int mii_model;
71 };
72
73 static device_method_t e1000phy_methods[] = {
74         /* device interface */
75         DEVMETHOD(device_probe,         e1000phy_probe),
76         DEVMETHOD(device_attach,        e1000phy_attach),
77         DEVMETHOD(device_detach,        mii_phy_detach),
78         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
79         { 0, 0 }
80 };
81
82 static devclass_t e1000phy_devclass;
83 static driver_t e1000phy_driver = {
84         "e1000phy",
85         e1000phy_methods,
86         sizeof(struct e1000phy_softc)
87 };
88
89 DRIVER_MODULE(e1000phy, miibus, e1000phy_driver, e1000phy_devclass, 0, 0);
90
91 static int      e1000phy_service(struct mii_softc *, struct mii_data *, int);
92 static void     e1000phy_status(struct mii_softc *);
93 static void     e1000phy_reset(struct mii_softc *);
94 static int      e1000phy_mii_phy_auto(struct e1000phy_softc *);
95
96 static const struct mii_phydesc e1000phys[] = {
97         MII_PHY_DESC(MARVELL, E1000),
98         MII_PHY_DESC(MARVELL, E1011),
99         MII_PHY_DESC(MARVELL, E1000_3),
100         MII_PHY_DESC(MARVELL, E1000S),
101         MII_PHY_DESC(MARVELL, E1000_5),
102         MII_PHY_DESC(MARVELL, E1000_6),
103         MII_PHY_DESC(MARVELL, E3082),
104         MII_PHY_DESC(MARVELL, E1112),
105         MII_PHY_DESC(MARVELL, E1149),
106         MII_PHY_DESC(MARVELL, E1111),
107         MII_PHY_DESC(MARVELL, E1116),
108         MII_PHY_DESC(MARVELL, E1118),
109         MII_PHY_DESC(xxMARVELL, E1000),
110         MII_PHY_DESC(xxMARVELL, E1011),
111         MII_PHY_DESC(xxMARVELL, E1000_3),
112         MII_PHY_DESC(xxMARVELL, E1000_5),
113         MII_PHY_DESC(xxMARVELL, E1111),
114         MII_PHY_END
115 };
116
117 static int
118 e1000phy_probe(device_t dev)
119 {
120
121         return (mii_phy_dev_probe(dev, e1000phys, BUS_PROBE_DEFAULT));
122 }
123
124 static int
125 e1000phy_attach(device_t dev)
126 {
127         struct e1000phy_softc *esc;
128         struct mii_softc *sc;
129         struct mii_attach_args *ma;
130         struct mii_data *mii;
131         int fast_ether;
132
133         esc = device_get_softc(dev);
134         sc = &esc->mii_sc;
135         ma = device_get_ivars(dev);
136         sc->mii_dev = device_get_parent(dev);
137         mii = device_get_softc(sc->mii_dev);
138         LIST_INSERT_HEAD(&mii->mii_phys, sc, mii_list);
139
140         sc->mii_inst = mii->mii_instance;
141         sc->mii_phy = ma->mii_phyno;
142         sc->mii_service = e1000phy_service;
143         sc->mii_pdata = mii;
144         sc->mii_anegticks = MII_ANEGTICKS_GIGE;
145         mii->mii_instance++;
146
147         fast_ether = 0;
148         esc->mii_model = MII_MODEL(ma->mii_id2);
149         switch (esc->mii_model) {
150         case MII_MODEL_MARVELL_E1011:
151         case MII_MODEL_MARVELL_E1112:
152                 if (PHY_READ(sc, E1000_ESSR) & E1000_ESSR_FIBER_LINK)
153                         sc->mii_flags |= MIIF_HAVEFIBER;
154                 break;
155         case MII_MODEL_MARVELL_E1149:
156                 /*
157                  * Some 88E1149 PHY's page select is initialized to
158                  * point to other bank instead of copper/fiber bank
159                  * which in turn resulted in wrong registers were
160                  * accessed during PHY operation. It is believed that
161                  * page 0 should be used for copper PHY so reinitialize
162                  * E1000_EADR to select default copper PHY. If parent
163                  * device know the type of PHY(either copper or fiber),
164                  * that information should be used to select default
165                  * type of PHY.
166                  */
167                 PHY_WRITE(sc, E1000_EADR, 0);
168                 break;
169         case MII_MODEL_MARVELL_E3082:
170                 /* 88E3082 10/100 Fast Ethernet PHY. */
171                 sc->mii_anegticks = MII_ANEGTICKS;
172                 fast_ether = 1;
173                 break;
174         }
175
176         e1000phy_reset(sc);
177
178         device_printf(dev, " ");
179
180 #define ADD(m, c)       ifmedia_add(&mii->mii_media, (m), (c), NULL)
181         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
182             E1000_CR_ISOLATE);
183         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
184                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
185                     E1000_CR_SPEED_10);
186                 printf("10baseT, ");
187                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
188                     E1000_CR_SPEED_10 | E1000_CR_FULL_DUPLEX);
189                 printf("10baseT-FDX, ");
190                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
191                     E1000_CR_SPEED_100);
192                 printf("100baseTX, ");
193                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
194                     E1000_CR_SPEED_100 | E1000_CR_FULL_DUPLEX);
195                 printf("100baseTX-FDX, ");
196                 if (fast_ether == 0) {
197                         /*
198                          * 1000BT-simplex not supported; driver must ignore
199                          * this entry, but it must be present in order to
200                          * manually set full-duplex.
201                          */
202                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
203                             sc->mii_inst), E1000_CR_SPEED_1000);
204                         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
205                             sc->mii_inst),
206                             E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX);
207                         printf("1000baseTX-FDX, ");
208                 }
209         } else {
210                 ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX, sc->mii_inst),
211                     E1000_CR_SPEED_1000 | E1000_CR_FULL_DUPLEX);
212                 printf("1000baseSX-FDX, ");
213         }
214         ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst), 0);
215         printf("auto\n");
216 #undef ADD
217
218         MIIBUS_MEDIAINIT(sc->mii_dev);
219         return (0);
220 }
221
222 static void
223 e1000phy_reset(struct mii_softc *sc)
224 {
225         struct e1000phy_softc *esc;
226         uint16_t reg, page;
227
228         esc = (struct e1000phy_softc *)sc;
229         reg = PHY_READ(sc, E1000_SCR);
230         if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) {
231                 reg &= ~E1000_SCR_AUTO_X_MODE;
232                 PHY_WRITE(sc, E1000_SCR, reg);
233                 if (esc->mii_model == MII_MODEL_MARVELL_E1112) {
234                         /* Select 1000BASE-X only mode. */
235                         page = PHY_READ(sc, E1000_EADR);
236                         PHY_WRITE(sc, E1000_EADR, 2);
237                         reg = PHY_READ(sc, E1000_SCR);
238                         reg &= ~E1000_SCR_MODE_MASK;
239                         reg |= E1000_SCR_MODE_1000BX;
240                         PHY_WRITE(sc, E1000_SCR, reg);
241                         PHY_WRITE(sc, E1000_EADR, page);
242                 }
243         } else {
244                 switch (esc->mii_model) {
245                 case MII_MODEL_MARVELL_E1111:
246                 case MII_MODEL_MARVELL_E1112:
247                 case MII_MODEL_MARVELL_E1116:
248                 case MII_MODEL_MARVELL_E1118:
249                 case MII_MODEL_MARVELL_E1149:
250                         /* Disable energy detect mode. */
251                         reg &= ~E1000_SCR_EN_DETECT_MASK;
252                         reg |= E1000_SCR_AUTO_X_MODE;
253                         if (esc->mii_model == MII_MODEL_MARVELL_E1116)
254                                 reg &= ~E1000_SCR_POWER_DOWN;
255                         break;
256                 case MII_MODEL_MARVELL_E3082:
257                         reg |= (E1000_SCR_AUTO_X_MODE >> 1);
258                         break;
259                 default:
260                         reg &= ~E1000_SCR_AUTO_X_MODE;
261                         break;
262                 }
263                 /* Enable CRS on TX. */
264                 reg |= E1000_SCR_ASSERT_CRS_ON_TX;
265                 /* Auto correction for reversed cable polarity. */
266                 reg &= ~E1000_SCR_POLARITY_REVERSAL;
267                 PHY_WRITE(sc, E1000_SCR, reg);
268
269                 if (esc->mii_model == MII_MODEL_MARVELL_E1116) {
270                         PHY_WRITE(sc, E1000_EADR, 2);
271                         reg = PHY_READ(sc, E1000_SCR);
272                         reg |= E1000_SCR_RGMII_POWER_UP;
273                         PHY_WRITE(sc, E1000_SCR, reg);
274                         PHY_WRITE(sc, E1000_EADR, 0);
275                 }
276         }
277
278         switch (MII_MODEL(esc->mii_model)) {
279         case MII_MODEL_MARVELL_E3082:
280         case MII_MODEL_MARVELL_E1112:
281         case MII_MODEL_MARVELL_E1116:
282         case MII_MODEL_MARVELL_E1118:
283         case MII_MODEL_MARVELL_E1149:
284                 break;
285         default:
286                 /* Force TX_CLK to 25MHz clock. */
287                 reg = PHY_READ(sc, E1000_ESCR);
288                 reg |= E1000_ESCR_TX_CLK_25;
289                 PHY_WRITE(sc, E1000_ESCR, reg);
290                 break;
291         }
292
293         /* Reset the PHY so all changes take effect. */
294         reg = PHY_READ(sc, E1000_CR);
295         reg |= E1000_CR_RESET;
296         PHY_WRITE(sc, E1000_CR, reg);
297 }
298
299 static int
300 e1000phy_service(struct mii_softc *sc, struct mii_data *mii, int cmd)
301 {
302         struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
303         struct e1000phy_softc *esc = (struct e1000phy_softc *)sc;
304         uint16_t speed, gig;
305         int reg;
306
307         switch (cmd) {
308         case MII_POLLSTAT:
309                 /*
310                  * If we're not polling our PHY instance, just return.
311                  */
312                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
313                         return (0);
314                 break;
315
316         case MII_MEDIACHG:
317                 /*
318                  * If the media indicates a different PHY instance,
319                  * isolate ourselves.
320                  */
321                 if (IFM_INST(ife->ifm_media) != sc->mii_inst) {
322                         reg = PHY_READ(sc, E1000_CR);
323                         PHY_WRITE(sc, E1000_CR, reg | E1000_CR_ISOLATE);
324                         return (0);
325                 }
326
327                 /*
328                  * If the interface is not up, don't do anything.
329                  */
330                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
331                         break;
332
333                 if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
334                         e1000phy_mii_phy_auto(esc);
335                         break;
336                 }
337
338                 speed = 0;
339                 switch (IFM_SUBTYPE(ife->ifm_media)) {
340                 case IFM_1000_T:
341                         if (esc->mii_model == MII_MODEL_MARVELL_E3082)
342                                 return (EINVAL);
343                         speed = E1000_CR_SPEED_1000;
344                         break;
345                 case IFM_1000_SX:
346                         if (esc->mii_model == MII_MODEL_MARVELL_E3082)
347                                 return (EINVAL);
348                         speed = E1000_CR_SPEED_1000;
349                         break;
350                 case IFM_100_TX:
351                         speed = E1000_CR_SPEED_100;
352                         break;
353                 case IFM_10_T:
354                         speed = E1000_CR_SPEED_10;
355                         break;
356                 case IFM_NONE:
357                         reg = PHY_READ(sc, E1000_CR);
358                         PHY_WRITE(sc, E1000_CR,
359                             reg | E1000_CR_ISOLATE | E1000_CR_POWER_DOWN);
360                         goto done;
361                 default:
362                         return (EINVAL);
363                 }
364
365                 if (((ife->ifm_media & IFM_GMASK) & IFM_FDX) != 0) {
366                         speed |= E1000_CR_FULL_DUPLEX;
367                         gig = E1000_1GCR_1000T_FD;
368                 } else
369                         gig = E1000_1GCR_1000T;
370
371                 reg = PHY_READ(sc, E1000_CR);
372                 reg &= ~E1000_CR_AUTO_NEG_ENABLE;
373                 PHY_WRITE(sc, E1000_CR, reg | E1000_CR_RESET);
374
375                 /*
376                  * When setting the link manually, one side must
377                  * be the master and the other the slave. However
378                  * ifmedia doesn't give us a good way to specify
379                  * this, so we fake it by using one of the LINK
380                  * flags. If LINK0 is set, we program the PHY to
381                  * be a master, otherwise it's a slave.
382                  */
383                 if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T ||
384                     (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_SX)) {
385                         if ((mii->mii_ifp->if_flags & IFF_LINK0))
386                                 PHY_WRITE(sc, E1000_1GCR, gig |
387                                     E1000_1GCR_MS_ENABLE | E1000_1GCR_MS_VALUE);
388                         else
389                                 PHY_WRITE(sc, E1000_1GCR, gig |
390                                     E1000_1GCR_MS_ENABLE);
391                 } else {
392                         if (esc->mii_model != MII_MODEL_MARVELL_E3082)
393                                 PHY_WRITE(sc, E1000_1GCR, 0);
394                 }
395                 PHY_WRITE(sc, E1000_AR, E1000_AR_SELECTOR_FIELD);
396                 PHY_WRITE(sc, E1000_CR, speed | E1000_CR_RESET);
397 done:
398                 break;
399         case MII_TICK:
400                 /*
401                  * If we're not currently selected, just return.
402                  */
403                 if (IFM_INST(ife->ifm_media) != sc->mii_inst)
404                         return (0);
405
406                 /*
407                  * Is the interface even up?
408                  */
409                 if ((mii->mii_ifp->if_flags & IFF_UP) == 0)
410                         return (0);
411
412                 /*
413                  * Only used for autonegotiation.
414                  */
415                 if (IFM_SUBTYPE(ife->ifm_media) != IFM_AUTO) {
416                         sc->mii_ticks = 0;
417                         break;
418                 }
419
420                 /*
421                  * check for link.
422                  * Read the status register twice; BMSR_LINK is latch-low.
423                  */
424                 reg = PHY_READ(sc, MII_BMSR) | PHY_READ(sc, MII_BMSR);
425                 if (reg & BMSR_LINK) {
426                         sc->mii_ticks = 0;
427                         break;
428                 }
429
430                 /* Announce link loss right after it happens. */
431                 if (sc->mii_ticks++ == 0)
432                         break;
433                 if (sc->mii_ticks <= sc->mii_anegticks)
434                         return (0);
435
436                 sc->mii_ticks = 0;
437                 e1000phy_reset(sc);
438                 e1000phy_mii_phy_auto(esc);
439                 break;
440         }
441
442         /* Update the media status. */
443         e1000phy_status(sc);
444
445         /* Callback if something changed. */
446         mii_phy_update(sc, cmd);
447         return (0);
448 }
449
450 static void
451 e1000phy_status(struct mii_softc *sc)
452 {
453         struct mii_data *mii = sc->mii_pdata;
454         int bmsr, bmcr, esr, gsr, ssr, isr, ar, lpar;
455
456         mii->mii_media_status = IFM_AVALID;
457         mii->mii_media_active = IFM_ETHER;
458
459         bmsr = PHY_READ(sc, E1000_SR) | PHY_READ(sc, E1000_SR);
460         esr = PHY_READ(sc, E1000_ESR);
461         bmcr = PHY_READ(sc, E1000_CR);
462         ssr = PHY_READ(sc, E1000_SSR);
463         isr = PHY_READ(sc, E1000_ISR);
464         ar = PHY_READ(sc, E1000_AR);
465         lpar = PHY_READ(sc, E1000_LPAR);
466
467         if (bmsr & E1000_SR_LINK_STATUS)
468                 mii->mii_media_status |= IFM_ACTIVE;
469
470         if (bmcr & E1000_CR_LOOPBACK)
471                 mii->mii_media_active |= IFM_LOOP;
472
473         if ((((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0) &&
474             ((bmsr & E1000_SR_AUTO_NEG_COMPLETE) == 0)) ||
475             ((ssr & E1000_SSR_LINK) == 0) ||
476             ((ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0)) {
477                 /* Erg, still trying, I guess... */
478                 mii->mii_media_active |= IFM_NONE;
479                 return;
480         }
481
482         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
483                 if (ssr & E1000_SSR_1000MBS)
484                         mii->mii_media_active |= IFM_1000_T;
485                 else if (ssr & E1000_SSR_100MBS)
486                         mii->mii_media_active |= IFM_100_TX;
487                 else
488                         mii->mii_media_active |= IFM_10_T;
489         } else {
490                 if (ssr & E1000_SSR_1000MBS)
491                         mii->mii_media_active |= IFM_1000_SX;
492         }
493
494         if (ssr & E1000_SSR_DUPLEX)
495                 mii->mii_media_active |= IFM_FDX;
496         else
497                 mii->mii_media_active |= IFM_HDX;
498
499         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
500                 /* FLAG0==rx-flow-control FLAG1==tx-flow-control */
501                 if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) {
502                         mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
503                 } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
504                     (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
505                         mii->mii_media_active |= IFM_FLAG1;
506                 } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
507                     !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
508                         mii->mii_media_active |= IFM_FLAG0;
509                 }
510         }
511
512         /* FLAG2 : local PHY resolved to MASTER */
513         if ((IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_T) ||
514             (IFM_SUBTYPE(mii->mii_media_active) == IFM_1000_SX)) {
515                 PHY_READ(sc, E1000_1GSR);
516                 gsr = PHY_READ(sc, E1000_1GSR);
517                 if ((gsr & E1000_1GSR_MS_CONFIG_RES) != 0)
518                         mii->mii_media_active |= IFM_FLAG2;
519         }
520 }
521
522 static int
523 e1000phy_mii_phy_auto(struct e1000phy_softc *esc)
524 {
525         struct mii_softc *sc;
526
527         sc = &esc->mii_sc;
528         if ((sc->mii_flags & MIIF_HAVEFIBER) == 0)
529                 PHY_WRITE(sc, E1000_AR, E1000_AR_10T | E1000_AR_10T_FD |
530                     E1000_AR_100TX | E1000_AR_100TX_FD |
531                     E1000_AR_PAUSE | E1000_AR_ASM_DIR);
532         else
533                 PHY_WRITE(sc, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X |
534                     E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE);
535         if (esc->mii_model != MII_MODEL_MARVELL_E3082)
536                 PHY_WRITE(sc, E1000_1GCR,
537                     E1000_1GCR_1000T_FD | E1000_1GCR_1000T);
538         PHY_WRITE(sc, E1000_CR,
539             E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG);
540
541         return (EJUSTRETURN);
542 }