/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include "nge.h"

#undef	NGE_DBG
#define	NGE_DBG		NGE_DBG_MII	/* debug flag for this code	*/

/*
 * The arrays below can be indexed by the MODE bits from the mac2phy
 * register to determine the current speed/duplex settings.
 */
static const int16_t nge_copper_link_speed[] = {
	0,				/* MII_AUX_STATUS_MODE_NONE	*/
	10,				/* MII_AUX_STAT0,US_MODE_10	*/
	100,				/* MII_AUX_STAT0,US_MODE_100	*/
	1000,				/* MII_AUX_STAT0,US_MODE_1000	*/
};

static const int8_t nge_copper_link_duplex[] = {
	LINK_DUPLEX_UNKNOWN,		/* MII_DUPLEX_NONE	*/
	LINK_DUPLEX_HALF,		/* MII_DUPLEX_HALF	*/
	LINK_DUPLEX_FULL,		/* MII_DUPLEX_FULL	*/
};


static uint16_t nge_mii_access(nge_t *ngep, nge_regno_t regno,
    uint16_t data, uint32_t cmd);
#pragma	inline(nge_mii_access)

static uint16_t
nge_mii_access(nge_t *ngep, nge_regno_t regno, uint16_t data, uint32_t cmd)
{
	uint16_t tries;
	uint16_t mdio_data;
	nge_mdio_adr mdio_adr;
	nge_mintr_src intr_src;

	NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)",
	    (void *)ngep, regno, data, cmd));

	/*
	 * Clear the privous interrupt event
	 */
	intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
	nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);

	/*
	 * Check whether the current operation has been finished
	 */
	mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
	for (tries = 0; tries < 30; tries ++) {
		if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
			break;
		drv_usecwait(10);
		mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
	}

	/*
	 * The current operation can not be finished successfully
	 *  The driver should halt the current operation
	 */
	if (tries == 30) {
		mdio_adr.adr_bits.mdio_clc = NGE_SET;
		nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);
		drv_usecwait(100);
	}

	/*
	 * Assemble the operation cmd
	 */
	mdio_adr.adr_bits.phy_reg = regno;
	mdio_adr.adr_bits.phy_adr = ngep->phy_xmii_addr;
	mdio_adr.adr_bits.mdio_rw = (cmd == NGE_MDIO_WRITE) ? 1 : 0;


	if (cmd == NGE_MDIO_WRITE)
		nge_reg_put16(ngep, NGE_MDIO_DATA, data);

	nge_reg_put16(ngep, NGE_MDIO_ADR, mdio_adr.adr_val);

	/*
	 * To check whether the read/write operation is finished
	 */
	for (tries = 0; tries < 300; tries ++) {
		drv_usecwait(10);
		mdio_adr.adr_val = nge_reg_get16(ngep, NGE_MDIO_ADR);
		if (mdio_adr.adr_bits.mdio_clc == NGE_CLEAR)
			break;
	}
	if (tries == 300)
		return ((uint16_t)~0);

	/*
	 * Read the data from MDIO data register
	 */
	if (cmd == NGE_MDIO_READ)
		mdio_data = nge_reg_get16(ngep, NGE_MDIO_DATA);

	/*
	 * To check whether the read/write operation is valid
	 */
	intr_src.src_val = nge_reg_get8(ngep, NGE_MINTR_SRC);
	nge_reg_put8(ngep, NGE_MINTR_SRC, intr_src.src_val);
	if (intr_src.src_bits.mrei == NGE_SET)
		return ((uint16_t)~0);

	return (mdio_data);
}

uint16_t nge_mii_get16(nge_t *ngep, nge_regno_t regno);
#pragma	inline(nge_mii_get16)

uint16_t
nge_mii_get16(nge_t *ngep, nge_regno_t regno)
{

	return (nge_mii_access(ngep, regno, 0, NGE_MDIO_READ));
}

void nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data);
#pragma	inline(nge_mii_put16)

void
nge_mii_put16(nge_t *ngep, nge_regno_t regno, uint16_t data)
{

	(void) nge_mii_access(ngep, regno, data, NGE_MDIO_WRITE);
}

/*
 * Basic low-level function to probe for a PHY
 *
 * Returns TRUE if the PHY responds with valid data, FALSE otherwise
 */
static boolean_t
nge_phy_probe(nge_t *ngep)
{
	int i;
	uint16_t phy_status;
	uint16_t phyidh;
	uint16_t phyidl;

	NGE_TRACE(("nge_phy_probe($%p)", (void *)ngep));

	/*
	 * Scan the phys to find the right address
	 * of the phy
	 *
	 * Probe maximum for 32 phy addresses
	 */
	for (i = 0; i < NGE_PHY_NUMBER; i++) {
		ngep->phy_xmii_addr = i;
		/*
		 * Read the MII_STATUS register twice, in
		 * order to clear any sticky bits (but they should
		 * have been cleared by the RESET, I think).
		 */
		phy_status = nge_mii_get16(ngep, MII_STATUS);
		phy_status = nge_mii_get16(ngep, MII_STATUS);
		if (phy_status != 0xffff) {
			phyidh = nge_mii_get16(ngep, MII_PHYIDH);
			phyidl = nge_mii_get16(ngep, MII_PHYIDL);
			ngep->phy_id =
			    (((uint32_t)phyidh << 16) |(phyidl & MII_IDL_MASK));
			NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x",
			    phy_status, ngep->phy_id));

			return (B_TRUE);
		}
	}

	return (B_FALSE);
}


/*
 * Basic low-level function to powerup the phy and remove the isolation
 */

static boolean_t
nge_phy_recover(nge_t *ngep)
{
	uint16_t control;
	uint16_t count;

	NGE_TRACE(("nge_phy_recover($%p)", (void *)ngep));
	control = nge_mii_get16(ngep, MII_CONTROL);
	control &= ~(MII_CONTROL_PWRDN | MII_CONTROL_ISOLATE);
	nge_mii_put16(ngep, MII_CONTROL, control);
	for (count = 0; ++count < 10; ) {
		drv_usecwait(5);
		control = nge_mii_get16(ngep, MII_CONTROL);
		if (BIC(control, MII_CONTROL_PWRDN))
			return (B_TRUE);
	}

	return (B_FALSE);
}
/*
 * Basic low-level function to reset the PHY.
 * Doesn't incorporate any special-case workarounds.
 *
 * Returns TRUE on success, FALSE if the RESET bit doesn't clear
 */
boolean_t
nge_phy_reset(nge_t *ngep)
{
	uint16_t control;
	uint_t count;

	NGE_TRACE(("nge_phy_reset($%p)", (void *)ngep));

	ASSERT(mutex_owned(ngep->genlock));

	/*
	 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
	 */
	control = nge_mii_get16(ngep, MII_CONTROL);
	control |= MII_CONTROL_RESET;
	nge_mii_put16(ngep, MII_CONTROL, control);
	/* We should wait for 500ms. It's defined in the manual */
	delay(drv_usectohz(500000));
	for (count = 0; ++count < 10; ) {
		drv_usecwait(5);
		control = nge_mii_get16(ngep, MII_CONTROL);
		if (BIC(control, MII_CONTROL_RESET))
			return (B_TRUE);
	}
	NGE_DEBUG(("nge_phy_reset: FAILED, control now 0x%x", control));

	return (B_FALSE);
}

