• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**  <at> file
2 *  Support for Marvell 88E1000 Series PHYs
3 *
4 *  Copyright (c) 2011-2016, ARM Limited. All rights reserved.
5 *
6 *  This program and the accompanying materials
7 *  are licensed and made available under the terms and conditions of the BSD License
8 *  which accompanies this distribution.  The full text of the license may be found at
9 *  http://opensource.org/licenses/bsd-license.php
10 *
11 *  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 *  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 *
14 **/
15 /*-
16  * Principal Author: Parag Patel
17  * Copyright (c) 2001
18  * All rights reserved.
19  *
20  * Redistribution and use in source and binary forms, with or without
21  * modification, are permitted provided that the following conditions
22  * are met:
23  * 1. Redistributions of source code must retain the above copyright
24  *    notice unmodified, this list of conditions, and the following
25  *    disclaimer.
26  * 2. Redistributions in binary form must reproduce the above copyright
27  *    notice, this list of conditions and the following disclaimer in the
28  *    documentation and/or other materials provided with the distribution.
29  *
30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40  * SUCH DAMAGE.
41  *
42  * Additonal Copyright (c) 2001 by Traakan Software under same licence.
43  * Secondary Author: Matthew Jacob
44  */
45 
46 /*
47  * driver for the Marvell 88E1000 series external 1000/100/10-BT PHY.
48  */
49 
50 /*
51  * Support added for the Marvell 88E1011 (Alaska) 1000/100/10baseTX and
52  * 1000baseSX PHY.
53  * Nathan Binkert <nate <at> openbsd.org>
54  * Jung-uk Kim <jkim <at> niksun.com>
55  */
56 
57 #include <Library/MemoryAllocationLib.h>
58 #include <Library/BaseLib.h>
59 #include <Library/DebugLib.h>
60 #include <Library/UefiBootServicesTableLib.h>
61 
62 #include "if_media.h"
63 
64 #include "miivar.h"
65 
66 #include "e1000phyreg.h"
67 
68 static EFI_STATUS e1000phy_probe (const struct mii_attach_args *ma);
69 STATIC VOID  e1000phy_attach (struct e1000phy_softc *, const struct mii_attach_args *ma);
70 STATIC VOID  e1000phy_service (struct e1000phy_softc *, INTN);
71 STATIC VOID  e1000phy_status (struct e1000phy_softc *);
72 STATIC VOID  e1000phy_reset (struct e1000phy_softc *);
73 STATIC VOID  e1000phy_mii_phy_auto (struct e1000phy_softc *);
74 
75 INTN msk_phy_readreg (VOID *, INTN);
76 INTN msk_phy_writereg (VOID *, INTN, INTN);
77 VOID msk_miibus_statchg (VOID *);
78 
79 static const struct mii_phydesc * mii_phy_match (const struct mii_attach_args *ma,
80                                                  const struct mii_phydesc *mpd);
81 static const struct mii_phydesc * mii_phy_match_gen (const struct mii_attach_args *ma,
82                                                      const struct mii_phydesc *mpd, UINTN endlen);
83 static EFI_STATUS mii_phy_dev_probe (const struct mii_attach_args *ma, const struct mii_phydesc *mpd);
84 STATIC VOID mii_phy_update (struct e1000phy_softc *, INTN);
85 
86 static const struct mii_phydesc e1000phys[] = {
87   MII_PHY_DESC (MARVELL, E1000),
88   MII_PHY_DESC (MARVELL, E1011),
89   MII_PHY_DESC (MARVELL, E1000_3),
90   MII_PHY_DESC (MARVELL, E1000S),
91   MII_PHY_DESC (MARVELL, E1000_5),
92   MII_PHY_DESC (MARVELL, E1000_6),
93   MII_PHY_DESC (MARVELL, E3082),
94   MII_PHY_DESC (MARVELL, E1112),
95   MII_PHY_DESC (MARVELL, E1149),
96   MII_PHY_DESC (MARVELL, E1111),
97   MII_PHY_DESC (MARVELL, E1116),
98   MII_PHY_DESC (MARVELL, E1116R),
99   MII_PHY_DESC (MARVELL, E1118),
100   MII_PHY_DESC (MARVELL, E3016),
101   MII_PHY_DESC (MARVELL, PHYG65G),
102   MII_PHY_DESC (xxMARVELL, E1000),
103   MII_PHY_DESC (xxMARVELL, E1011),
104   MII_PHY_DESC (xxMARVELL, E1000_3),
105   MII_PHY_DESC (xxMARVELL, E1000_5),
106   MII_PHY_DESC (xxMARVELL, E1111),
107   MII_PHY_END
108 };
109 
110 EFI_STATUS
e1000_probe_and_attach(struct mii_data * mii,const struct msk_mii_data * mmd,VOID * sc_if,VOID ** rsc_phy)111 e1000_probe_and_attach (
112     struct mii_data             *mii,
113     const struct msk_mii_data   *mmd,
114     VOID                        *sc_if,
115     VOID                        **rsc_phy
116     )
117 {
118   struct mii_attach_args    ma;
119   INTN                      bmsr;
120   EFI_STATUS                Status;
121   struct e1000phy_softc        *sc_phy;
122 
123   Status = gBS->AllocatePool (EfiBootServicesData,
124                               sizeof (struct e1000phy_softc),
125                               (VOID**) &sc_phy);
126   if (EFI_ERROR (Status)) {
127     return Status;
128   }
129   gBS->SetMem (sc_phy, sizeof (struct e1000phy_softc), 0);
130   sc_phy->mmd = mmd;
131 
132   sc_phy->sc_if = sc_if;
133 
134   /*
135    * Check to see if there is a PHY at this address.  Note,
136    * many braindead PHYs report 0/0 in their ID registers,
137    * so we test for media in the BMSR.
138    */
139   bmsr = PHY_READ (sc_phy, E1000_SR);
140   if (bmsr == 0 || bmsr == 0xffff || (bmsr & (E1000_SR_EXTENDED_STATUS|E1000_SR_MEDIAMASK)) == 0) {
141     /* Assume no PHY at this address. */
142     gBS->FreePool (sc_phy);
143     return EFI_DEVICE_ERROR;
144   }
145 
146   /*
147    * Extract the IDs.
148    */
149   ma.mii_id1 = PHY_READ (sc_phy, E1000_ID1);
150   ma.mii_id2 = PHY_READ (sc_phy, E1000_ID2);
151 
152   ma.mii_data = mii;
153 
154   Status = e1000phy_probe (&ma);
155   if (EFI_ERROR (Status)) {
156     gBS->FreePool (sc_phy);
157     return Status;
158   }
159 
160   e1000phy_attach (sc_phy, &ma);
161 
162   *rsc_phy = sc_phy;
163 
164   return EFI_SUCCESS;
165 }
166 
167 VOID
e1000phy_detach(struct e1000phy_softc * sc_phy)168 e1000phy_detach (
169     struct e1000phy_softc *sc_phy
170     )
171 {
172   if (sc_phy != NULL) {
173     gBS->FreePool (sc_phy);
174   }
175 }
176 
177 EFI_STATUS
e1000phy_probe(const struct mii_attach_args * ma)178 e1000phy_probe (
179     const struct mii_attach_args    *ma
180     )
181 {
182   return (mii_phy_dev_probe (ma, e1000phys));
183 }
184 
185 static void
e1000phy_attach(struct e1000phy_softc * sc_phy,const struct mii_attach_args * ma)186 e1000phy_attach (
187     struct e1000phy_softc        *sc_phy,
188     const struct mii_attach_args *ma
189     )
190 {
191   struct mii_softc    *sc;
192 
193   sc = &sc_phy->mii_sc;
194   sc->mii_pdata = ma->mii_data;
195   sc->mii_anegticks = MII_ANEGTICKS_GIGE;
196 
197   sc_phy->mii_model = MII_MODEL (ma->mii_id2);
198 
199   if (sc_phy->mmd != NULL && (sc_phy->mmd->mii_flags & MIIF_HAVEFIBER) != 0) {
200     sc->mii_flags |= MIIF_HAVEFIBER;
201   }
202 
203   switch (sc_phy->mii_model) {
204     case MII_MODEL_MARVELL_E1011:
205     case MII_MODEL_MARVELL_E1112:
206       if (PHY_READ (sc_phy, E1000_ESSR) & E1000_ESSR_FIBER_LINK) {
207         sc->mii_flags |= MIIF_HAVEFIBER;
208       }
209       break;
210     case MII_MODEL_MARVELL_E1149:
211       /*
212      * Some 88E1149 PHY's page select is initialized to
213      * point to other bank instead of copper/fiber bank
214      * which in turn resulted in wrong registers were
215      * accessed during PHY operation. It is believed that
216      * page 0 should be used for copper PHY so reinitialize
217      * E1000_EADR to select default copper PHY. If parent
218      * device know the type of PHY(either copper or fiber),
219      * that information should be used to select default
220      * type of PHY.
221      */
222       PHY_WRITE (sc_phy, E1000_EADR, 0);
223       break;
224   }
225 
226   e1000phy_reset (sc_phy);
227 
228   sc->mii_capabilities = PHY_READ (sc_phy, E1000_SR) & 0xFFFFFFFF;
229   if (sc->mii_capabilities & E1000_SR_EXTENDED_STATUS) {
230     sc->mii_extcapabilities = PHY_READ (sc_phy, E1000_ESR);
231   }
232 }
233 
234 static void
e1000phy_reset(struct e1000phy_softc * sc_phy)235 e1000phy_reset (
236     struct e1000phy_softc  *sc_phy
237     )
238 {
239   UINT16  reg;
240   UINT16  page;
241   struct mii_softc *sc;
242 
243   sc = &sc_phy->mii_sc;
244 
245   reg = PHY_READ (sc_phy, E1000_SCR);
246   if ((sc->mii_flags & MIIF_HAVEFIBER) != 0) {
247     reg &= ~E1000_SCR_AUTO_X_MODE;
248     PHY_WRITE (sc_phy, E1000_SCR, reg);
249     if (sc_phy->mii_model == MII_MODEL_MARVELL_E1112) {
250       // Select 1000BASE-X only mode.
251       page = PHY_READ (sc_phy, E1000_EADR);
252       PHY_WRITE (sc_phy, E1000_EADR, 2);
253       reg = PHY_READ (sc_phy, E1000_SCR);
254       reg &= ~E1000_SCR_MODE_MASK;
255       reg |= E1000_SCR_MODE_1000BX;
256       PHY_WRITE (sc_phy, E1000_SCR, reg);
257       if (sc_phy->mmd != NULL && sc_phy->mmd->pmd == 'P') {
258         // Set SIGDET polarity low for SFP module
259         PHY_WRITE (sc_phy, E1000_EADR, 1);
260         reg = PHY_READ (sc_phy, E1000_SCR);
261         reg |= E1000_SCR_FIB_SIGDET_POLARITY;
262         PHY_WRITE (sc_phy, E1000_SCR, reg);
263       }
264       PHY_WRITE (sc_phy, E1000_EADR, page);
265     }
266   } else {
267     switch (sc_phy->mii_model) {
268       case MII_MODEL_MARVELL_E1111:
269       case MII_MODEL_MARVELL_E1112:
270       case MII_MODEL_MARVELL_E1116:
271       case MII_MODEL_MARVELL_E1118:
272       case MII_MODEL_MARVELL_E1149:
273       case MII_MODEL_MARVELL_PHYG65G:
274         // Disable energy detect mode
275         reg &= ~E1000_SCR_EN_DETECT_MASK;
276         reg |= E1000_SCR_AUTO_X_MODE;
277         if (sc_phy->mii_model == MII_MODEL_MARVELL_E1116)
278           reg &= ~E1000_SCR_POWER_DOWN;
279         reg |= E1000_SCR_ASSERT_CRS_ON_TX;
280         break;
281       case MII_MODEL_MARVELL_E3082:
282         reg |= (E1000_SCR_AUTO_X_MODE >> 1);
283         reg |= E1000_SCR_ASSERT_CRS_ON_TX;
284         break;
285       case MII_MODEL_MARVELL_E3016:
286         reg |= E1000_SCR_AUTO_MDIX;
287         reg &= ~(E1000_SCR_EN_DETECT |
288                  E1000_SCR_SCRAMBLER_DISABLE);
289         reg |= E1000_SCR_LPNP;
290         // XXX Enable class A driver for Yukon FE+ A0
291         PHY_WRITE (sc_phy, 0x1C, PHY_READ (sc_phy, 0x1C) | 0x0001);
292         break;
293       default:
294         reg &= ~E1000_SCR_AUTO_X_MODE;
295         reg |= E1000_SCR_ASSERT_CRS_ON_TX;
296         break;
297     }
298     if (sc_phy->mii_model != MII_MODEL_MARVELL_E3016) {
299       /* Auto correction for reversed cable polarity. */
300       reg &= ~E1000_SCR_POLARITY_REVERSAL;
301     }
302     PHY_WRITE (sc_phy, E1000_SCR, reg);
303 
304     if (sc_phy->mii_model == MII_MODEL_MARVELL_E1116 ||
305         sc_phy->mii_model == MII_MODEL_MARVELL_E1149) {
306       PHY_WRITE (sc_phy, E1000_EADR, 2);
307       reg = PHY_READ (sc_phy, E1000_SCR);
308       reg |= E1000_SCR_RGMII_POWER_UP;
309       PHY_WRITE (sc_phy, E1000_SCR, reg);
310       PHY_WRITE (sc_phy, E1000_EADR, 0);
311     }
312   }
313 
314   switch (sc_phy->mii_model) {
315     case MII_MODEL_MARVELL_E3082:
316     case MII_MODEL_MARVELL_E1112:
317     case MII_MODEL_MARVELL_E1118:
318       break;
319     case MII_MODEL_MARVELL_E1116:
320       page = PHY_READ (sc_phy, E1000_EADR);
321       /* Select page 3, LED control register. */
322       PHY_WRITE (sc_phy, E1000_EADR, 3);
323       PHY_WRITE (sc_phy, E1000_SCR,
324                  E1000_SCR_LED_LOS (1) |  /* Link/Act */
325                  E1000_SCR_LED_INIT (8) |  /* 10Mbps */
326                  E1000_SCR_LED_STAT1 (7) |  /* 100Mbps */
327                  E1000_SCR_LED_STAT0 (7));  /* 1000Mbps */
328       /* Set blink rate. */
329       PHY_WRITE (sc_phy, E1000_IER, E1000_PULSE_DUR (E1000_PULSE_170MS) | E1000_BLINK_RATE (E1000_BLINK_84MS));
330       PHY_WRITE (sc_phy, E1000_EADR, page);
331       break;
332     case MII_MODEL_MARVELL_E3016:
333       /* LED2 -> ACT, LED1 -> LINK, LED0 -> SPEED. */
334       PHY_WRITE (sc_phy, 0x16, 0x0B << 8 | 0x05 << 4 | 0x04);
335       /* Integrated register calibration workaround. */
336       PHY_WRITE (sc_phy, 0x1D, 17);
337       PHY_WRITE (sc_phy, 0x1E, 0x3F60);
338       break;
339     default:
340       /* Force TX_CLK to 25MHz clock. */
341       reg = PHY_READ (sc_phy, E1000_ESCR);
342       reg |= E1000_ESCR_TX_CLK_25;
343       PHY_WRITE (sc_phy, E1000_ESCR, reg);
344       break;
345   }
346 
347   /* Reset the PHY so all changes take effect. */
348   reg = PHY_READ (sc_phy, E1000_CR);
349   reg |= E1000_CR_RESET;
350   PHY_WRITE (sc_phy, E1000_CR, reg);
351 }
352 
353 static void
mii_phy_update(struct e1000phy_softc * sc_phy,INTN cmd)354 mii_phy_update (
355     struct e1000phy_softc  *sc_phy,
356     INTN                   cmd
357     )
358 {
359   struct mii_softc      *sc = &sc_phy->mii_sc;
360   struct mii_data       *mii = sc->mii_pdata;
361 
362   if (sc->mii_media_active != mii->mii_media_active ||
363       sc->mii_media_status != mii->mii_media_status ||
364       cmd == MII_MEDIACHG)
365   {
366     msk_miibus_statchg (sc_phy->sc_if);
367     sc->mii_media_active = mii->mii_media_active;
368     sc->mii_media_status = mii->mii_media_status;
369   }
370 }
371 
372 void
e1000phy_tick(struct e1000phy_softc * sc_phy)373 e1000phy_tick (
374     struct e1000phy_softc  *sc_phy
375     )
376 {
377   e1000phy_service (sc_phy, MII_TICK);
378 }
379 
380 void
e1000phy_mediachg(struct e1000phy_softc * sc_phy)381 e1000phy_mediachg (
382     struct e1000phy_softc  *sc_phy
383     )
384 {
385   struct mii_data *mii;
386 
387   mii = sc_phy->mii_sc.mii_pdata;
388 
389   mii->mii_media_status = 0;
390   mii->mii_media_active = IFM_NONE;
391   e1000phy_service (sc_phy, MII_MEDIACHG);
392 }
393 
394 static void
e1000phy_service(struct e1000phy_softc * sc_phy,INTN cmd)395 e1000phy_service (
396     struct e1000phy_softc  *sc_phy,
397     INTN                   cmd
398     )
399 {
400   struct mii_softc    *sc;
401   INTN                reg;
402 
403   sc = &sc_phy->mii_sc;
404 
405   switch (cmd) {
406     case MII_POLLSTAT:
407       break;
408 
409     case MII_MEDIACHG:
410       //
411       // Always try to auto-negotiate
412       //
413       e1000phy_mii_phy_auto (sc_phy);
414       break;
415 
416     case MII_TICK:
417       /*
418      * check for link.
419      * Read the status register twice; Link Status is latch-low.
420      */
421       reg = PHY_READ (sc_phy, E1000_SR) | PHY_READ (sc_phy, E1000_SR);
422       if (reg & E1000_SR_LINK_STATUS) {
423         sc->mii_ticks = 0;
424         break;
425       }
426 
427       /* Announce link loss right after it happens. */
428       if (sc->mii_ticks++ == 0) {
429         break;
430       }
431       if (sc->mii_ticks <= sc->mii_anegticks) {
432         break;
433       }
434 
435       //
436       // Restart the auto-negotiation
437       //
438       sc->mii_ticks = 0;
439       e1000phy_reset (sc_phy);
440       e1000phy_mii_phy_auto (sc_phy);
441       break;
442   }
443 
444   /* Update the media status. */
445   e1000phy_status (sc_phy);
446 
447   /* Callback if something changed. */
448   mii_phy_update (sc_phy, cmd);
449 }
450 
451 static void
e1000phy_status(struct e1000phy_softc * sc_phy)452 e1000phy_status (
453     struct e1000phy_softc  *sc_phy
454     )
455 {
456   struct mii_softc    *sc;
457   struct mii_data     *mii;
458   INTN                bmcr;
459   INTN                bmsr;
460   INTN                gsr;
461   INTN                ssr;
462   INTN                ar;
463   INTN                lpar;
464 
465   sc = &sc_phy->mii_sc;
466   mii = sc->mii_pdata;
467 
468   mii->mii_media_status = IFM_AVALID;
469   mii->mii_media_active = IFM_ETHER;
470 
471   bmsr = PHY_READ (sc_phy, E1000_SR) | PHY_READ (sc_phy, E1000_SR);
472   bmcr = PHY_READ (sc_phy, E1000_CR);
473   ssr = PHY_READ (sc_phy, E1000_SSR);
474 
475   if (bmsr & E1000_SR_LINK_STATUS) {
476     DEBUG ((EFI_D_NET, "Marvell Yukon: e1000phy_status, link up\n"));
477     mii->mii_media_status |= IFM_ACTIVE;
478   }
479 
480   if (bmcr & E1000_CR_LOOPBACK) {
481     mii->mii_media_active |= IFM_LOOP;
482   }
483 
484   if ((bmcr & E1000_CR_AUTO_NEG_ENABLE) != 0 && (ssr & E1000_SSR_SPD_DPLX_RESOLVED) == 0) {
485     /* Erg, still trying, I guess... */
486     DEBUG ((EFI_D_NET, "Marvell Yukon: e1000phy_status, auto negotiation not complete\n"));
487     mii->mii_media_active |= IFM_NONE;
488     return;
489   }
490 
491   if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
492     switch (ssr & E1000_SSR_SPEED) {
493       case E1000_SSR_1000MBS:
494         mii->mii_media_active |= IFM_1000_T;
495         break;
496       case E1000_SSR_100MBS:
497         mii->mii_media_active |= IFM_100_TX;
498         break;
499       case E1000_SSR_10MBS:
500         mii->mii_media_active |= IFM_10_T;
501         break;
502       default:
503         mii->mii_media_active |= IFM_NONE;
504         return;
505     }
506   } else {
507     /*
508      * Some fiber PHY(88E1112) does not seem to set resolved
509      * speed so always assume we've got IFM_1000_SX.
510      */
511     mii->mii_media_active |= IFM_1000_SX;
512   }
513 
514   if (ssr & E1000_SSR_DUPLEX) {
515     mii->mii_media_active |= IFM_FDX;
516   } else {
517     mii->mii_media_active |= IFM_HDX;
518   }
519 
520   if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
521     ar = PHY_READ (sc_phy, E1000_AR);
522     lpar = PHY_READ (sc_phy, E1000_LPAR);
523     /* FLAG0==rx-flow-control FLAG1==tx-flow-control */
524     if ((ar & E1000_AR_PAUSE) && (lpar & E1000_LPAR_PAUSE)) {
525       mii->mii_media_active |= IFM_FLAG0 | IFM_FLAG1;
526     } else if (!(ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
527                (lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
528       mii->mii_media_active |= IFM_FLAG1;
529     } else if ((ar & E1000_AR_PAUSE) && (ar & E1000_AR_ASM_DIR) &&
530                !(lpar & E1000_LPAR_PAUSE) && (lpar & E1000_LPAR_ASM_DIR)) {
531       mii->mii_media_active |= IFM_FLAG0;
532     }
533   }
534 
535   /* FLAG2 : local PHY resolved to MASTER */
536   if ((IFM_SUBTYPE (mii->mii_media_active) == IFM_1000_T) ||
537       (IFM_SUBTYPE (mii->mii_media_active) == IFM_1000_SX)) {
538     PHY_READ (sc_phy, E1000_1GSR);
539     gsr = PHY_READ (sc_phy, E1000_1GSR);
540     if ((gsr & E1000_1GSR_MS_CONFIG_RES) != 0) {
541       mii->mii_media_active |= IFM_FLAG2;
542     }
543   }
544 }
545 
546 static void
e1000phy_mii_phy_auto(struct e1000phy_softc * sc_phy)547 e1000phy_mii_phy_auto (
548     struct e1000phy_softc  *sc_phy
549     )
550 {
551   struct mii_softc    *sc;
552   UINT16              reg;
553 
554   DEBUG ((EFI_D_NET, "Marvell Yukon: e1000phy_mii_phy_auto negotiation started\n"));
555   sc = &sc_phy->mii_sc;
556   if ((sc->mii_flags & MIIF_HAVEFIBER) == 0) {
557     reg = PHY_READ (sc_phy, E1000_AR);
558     reg |= E1000_AR_10T | E1000_AR_10T_FD |
559         E1000_AR_100TX | E1000_AR_100TX_FD |
560         E1000_AR_PAUSE | E1000_AR_ASM_DIR;
561     PHY_WRITE (sc_phy, E1000_AR, reg | E1000_AR_SELECTOR_FIELD);
562   } else {
563     PHY_WRITE (sc_phy, E1000_AR, E1000_FA_1000X_FD | E1000_FA_1000X | E1000_FA_SYM_PAUSE | E1000_FA_ASYM_PAUSE);
564   }
565 
566   if ((sc->mii_extcapabilities & (E1000_ESR_1000T_FD | E1000_ESR_1000T)) != 0) {
567     PHY_WRITE (sc_phy, E1000_1GCR, E1000_1GCR_1000T_FD | E1000_1GCR_1000T);
568   }
569 
570   PHY_WRITE (sc_phy, E1000_CR, E1000_CR_AUTO_NEG_ENABLE | E1000_CR_RESTART_AUTO_NEG);
571 }
572 
573 //
574 // Generic helper functions
575 //
576 
577 const struct mii_phydesc *
mii_phy_match_gen(const struct mii_attach_args * ma,const struct mii_phydesc * mpd,UINTN len)578     mii_phy_match_gen (
579     const struct mii_attach_args    *ma,
580     const struct mii_phydesc        *mpd,
581     UINTN                           len
582     )
583 {
584 
585   for (; mpd->mpd_name != NULL;
586        mpd = (const struct mii_phydesc *) ((const CHAR8 *) mpd + len)) {
587     if (MII_OUI (ma->mii_id1, ma->mii_id2) == mpd->mpd_oui &&
588         MII_MODEL (ma->mii_id2) == mpd->mpd_model) {
589       return (mpd);
590     }
591   }
592   return (NULL);
593 }
594 
595 const struct mii_phydesc *
mii_phy_match(const struct mii_attach_args * ma,const struct mii_phydesc * mpd)596     mii_phy_match (
597     const struct mii_attach_args    *ma,
598     const struct mii_phydesc        *mpd
599     )
600 {
601 
602   return (mii_phy_match_gen (ma, mpd, sizeof (struct mii_phydesc)));
603 }
604 
605 EFI_STATUS
mii_phy_dev_probe(const struct mii_attach_args * ma,const struct mii_phydesc * mpd)606 mii_phy_dev_probe (
607     const struct mii_attach_args    *ma,
608     const struct mii_phydesc        *mpd
609     )
610 {
611 
612   mpd = mii_phy_match (ma, mpd);
613   if (mpd != NULL) {
614     DEBUG ((EFI_D_NET, "Marvell Yukon: Found PHY (%a)\n", mpd->mpd_name));
615     return EFI_SUCCESS;
616   }
617 
618   DEBUG ((DEBUG_NET, "Marvell Yukon: PHY not found (OUI=0x%x, MODEL=0x%x)\n",
619          MII_OUI (ma->mii_id1, ma->mii_id2), MII_MODEL (ma->mii_id2)));
620   return EFI_NOT_FOUND;
621 }
622