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