1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 #include "nge.h"
28
29 #undef NGE_DBG
30 #define NGE_DBG NGE_DBG_MII /* debug flag for this code */
31
32 /*
33 * The arrays below can be indexed by the MODE bits from the mac2phy
34 * register to determine the current speed/duplex settings.
35 */
36 static const int16_t nge_copper_link_speed[] = {
37 0, /* MII_AUX_STATUS_MODE_NONE */
38 10, /* MII_AUX_STAT0,US_MODE_10 */
39 100, /* MII_AUX_STAT0,US_MODE_100 */
40 1000, /* MII_AUX_STAT0,US_MODE_1000 */
41 };
42
43 static const int8_t nge_copper_link_duplex[] = {
44 LINK_DUPLEX_UNKNOWN, /* MII_DUPLEX_NONE */
45 LINK_DUPLEX_HALF, /* MII_DUPLEX_HALF */
46 LINK_DUPLEX_FULL, /* MII_DUPLEX_FULL */
47 };
48
49
50 static uint16_t nge_mii_access(nge_t *ngep, nge_regno_t regno,
51 uint16_t data, uint32_t cmd);
52 #pragma inline(nge_mii_access)
53
54 static uint16_t
nge_mii_access(nge_t * ngep,nge_regno_t regno,uint16_t data,uint32_t cmd)55 nge_mii_access(nge_t *ngep, nge_regno_t regno, uint16_t data, uint32_t cmd)
56 {
57 uint16_t tries;
58 uint16_t mdio_data;
59 nge_mdio_adr mdio_adr;
60 nge_mintr_src intr_src;
61
62 NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)",
63 (void *)ngep, regno, data, cmd));
64
65 /*
66 * Clear the privous interrupt event
67 */
68 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
69 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);
70
71 /*
72 * Check whether the current operation has been finished
73 */
74 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
75 for (tries = 0; tries < 30; tries ++) {
76 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
77 break;
78 drv_usecwait(10);
79 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
80 }
81
82 /*
83 * The current operation can not be finished successfully
84 * The driver should halt the current operation
85 */
86 if (tries == 30) {
87 mdio_adr.adr_bits.mdio_clc = NGE_SET;
88 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);
89 drv_usecwait(100);
90 }
91
92 /*
93 * Assemble the operation cmd
94 */
95 mdio_adr.adr_bits.phy_reg = (uint16_t)regno;
96 mdio_adr.adr_bits.phy_adr = ngep->phy_xmii_addr;
97 mdio_adr.adr_bits.mdio_rw = (cmd == NGE_MDIO_WRITE) ? 1 : 0;
98
99
100 if (cmd == NGE_MDIO_WRITE)
101 nge_reg_put16(ngep, NGE_MDIO_DATA, data);
102
103 nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);
104
105 /*
106 * To check whether the read/write operation is finished
107 */
108 for (tries = 0; tries < 300; tries ++) {
109 drv_usecwait(10);
110 mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
111 if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
112 break;
113 }
114 if (tries == 300)
115 return ((uint16_t)~0);
116
117 /*
118 * Read the data from MDIO data register
119 */
120 if (cmd == NGE_MDIO_READ)
121 mdio_data = nge_reg_get16(ngep, NGE_MDIO_DATA);
122
123 /*
124 * To check whether the read/write operation is valid
125 */
126 intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
127 nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);
128 if (intr_src.src_bits.mrei == NGE_SET)
129 return ((uint16_t)~0);
130
131 return (mdio_data);
132 }
133
134 uint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno);
135 #pragma inline(nge_mii_get16)
136
137 uint16_t
nge_mii_get16(nge_t * ngep,nge_regno_t regno)138 nge_mii_get16(nge_t *ngep, nge_regno_t regno)
139 {
140
141 return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ));
142 }
143
144 void nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data);
145 #pragma inline(nge_mii_put16)
146
147 void
nge_mii_put16(nge_t * ngep,nge_regno_t regno,uint16_t data)148 nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data)
149 {
150
151 (void) nge_mii_access(ngep, regno, data, NGE_MDIO_WRITE);
152 }
153
154 /*
155 * Basic low-level function to probe for a PHY
156 *
157 * Returns TRUE if the PHY responds with valid data, FALSE otherwise
158 */
159 static boolean_t
nge_phy_probe(nge_t * ngep)160 nge_phy_probe(nge_t *ngep)
161 {
162 int i;
163 uint16_t phy_status;
164 uint16_t phyidh;
165 uint16_t phyidl;
166
167 NGE_TRACE(("nge_phy_probe($%p)", (void *)ngep));
168
169 /*
170 * Scan the phys to find the right address
171 * of the phy
172 *
173 * Probe maximum for 32 phy addresses
174 */
175 for (i = 0; i < NGE_PHY_NUMBER; i++) {
176 ngep->phy_xmii_addr = i;
177 /*
178 * Read the MII_STATUS register twice, in
179 * order to clear any sticky bits (but they should
180 * have been cleared by the RESET, I think).
181 */
182 phy_status = nge_mii_get16(ngep, MII_STATUS);
183 phy_status = nge_mii_get16(ngep, MII_STATUS);
184 if (phy_status != 0xffff) {
185 phyidh = nge_mii_get16(ngep, MII_PHYIDH);
186 phyidl = nge_mii_get16(ngep, MII_PHYIDL);
187 ngep->phy_id =
188 (((uint32_t)phyidh << 16) |(phyidl & MII_IDL_MASK));
189 NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x",
190 phy_status, ngep->phy_id));
191
192 return (B_TRUE);
193 }
194 }
195
196 return (B_FALSE);
197 }
198
199
200 /*
201 * Basic low-level function to powerup the phy and remove the isolation
202 */
203
204 static boolean_t
nge_phy_recover(nge_t * ngep)205 nge_phy_recover(nge_t *ngep)
206 {
207 uint16_t control;
208 uint16_t count;
209
210 NGE_TRACE(("nge_phy_recover($%p)", (void *)ngep));
211 control = nge_mii_get16(ngep, MII_CONTROL);
212 control &= ~(MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
213 nge_mii_put16(ngep, MII_CONTROL, control);
214 for (count = 0; ++count < 10; ) {
215 drv_usecwait(5);
216 control = nge_mii_get16(ngep, MII_CONTROL);
217 if (BIC(control, MII_CONTROL_PWRDN))
218 return (B_TRUE);
219 }
220
221 return (B_FALSE);
222 }
223 /*
224 * Basic low-level function to reset the PHY.
225 * Doesn't incorporate any special-case workarounds.
226 *
227 * Returns TRUE on success, FALSE if the RESET bit doesn't clear
228 */
229 boolean_t
nge_phy_reset(nge_t * ngep)230 nge_phy_reset(nge_t *ngep)
231 {
232 uint16_t control;
233 uint_t count;
234
235 NGE_TRACE(("nge_phy_reset($%p)", (void *)ngep));
236
237 ASSERT(mutex_owned(ngep->genlock));
238
239 /*
240 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
241 */
242 control = nge_mii_get16(ngep, MII_CONTROL);
243 control |= MII_CONTROL_RESET;
244 nge_mii_put16(ngep, MII_CONTROL, control);
245 /* We should wait for 500ms. It's defined in the manual */
246 delay(drv_usectohz(500000));
247 for (count = 0; ++count < 10; ) {
248 drv_usecwait(5);
249 control = nge_mii_get16(ngep, MII_CONTROL);
250 if (BIC(control, MII_CONTROL_RESET))
251 return (B_TRUE);
252 }
253 NGE_DEBUG(("nge_phy_reset: FAILED, control now 0x%x", control));
254
255 return (B_FALSE);
256 }
257
258 static boolean_t
nge_phy_restart(nge_t * ngep)259 nge_phy_restart(nge_t *ngep)
260 {
261 uint16_t mii_reg;
262
263 if (!nge_phy_recover(ngep))
264 return (B_FALSE);
265 if (!nge_phy_reset(ngep))
266 return (B_FALSE);
267
268 if (MII_PHY_MFG(ngep->phy_id) == MII_ID_CICADA) {
269 if (ngep->phy_mode == RGMII_IN) {
270 mii_reg = nge_mii_get16(ngep,
271 MII_CICADA_EXT_CONTROL);
272 mii_reg &= ~(MII_CICADA_MODE_SELECT_BITS
273 | MII_CICADA_POWER_SUPPLY_BITS);
274 mii_reg |= (MII_CICADA_MODE_SELECT_RGMII
275 | MII_CICADA_POWER_SUPPLY_2_5V);
276 nge_mii_put16(ngep, MII_CICADA_EXT_CONTROL, mii_reg);
277
278 mii_reg = nge_mii_get16(ngep,
279 MII_CICADA_AUXCTRL_STATUS);
280 mii_reg |= MII_CICADA_PIN_PRORITY_SETTING;
281 nge_mii_put16(ngep, MII_CICADA_AUXCTRL_STATUS,
282 mii_reg);
283 } else {
284 mii_reg = nge_mii_get16(ngep,
285 MII_CICADA_10BASET_CONTROL);
286 mii_reg |= MII_CICADA_DISABLE_ECHO_MODE;
287 nge_mii_put16(ngep,
288 MII_CICADA_10BASET_CONTROL, mii_reg);
289
290 mii_reg = nge_mii_get16(ngep,
291 MII_CICADA_BYPASS_CONTROL);
292 mii_reg &= (~CICADA_125MHZ_CLOCK_ENABLE);
293 nge_mii_put16(ngep, MII_CICADA_BYPASS_CONTROL, mii_reg);
294 }
295 }
296
297 return (B_TRUE);
298 }
299
300 /*
301 * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities
302 * and advertisements with the required settings as specified by the various
303 * param_* variables that can be poked via the NDD interface.
304 *
305 * We always reset the PHY and reprogram *all* the relevant registers,
306 * not just those changed. This should cause the link to go down, and then
307 * back up again once the link is stable and autonegotiation (if enabled)
308 * is complete. We should get a link state change interrupt somewhere along
309 * the way ...
310 *
311 * NOTE: <genlock> must already be held by the caller
312 */
313 static void
nge_update_copper(nge_t * ngep)314 nge_update_copper(nge_t *ngep)
315 {
316 uint16_t control;
317 uint16_t gigctrl;
318 uint16_t anar;
319 boolean_t adv_autoneg;
320 boolean_t adv_pause;
321 boolean_t adv_asym_pause;
322 boolean_t adv_1000fdx;
323 boolean_t adv_100fdx;
324 boolean_t adv_100hdx;
325 boolean_t adv_10fdx;
326 boolean_t adv_10hdx;
327
328 NGE_TRACE(("nge_update_copper($%p)", (void *)ngep));
329
330 ASSERT(mutex_owned(ngep->genlock));
331
332 NGE_DEBUG(("nge_update_copper: autoneg %d "
333 "pause %d asym_pause %d "
334 "1000fdx %d "
335 "100fdx %d 100hdx %d "
336 "10fdx %d 10hdx %d ",
337 ngep->param_adv_autoneg,
338 ngep->param_adv_pause, ngep->param_adv_asym_pause,
339 ngep->param_adv_1000fdx,
340 ngep->param_adv_100fdx, ngep->param_adv_100hdx,
341 ngep->param_adv_10fdx, ngep->param_adv_10hdx));
342
343 control = anar = gigctrl = 0;
344
345 /*
346 * PHY settings are normally based on the param_* variables,
347 * but if any loopback mode is in effect, that takes precedence.
348 *
349 * NGE supports MAC-internal loopback, PHY-internal loopback,
350 * and External loopback at a variety of speeds (with a special
351 * cable). In all cases, autoneg is turned OFF, full-duplex
352 * is turned ON, and the speed/mastership is forced.
353 */
354 switch (ngep->param_loop_mode) {
355 case NGE_LOOP_NONE:
356 default:
357 adv_pause = ngep->param_adv_pause;
358 adv_autoneg = ngep->param_adv_autoneg;
359 adv_asym_pause = ngep->param_adv_asym_pause;
360 if (ngep->phy_mode == MII_IN) {
361 adv_1000fdx = ngep->param_adv_1000fdx = B_FALSE;
362 }
363 adv_1000fdx = ngep->param_adv_1000fdx;
364 adv_100fdx = ngep->param_adv_100fdx;
365 adv_100hdx = ngep->param_adv_100hdx;
366 adv_10fdx = ngep->param_adv_10fdx;
367 adv_10hdx = ngep->param_adv_10hdx;
368
369 break;
370
371 case NGE_LOOP_EXTERNAL_100:
372 case NGE_LOOP_EXTERNAL_10:
373 case NGE_LOOP_INTERNAL_PHY:
374 adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
375 adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
376 adv_100hdx = adv_10hdx = B_FALSE;
377 ngep->param_link_duplex = LINK_DUPLEX_FULL;
378
379 switch (ngep->param_loop_mode) {
380 case NGE_LOOP_EXTERNAL_100:
381 ngep->param_link_speed = 100;
382 adv_100fdx = B_TRUE;
383 break;
384
385 case NGE_LOOP_EXTERNAL_10:
386 ngep->param_link_speed = 10;
387 adv_10fdx = B_TRUE;
388 break;
389
390 case NGE_LOOP_INTERNAL_PHY:
391 ngep->param_link_speed = 1000;
392 adv_1000fdx = B_TRUE;
393 break;
394
395 }
396 }
397 NGE_DEBUG(("nge_update_copper: autoneg %d "
398 "pause %d asym_pause %d "
399 "1000fdx %d "
400 "100fdx %d 100hdx %d "
401 "10fdx %d 10hdx %d ",
402 adv_autoneg,
403 adv_pause, adv_asym_pause,
404 adv_1000fdx,
405 adv_100fdx, adv_100hdx,
406 adv_10fdx, adv_10hdx));
407
408 /*
409 * We should have at least one technology capability set;
410 * if not, we select a default of 10Mb/s half-duplex
411 */
412 if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
413 !adv_100hdx && !adv_10hdx)
414 adv_10hdx = B_TRUE;
415
416 /*
417 * Now transform the adv_* variables into the proper settings
418 * of the PHY registers ...
419 *
420 * If autonegotiation is (now) enabled, we want to trigger
421 * a new autonegotiation cycle once the PHY has been
422 * programmed with the capabilities to be advertised.
423 */
424 if (adv_autoneg)
425 control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
426
427 if (adv_1000fdx)
428 control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX;
429 else if (adv_100fdx)
430 control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
431 else if (adv_100hdx)
432 control |= MII_CONTROL_100MB;
433 else if (adv_10fdx)
434 control |= MII_CONTROL_FDUPLEX;
435 else if (adv_10hdx)
436 control |= 0;
437 else
438 { _NOTE(EMPTY); } /* Can't get here anyway ... */
439
440 if (adv_1000fdx)
441 gigctrl |= MII_1000BT_CTL_ADV_FDX;
442 if (adv_100fdx)
443 anar |= MII_ABILITY_100BASE_TX_FD;
444 if (adv_100hdx)
445 anar |= MII_ABILITY_100BASE_TX;
446 if (adv_10fdx)
447 anar |= MII_ABILITY_10BASE_T_FD;
448 if (adv_10hdx)
449 anar |= MII_ABILITY_10BASE_T;
450
451 if (adv_pause)
452 anar |= MII_ABILITY_PAUSE;
453 if (adv_asym_pause)
454 anar |= MII_ABILITY_ASMPAUSE;
455
456 /*
457 * Munge in any other fixed bits we require ...
458 */
459 anar |= MII_AN_SELECTOR_8023;
460
461 /*
462 * Restart the PHY and write the new values.
463 */
464 nge_mii_put16(ngep, MII_AN_ADVERT, anar);
465 nge_mii_put16(ngep, MII_CONTROL, control);
466 nge_mii_put16(ngep, MII_1000BASE_T_CONTROL, gigctrl);
467 if (!nge_phy_restart(ngep))
468 nge_error(ngep, "nge_update_copper: failed to restart phy");
469 /*
470 * Loopback bit in control register is not reset sticky
471 * write it after PHY restart.
472 */
473 if (ngep->param_loop_mode == NGE_LOOP_INTERNAL_PHY) {
474 control = nge_mii_get16(ngep, MII_CONTROL);
475 control |= MII_CONTROL_LOOPBACK;
476 nge_mii_put16(ngep, MII_CONTROL, control);
477 }
478 }
479
480 static boolean_t
nge_check_copper(nge_t * ngep)481 nge_check_copper(nge_t *ngep)
482 {
483 uint16_t mii_status;
484 uint16_t mii_exstatus;
485 uint16_t mii_excontrol;
486 uint16_t anar;
487 uint16_t lpan;
488 uint_t speed;
489 uint_t duplex;
490 boolean_t linkup;
491 nge_mii_cs mii_cs;
492 nge_mintr_src mintr_src;
493
494 speed = UNKOWN_SPEED;
495 duplex = UNKOWN_DUPLEX;
496 /*
497 * Read the status from the PHY (which is self-clearing
498 * on read!); also read & clear the main (Ethernet) MAC status
499 * (the relevant bits of this are write-one-to-clear).
500 */
501 mii_status = nge_mii_get16(ngep, MII_STATUS);
502 mii_cs.cs_val = nge_reg_get32(ngep, NGE_MII_CS);
503 mintr_src.src_val = nge_reg_get32(ngep, NGE_MINTR_SRC);
504 nge_reg_put32(ngep, NGE_MINTR_SRC, mintr_src.src_val);
505
506 NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x "
507 "(was 0x%x)", ngep->link_state,
508 UPORDOWN(ngep->param_link_up), mii_status,
509 ngep->phy_gen_status));
510
511 do {
512 /*
513 * If the PHY status changed, record the time
514 */
515 switch (ngep->phy_mode) {
516 default:
517 case RGMII_IN:
518
519 /*
520 * Judge the giga speed by reading control
521 * and status register
522 */
523 mii_excontrol = nge_mii_get16(ngep,
524 MII_1000BASE_T_CONTROL);
525 mii_exstatus = nge_mii_get16(ngep,
526 MII_1000BASE_T_STATUS);
527 if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) &&
528 (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP)) {
529 speed = NGE_1000M;
530 duplex = NGE_FD;
531 } else {
532 anar = nge_mii_get16(ngep, MII_AN_ADVERT);
533 lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
534 if (lpan != 0)
535 anar = (anar & lpan);
536 if (anar & MII_100BASET_FD) {
537 speed = NGE_100M;
538 duplex = NGE_FD;
539 } else if (anar & MII_100BASET_HD) {
540 speed = NGE_100M;
541 duplex = NGE_HD;
542 } else if (anar & MII_10BASET_FD) {
543 speed = NGE_10M;
544 duplex = NGE_FD;
545 } else if (anar & MII_10BASET_HD) {
546 speed = NGE_10M;
547 duplex = NGE_HD;
548 }
549 }
550 break;
551 case MII_IN:
552 anar = nge_mii_get16(ngep, MII_AN_ADVERT);
553 lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
554 if (lpan != 0)
555 anar = (anar & lpan);
556
557 if (anar & MII_100BASET_FD) {
558 speed = NGE_100M;
559 duplex = NGE_FD;
560 } else if (anar & MII_100BASET_HD) {
561 speed = NGE_100M;
562 duplex = NGE_HD;
563 } else if (anar & MII_10BASET_FD) {
564 speed = NGE_10M;
565 duplex = NGE_FD;
566 } else if (anar & MII_10BASET_HD) {
567 speed = NGE_10M;
568 duplex = NGE_HD;
569 }
570 break;
571 }
572
573
574 /*
575 * We will only consider the link UP if all the readings
576 * are consistent and give meaningful results ...
577 */
578 linkup = nge_copper_link_speed[speed] > 0;
579 linkup &= nge_copper_link_duplex[duplex] != LINK_DUPLEX_UNKNOWN;
580 linkup &= BIS(mii_status, MII_STATUS_LINKUP);
581 linkup &= BIS(mii_cs.cs_val, MII_STATUS_LINKUP);
582
583 /*
584 * Record current register values, then reread status
585 * register & loop until it stabilises ...
586 */
587 ngep->phy_gen_status = mii_status;
588 mii_status = nge_mii_get16(ngep, MII_STATUS);
589 } while (mii_status != ngep->phy_gen_status);
590
591 /* Get the Link Partner Ability */
592 mii_exstatus = nge_mii_get16(ngep, MII_1000BASE_T_STATUS);
593 lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
594 if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) {
595 ngep->param_lp_autoneg = B_TRUE;
596 ngep->param_link_autoneg = B_TRUE;
597 ngep->param_lp_1000fdx = B_TRUE;
598 }
599 if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) {
600 ngep->param_lp_autoneg = B_TRUE;
601 ngep->param_link_autoneg = B_TRUE;
602 ngep->param_lp_1000hdx = B_TRUE;
603 }
604 if (lpan & MII_100BASET_FD)
605 ngep->param_lp_100fdx = B_TRUE;
606 if (lpan & MII_100BASET_HD)
607 ngep->param_lp_100hdx = B_TRUE;
608 if (lpan & MII_10BASET_FD)
609 ngep->param_lp_10fdx = B_TRUE;
610 if (lpan & MII_10BASET_HD)
611 ngep->param_lp_10hdx = B_TRUE;
612 if (lpan & MII_LP_ASYM_PAUSE)
613 ngep->param_lp_asym_pause = B_TRUE;
614 if (lpan & MII_LP_PAUSE)
615 ngep->param_lp_pause = B_TRUE;
616 if (linkup) {
617 ngep->param_link_up = linkup;
618 ngep->param_link_speed = nge_copper_link_speed[speed];
619 ngep->param_link_duplex = nge_copper_link_duplex[duplex];
620 } else {
621 ngep->param_link_up = B_FALSE;
622 ngep->param_link_speed = 0;
623 ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
624 }
625 NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d",
626 UPORDOWN(ngep->param_link_up),
627 ngep->param_link_speed,
628 ngep->param_link_duplex));
629
630 return (B_FALSE);
631 }
632
633 /*
634 * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset,
635 * the different vendor can use different media(serdes and copper).
636 * To make it easier to extend the driver to support more platforms with ck8-04,
637 * For example, one platform with serdes support,
638 * wrapper phy operation functions.
639 * But now, only supply copper phy operations.
640 */
641 static const phys_ops_t copper_ops = {
642 nge_phy_restart,
643 nge_update_copper,
644 nge_check_copper
645 };
646
647 /*
648 * Here we have to determine which media we're using (copper or serdes).
649 * Once that's done, we can initialise the physical layer appropriately.
650 */
651 void
nge_phys_init(nge_t * ngep)652 nge_phys_init(nge_t *ngep)
653 {
654 nge_mac2phy m2p;
655 NGE_TRACE(("nge_phys_init($%p)", (void *)ngep));
656
657 /* Get the phy type from MAC2PHY register */
658 m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY);
659 ngep->phy_mode = m2p.m2p_bits.in_type;
660 if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) {
661 ngep->phy_mode = RGMII_IN;
662 m2p.m2p_bits.in_type = RGMII_IN;
663 nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val);
664 }
665
666 /*
667 * Probe for the type of the PHY.
668 */
669 ngep->phy_xmii_addr = 1;
670 (void) nge_phy_probe(ngep);
671 ngep->chipinfo.flags |= CHIP_FLAG_COPPER;
672 ngep->physops = &copper_ops;
673 (*(ngep->physops->phys_restart))(ngep);
674 }
675