static boolean_t
nge_phy_restart(nge_t *ngep)
{
	uint16_t mii_reg;

	if (!nge_phy_recover(ngep))
		return (B_FALSE);
	if (!nge_phy_reset(ngep))
		return (B_FALSE);

	if (PHY_MANUFACTURER(ngep->phy_id) == MII_ID_CICADA) {
		if (ngep->phy_mode == RGMII_IN) {
			mii_reg = nge_mii_get16(ngep,
			    MII_CICADA_EXT_CONTROL);
			mii_reg &= ~(MII_CICADA_MODE_SELECT_BITS
			    | MII_CICADA_POWER_SUPPLY_BITS);
			mii_reg |= (MII_CICADA_MODE_SELECT_RGMII
			    | MII_CICADA_POWER_SUPPLY_2_5V);
			nge_mii_put16(ngep, MII_CICADA_EXT_CONTROL, mii_reg);

			mii_reg = nge_mii_get16(ngep,
			    MII_CICADA_AUXCTRL_STATUS);
			mii_reg |= MII_CICADA_PIN_PRORITY_SETTING;
			nge_mii_put16(ngep, MII_CICADA_AUXCTRL_STATUS,
			    mii_reg);
		} else {
			mii_reg = nge_mii_get16(ngep,
			    MII_CICADA_10BASET_CONTROL);
			mii_reg |= MII_CICADA_DISABLE_ECHO_MODE;
			nge_mii_put16(ngep,
			    MII_CICADA_10BASET_CONTROL, mii_reg);

			mii_reg = nge_mii_get16(ngep,
			    MII_CICADA_BYPASS_CONTROL);
			mii_reg &= (~CICADA_125MHZ_CLOCK_ENABLE);
			nge_mii_put16(ngep, MII_CICADA_BYPASS_CONTROL, mii_reg);
		}
	}

	return (B_TRUE);
}

/*
 * Synchronise the (copper) PHY's speed/duplex/autonegotiation capabilities
 * and advertisements with the required settings as specified by the various
 * param_* variables that can be poked via the NDD interface.
 *
 * We always reset the PHY and reprogram *all* the relevant registers,
 * not just those changed.  This should cause the link to go down, and then
 * back up again once the link is stable and autonegotiation (if enabled)
 * is complete.  We should get a link state change interrupt somewhere along
 * the way ...
 *
 * NOTE: <genlock> must already be held by the caller
 */
