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