nge_xmii.c revision 5164839fa87447c0a1186035041427886a572d29
/*
* 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
* 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"
/*
* The arrays below can be indexed by the MODE bits from the mac2phy
*/
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 */
};
#pragma inline(nge_mii_access)
static uint16_t
{
NGE_TRACE(("nge_mii_access($%p, 0x%lx, 0x%x, 0x%x)",
/*
* Clear the privous interrupt event
*/
/*
* Check whether the current operation has been finished
*/
break;
drv_usecwait(10);
}
/*
* The current operation can not be finished successfully
* The driver should halt the current operation
*/
if (tries == 30) {
drv_usecwait(100);
}
/*
* Assemble the operation cmd
*/
if (cmd == NGE_MDIO_WRITE)
/*
*/
drv_usecwait(10);
break;
}
if (tries == 300)
return ((uint16_t)~0);
/*
* Read the data from MDIO data register
*/
if (cmd == NGE_MDIO_READ)
/*
*/
return ((uint16_t)~0);
return (mdio_data);
}
#pragma inline(nge_mii_get16)
{
}
#pragma inline(nge_mii_put16)
void
{
}
/*
* Basic low-level function to probe for a PHY
*
* Returns TRUE if the PHY responds with valid data, FALSE otherwise
*/
static boolean_t
{
int i;
/*
* 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).
*/
if (phy_status != 0xffff) {
NGE_DEBUG(("nge_phy_probe: status 0x%x, phy id 0x%x",
return (B_TRUE);
}
}
return (B_FALSE);
}
/*
* Basic low-level function to powerup the phy and remove the isolation
*/
static boolean_t
{
drv_usecwait(5);
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
*/
{
/*
* Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
*/
/* We should wait for 500ms. It's defined in the manual */
drv_usecwait(5);
return (B_TRUE);
}
return (B_FALSE);
}
static boolean_t
{
if (!nge_phy_recover(ngep))
return (B_FALSE);
if (!nge_phy_reset(ngep))
return (B_FALSE);
mii_reg);
} else {
}
}
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_DEBUG(("nge_update_copper: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d "
"100fdx %d 100hdx %d "
"10fdx %d 10hdx %d ",
/*
* 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:
}
break;
case NGE_LOOP_EXTERNAL_100:
case NGE_LOOP_EXTERNAL_10:
case NGE_LOOP_INTERNAL_PHY:
switch (ngep->param_loop_mode) {
case NGE_LOOP_EXTERNAL_100:
adv_100fdx = B_TRUE;
break;
case NGE_LOOP_EXTERNAL_10:
break;
case NGE_LOOP_INTERNAL_PHY:
break;
}
}
NGE_DEBUG(("nge_update_copper: autoneg %d "
"pause %d asym_pause %d "
"1000fdx %d "
"100fdx %d 100hdx %d "
"10fdx %d 10hdx %d ",
/*
* We should have at least one technology capability set;
* if not, we select a default of 10Mb/s half-duplex
*/
!adv_100hdx && !adv_10hdx)
/*
* 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)
if (adv_1000fdx)
else if (adv_100fdx)
else if (adv_100hdx)
else if (adv_10fdx)
else if (adv_10hdx)
control |= 0;
else
if (adv_1000fdx)
if (adv_100fdx)
if (adv_100hdx)
if (adv_10fdx)
if (adv_10hdx)
if (adv_pause)
if (adv_asym_pause)
/*
* Munge in any other fixed bits we require ...
*/
/*
* Restart the PHY and write the new values.
*/
if (!nge_phy_restart(ngep))
/*
* Loopback bit in control register is not reset sticky
* write it after PHY restart.
*/
}
}
static boolean_t
{
/*
* 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).
*/
NGE_DEBUG(("nge_check_copper: link %d/%s, MII status 0x%x "
ngep->phy_gen_status));
do {
/*
* If the PHY status changed, record the time
*/
default:
case RGMII_IN:
/*
* Judge the giga speed by reading control
* and status register
*/
if ((mii_excontrol & MII_1000BT_CTL_ADV_FDX) &&
} else {
if (lpan != 0)
if (anar & MII_100BASET_FD) {
} else if (anar & MII_100BASET_HD) {
} else if (anar & MII_10BASET_FD) {
} else if (anar & MII_10BASET_HD) {
}
}
break;
case MII_IN:
if (lpan != 0)
if (anar & MII_100BASET_FD) {
} else if (anar & MII_100BASET_HD) {
} else if (anar & MII_10BASET_FD) {
} else if (anar & MII_10BASET_HD) {
}
break;
}
/*
* We will only consider the link UP if all the readings
* are consistent and give meaningful results ...
*/
/*
* Record current register values, then reread status
* register & loop until it stabilises ...
*/
/* Get the Link Partner Ability */
if (mii_exstatus & MII_1000BT_STAT_LP_FDX_CAP) {
}
if (mii_exstatus & MII_1000BT_STAT_LP_HDX_CAP) {
}
if (lpan & MII_100BASET_FD)
if (lpan & MII_100BASET_HD)
if (lpan & MII_10BASET_FD)
if (lpan & MII_10BASET_HD)
if (lpan & MII_LP_ASYM_PAUSE)
if (lpan & MII_LP_PAUSE)
if (ngep->param_adv_autoneg)
else
if (linkup) {
} else {
ngep->param_link_speed = 0;
}
NGE_DEBUG(("nge_check_copper: link now %s speed %d duplex %d",
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 = {
};
/*
* 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
{
/* Get the phy type from MAC2PHY register */
}
/*
* Probe for the type of the PHY.
*/
(void) nge_phy_probe(ngep);
}