static void
nge_update_copper(nge_t *ngep)
{
	uint16_t control;
	uint16_t gigctrl;
	uint16_t anar;
	boolean_t adv_autoneg;
	boolean_t adv_pause;
	boolean_t adv_asym_pause;
	boolean_t adv_1000fdx;
	boolean_t adv_100fdx;
	boolean_t adv_100hdx;
	boolean_t adv_10fdx;
	boolean_t adv_10hdx;

	NGE_TRACE(("nge_update_copper($%p)", (void *)ngep));

	ASSERT(mutex_owned(ngep->genlock));

	NGE_DEBUG(("nge_update_copper: autoneg %d "
	    "pause %d asym_pause %d "
	    "1000fdx %d "
	    "100fdx %d 100hdx %d "
	    "10fdx %d 10hdx %d ",
	    ngep->param_adv_autoneg,
	    ngep->param_adv_pause, ngep->param_adv_asym_pause,
	    ngep->param_adv_1000fdx,
	    ngep->param_adv_100fdx, ngep->param_adv_100hdx,
	    ngep->param_adv_10fdx, ngep->param_adv_10hdx));

	control = anar = gigctrl = 0;

	/*
	 * PHY settings are normally based on the param_* variables,
	 * but if any loopback mode is in effect, that takes precedence.
	 *
	 * NGE supports MAC-internal loopback, PHY-internal loopback,
	 * and External loopback at a variety of speeds (with a special
	 * cable).  In all cases, autoneg is turned OFF, full-duplex
	 * is turned ON, and the speed/mastership is forced.
	 */
	switch (ngep->param_loop_mode) {
	case NGE_LOOP_NONE:
	default:
		adv_pause = ngep->param_adv_pause;
		adv_autoneg = ngep->param_adv_autoneg;
		adv_asym_pause = ngep->param_adv_asym_pause;
		if (ngep->phy_mode == MII_IN) {
			adv_1000fdx = ngep->param_adv_1000fdx = B_FALSE;
		}
		adv_1000fdx = ngep->param_adv_1000fdx;
		adv_100fdx = ngep->param_adv_100fdx;
		adv_100hdx = ngep->param_adv_100hdx;
		adv_10fdx = ngep->param_adv_10fdx;
		adv_10hdx = ngep->param_adv_10hdx;

		break;

	case NGE_LOOP_EXTERNAL_100:
	case NGE_LOOP_EXTERNAL_10:
	case NGE_LOOP_INTERNAL_PHY:
		adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
		adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
		adv_100hdx = adv_10hdx = B_FALSE;
		ngep->param_link_duplex = LINK_DUPLEX_FULL;

		switch (ngep->param_loop_mode) {
		case NGE_LOOP_EXTERNAL_100:
			ngep->param_link_speed = 100;
			adv_100fdx = B_TRUE;
			break;

		case NGE_LOOP_EXTERNAL_10:
			ngep->param_link_speed = 10;
			adv_10fdx = B_TRUE;
			break;

		case NGE_LOOP_INTERNAL_PHY:
			ngep->param_link_speed = 1000;
			adv_1000fdx = B_TRUE;
			break;

		}
	}
	NGE_DEBUG(("nge_update_copper: autoneg %d "
	    "pause %d asym_pause %d "
	    "1000fdx %d "
	    "100fdx %d 100hdx %d "
	    "10fdx %d 10hdx %d ",
	    adv_autoneg,
	    adv_pause, adv_asym_pause,
	    adv_1000fdx,
	    adv_100fdx, adv_100hdx,
	    adv_10fdx, adv_10hdx));

	/*
	 * We should have at least one technology capability set;
	 * if not, we select a default of 10Mb/s half-duplex
	 */
	if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
	    !adv_100hdx && !adv_10hdx)
		adv_10hdx = B_TRUE;

	/*
	 * Now transform the adv_* variables into the proper settings
	 * of the PHY registers ...
	 *
	 * If autonegotiation is (now) enabled, we want to trigger
	 * a new autonegotiation cycle once the PHY has been
	 * programmed with the capabilities to be advertised.
	 */
	if (adv_autoneg)
		control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;

	if (adv_1000fdx)
		control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX;
	else if (adv_100fdx)
		control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
	else if (adv_100hdx)
		control |= MII_CONTROL_100MB;
	else if (adv_10fdx)
		control |= MII_CONTROL_FDUPLEX;
	else if (adv_10hdx)
		control |= 0;
	else
		{ _NOTE(EMPTY); }	/* Can't get here anyway ...	*/

	if (adv_1000fdx)
		gigctrl |= MII_1000BT_CTL_ADV_FDX;
	if (adv_100fdx)
		anar |= MII_ABILITY_100BASE_TX_FD;
	if (adv_100hdx)
		anar |= MII_ABILITY_100BASE_TX;
	if (adv_10fdx)
		anar |= MII_ABILITY_10BASE_T_FD;
	if (adv_10hdx)
		anar |= MII_ABILITY_10BASE_T;

	if (adv_pause)
		anar |= MII_ABILITY_PAUSE;
	if (adv_asym_pause)
		anar |= MII_ABILITY_ASYM_PAUSE;

	/*
	 * Munge in any other fixed bits we require ...
	 */
	anar |= MII_AN_SELECTOR_8023;

	/*
	 * Restart the PHY and write the new values.
	 */
	nge_mii_put16(ngep, MII_AN_ADVERT, anar);
	nge_mii_put16(ngep, MII_CONTROL, control);
	nge_mii_put16(ngep, MII_1000BASE_T_CONTROL, gigctrl);
	if (!nge_phy_restart(ngep))
		nge_error(ngep, "nge_update_copper: failed to restart phy");
	/*
	 * Loopback bit in control register is not reset sticky
	 * write it after PHY restart.
	 */
	if (ngep->param_loop_mode == NGE_LOOP_INTERNAL_PHY) {
		control = nge_mii_get16(ngep, MII_CONTROL);
		control |= MII_CONTROL_LOOPBACK;
		nge_mii_put16(ngep, MII_CONTROL, control);
	}
}

