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 */
36static 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
43static 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
50static 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
54static uint16_t
55nge_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
134uint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno);
135#pragma	inline(nge_mii_get16)
136
137uint16_t
138nge_mii_get16(nge_t *ngep, nge_regno_t regno)
139{
140
141	return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ));
142}
143
144void nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data);
145#pragma	inline(nge_mii_put16)
146
147void
148nge_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 */
159static boolean_t
160nge_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
204static boolean_t
205nge_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 */
229boolean_t
230nge_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
258static boolean_t
259nge_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 */
313static void
314nge_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
480static boolean_t
481nge_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 */
641static 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 */
651void
652nge_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