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