static boolean_t
nge_check_copper(nge_t *ngep)
{
	uint16_t mii_status;
	uint16_t mii_exstatus;
	uint16_t mii_excontrol;
	uint16_t anar;
	uint16_t lpan;
	uint_t speed;
	uint_t duplex;
	boolean_t linkup;
	nge_mii_cs mii_cs;
	nge_mintr_src mintr_src;

	speed = UNKOWN_SPEED;
	duplex = UNKOWN_DUPLEX;
	/*
	 * Read the status from the PHY (which is self-clearing
	 * on read!); also read & clear the main (Ethernet) MAC status
	 * (the relevant bits of this are write-one-to-clear).
	 */
	mii_status = nge_mii_get16(ngep, MII_STATUS);
	mii_cs.cs_val = nge_reg_get32(ngep, NGE_MII_CS);
	mintr_src.src_val = nge_reg_get32(ngep, NGE_MINTR_SRC);
	nge_reg_put32(ngep, NGE_MINTR_SRC, mintr_src.src_val);

	NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x "
	    "(was 0x%x)", ngep->link_state,
	    UPORDOWN(ngep->param_link_up), mii_status,
	    ngep->phy_gen_status));

	do {
		/*
		 * If the PHY status changed, record the time
		 */
		switch (ngep->phy_mode) {
		default:
		case RGMII_IN:

			/*
			 * Judge the giga speed by reading control
			 * and status register
			 */
			mii_excontrol = nge_mii_get16(ngep,
			    MII_1000BASE_T_CONTROL);
			mii_exstatus = nge_mii_get16(ngep,
			    MII_1000BASE_T_STATUS);
			if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) &&
			    (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP)) {
				speed  = NGE_1000M;
				duplex = NGE_FD;
			} else {
				anar = nge_mii_get16(ngep, MII_AN_ADVERT);
				lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
				if (lpan != 0)
					anar = (anar & lpan);
				if (anar & MII_100BASET_FD) {
					speed = NGE_100M;
					duplex = NGE_FD;
				} else if (anar & MII_100BASET_HD) {
					speed = NGE_100M;
					duplex = NGE_HD;
				} else if (anar & MII_10BASET_FD) {
					speed = NGE_10M;
					duplex = NGE_FD;
				} else if (anar & MII_10BASET_HD) {
					speed = NGE_10M;
					duplex = NGE_HD;
				}
			}
			break;
		case MII_IN:
			anar = nge_mii_get16(ngep, MII_AN_ADVERT);
			lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
			if (lpan != 0)
				anar = (anar & lpan);

			if (anar & MII_100BASET_FD) {
				speed = NGE_100M;
				duplex = NGE_FD;
			} else if (anar & MII_100BASET_HD) {
				speed = NGE_100M;
				duplex = NGE_HD;
			} else if (anar & MII_10BASET_FD) {
				speed = NGE_10M;
				duplex = NGE_FD;
			} else if (anar & MII_10BASET_HD) {
				speed = NGE_10M;
				duplex = NGE_HD;
			}
			break;
		}


		/*
		 * We will only consider the link UP if all the readings
		 * are consistent and give meaningful results ...
		 */
		linkup = nge_copper_link_speed[speed] > 0;
		linkup &= nge_copper_link_duplex[duplex] != LINK_DUPLEX_UNKNOWN;
		linkup &= BIS(mii_status, MII_STATUS_LINKUP);
		linkup &= BIS(mii_cs.cs_val, MII_STATUS_LINKUP);

		/*
		 * Record current register values, then reread status
		 * register & loop until it stabilises ...
		 */
		ngep->phy_gen_status = mii_status;
		mii_status = nge_mii_get16(ngep, MII_STATUS);
	} while (mii_status != ngep->phy_gen_status);

	/* Get the Link Partner Ability */
	mii_exstatus = nge_mii_get16(ngep, MII_1000BASE_T_STATUS);
	lpan = nge_mii_get16(ngep, MII_AN_LPABLE);
	if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) {
		ngep->param_lp_autoneg = B_TRUE;
		ngep->param_link_autoneg = B_TRUE;
		ngep->param_lp_1000fdx = B_TRUE;
	}
	if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) {
		ngep->param_lp_autoneg = B_TRUE;
		ngep->param_link_autoneg = B_TRUE;
		ngep->param_lp_1000hdx = B_TRUE;
	}
	if (lpan & MII_100BASET_FD)
		ngep->param_lp_100fdx = B_TRUE;
	if (lpan & MII_100BASET_HD)
		ngep->param_lp_100hdx = B_TRUE;
	if (lpan & MII_10BASET_FD)
		ngep->param_lp_10fdx = B_TRUE;
	if (lpan & MII_10BASET_HD)
		ngep->param_lp_10hdx = B_TRUE;
	if (lpan & MII_LP_ASYM_PAUSE)
		ngep->param_lp_asym_pause = B_TRUE;
	if (lpan & MII_LP_PAUSE)
		ngep->param_lp_pause = B_TRUE;
	ngep->param_link_tx_pause = B_FALSE;

	if (ngep->param_adv_autoneg)
		ngep->param_link_rx_pause = B_FALSE;
	else
		ngep->param_link_rx_pause = ngep->param_adv_pause;
	if (linkup) {
		ngep->param_link_up = linkup;
		ngep->param_link_speed = nge_copper_link_speed[speed];
		ngep->param_link_duplex = nge_copper_link_duplex[duplex];
	} else {
		ngep->param_link_up = B_FALSE;
		ngep->param_link_speed = 0;
		ngep->param_link_duplex = LINK_DUPLEX_UNKNOWN;
	}
	NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d",
	    UPORDOWN(ngep->param_link_up),
	    ngep->param_link_speed,
	    ngep->param_link_duplex));

	return (B_FALSE);
}

/*
 * Because the network chipset embedded in Ck8-04 bridge is only a mac chipset,
 * the different vendor can use different media(serdes and copper).
 * To make it easier to extend the driver to support more platforms with ck8-04,
 * For example, one platform with serdes support,
 * wrapper phy operation functions.
 * But now, only supply copper phy operations.
 */
static const phys_ops_t copper_ops = {
	nge_phy_restart,
	nge_update_copper,
	nge_check_copper
};

/*
 * Here we have to determine which media we're using (copper or serdes).
 * Once that's done, we can initialise the physical layer appropriately.
 */
void
nge_phys_init(nge_t *ngep)
{
	nge_mac2phy m2p;
	NGE_TRACE(("nge_phys_init($%p)", (void *)ngep));

	/* Get the phy type from MAC2PHY register */
	m2p.m2p_val = nge_reg_get32(ngep, NGE_MAC2PHY);
	ngep->phy_mode = m2p.m2p_bits.in_type;
	if ((ngep->phy_mode != RGMII_IN) && (ngep->phy_mode != MII_IN)) {
		ngep->phy_mode = RGMII_IN;
		m2p.m2p_bits.in_type = RGMII_IN;
		nge_reg_put32(ngep, NGE_MAC2PHY, m2p.m2p_val);
	}

	/*
	 * Probe for the type of the  PHY.
	 */
	ngep->phy_xmii_addr = 1;
	(void) nge_phy_probe(ngep);
	ngep->chipinfo.flags |= CHIP_FLAG_COPPER;
	ngep->physops = &copper_ops;
	(*(ngep->physops->phys_restart))(ngep);
}