Jan Kiszka provided a patch for the smc9000 for missing phy-setup
authortimlegge <timlegge>
Thu, 2 Jun 2005 01:14:40 +0000 (01:14 +0000)
committertimlegge <timlegge>
Thu, 2 Jun 2005 01:14:40 +0000 (01:14 +0000)
LOG
src/drivers/net/smc9000.c
src/drivers/net/smc9000.h

diff --git a/LOG b/LOG
index ab61c10..39179ac 100644 (file)
--- a/LOG
+++ b/LOG
@@ -2868,3 +2868,5 @@ driver
 that it supports the Gigabit nVidia NICs
 
 + Timothy Legge fixed relocation issues with the eepro driver
+
++ Jan Kiszka provided a patch for the smc9000 for missing phy-setup
index a05521e..a6cca3a 100644 (file)
 #define SMC9000_VERBOSE  1
 #define SMC9000_DEBUG    0
 
+#if SMC9000_DEBUG > 1
+#define PRINTK2 printf
+#else
+#define PRINTK2(args...)
+#endif
+
 #include "etherboot.h"
 #include "nic.h"
 #include "isa.h"
+#include "timer.h"
 #include "smc9000.h"
 
 # define _outb outb
@@ -49,11 +56,449 @@ static const char       *chip_ids[ 15 ] =  {
    NULL,
    /* 7 */ "SMC91C100",
    /* 8 */ "SMC91C100FD",
-   NULL, NULL, NULL,
+   /* 9 */ "SMC91C11xFD",
+   NULL, NULL,
    NULL, NULL, NULL
 };
 static const char      smc91c96_id[] = "SMC91C96";
 
+/*------------------------------------------------------------
+ . Reads a register from the MII Management serial interface
+ .-------------------------------------------------------------*/
+static word smc_read_phy_register(int ioaddr, byte phyaddr, byte phyreg)
+{
+    int oldBank;
+    unsigned int i;
+    byte mask;
+    word mii_reg;
+    byte bits[64];
+    int clk_idx = 0;
+    int input_idx;
+    word phydata;
+
+    // 32 consecutive ones on MDO to establish sync
+    for (i = 0; i < 32; ++i)
+        bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Start code <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Read command <10>
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+    bits[clk_idx++] = MII_MDOE;
+
+    // Output the PHY address, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyaddr & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Output the phy register number, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyreg & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Tristate and turnaround (2 bit times)
+    bits[clk_idx++] = 0;
+    //bits[clk_idx++] = 0;
+
+    // Input starts at this bit time
+    input_idx = clk_idx;
+
+    // Will input 16 bits
+    for (i = 0; i < 16; ++i)
+        bits[clk_idx++] = 0;
+
+    // Final clock bit
+    bits[clk_idx++] = 0;
+
+    // Save the current bank
+    oldBank = inw( ioaddr+BANK_SELECT );
+
+    // Select bank 3
+    SMC_SELECT_BANK(ioaddr, 3);
+
+    // Get the current MII register value
+    mii_reg = inw( ioaddr+MII_REG );
+
+    // Turn off all MII Interface bits
+    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+    // Clock all 64 cycles
+    for (i = 0; i < sizeof(bits); ++i)
+    {
+        // Clock Low - output data
+        outw( mii_reg | bits[i], ioaddr+MII_REG );
+        udelay(50);
+
+
+        // Clock Hi - input data
+        outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+        udelay(50);
+        bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+    }
+
+    // Return to idle state
+    // Set clock to low, data to low, and output tristated
+    outw( mii_reg, ioaddr+MII_REG );
+    udelay(50);
+
+    // Restore original bank select
+    SMC_SELECT_BANK(ioaddr, oldBank);
+
+    // Recover input data
+    phydata = 0;
+    for (i = 0; i < 16; ++i)
+    {
+        phydata <<= 1;
+
+        if (bits[input_idx++] & MII_MDI)
+            phydata |= 0x0001;
+    }
+
+#if (SMC_DEBUG > 2 )
+        printf("smc_read_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+               phyaddr, phyreg, phydata);
+#endif
+
+        return(phydata);
+}
+
+
+/*------------------------------------------------------------
+ . Writes a register to the MII Management serial interface
+ .-------------------------------------------------------------*/
+static void smc_write_phy_register(int ioaddr,
+                                   byte phyaddr, byte phyreg, word phydata)
+{
+    int oldBank;
+    unsigned int i;
+    word mask;
+    word mii_reg;
+    byte bits[65];
+    int clk_idx = 0;
+
+    // 32 consecutive ones on MDO to establish sync
+    for (i = 0; i < 32; ++i)
+        bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Start code <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Write command <01>
+    bits[clk_idx++] = MII_MDOE;
+    bits[clk_idx++] = MII_MDOE | MII_MDO;
+
+    // Output the PHY address, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyaddr & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+                // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Output the phy register number, msb first
+    mask = (byte)0x10;
+    for (i = 0; i < 5; ++i)
+    {
+        if (phyreg & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Tristate and turnaround (2 bit times)
+    bits[clk_idx++] = 0;
+    bits[clk_idx++] = 0;
+
+    // Write out 16 bits of data, msb first
+    mask = 0x8000;
+    for (i = 0; i < 16; ++i)
+    {
+        if (phydata & mask)
+            bits[clk_idx++] = MII_MDOE | MII_MDO;
+        else
+            bits[clk_idx++] = MII_MDOE;
+
+        // Shift to next lowest bit
+        mask >>= 1;
+    }
+
+    // Final clock bit (tristate)
+    bits[clk_idx++] = 0;
+
+    // Save the current bank
+    oldBank = inw( ioaddr+BANK_SELECT );
+
+    // Select bank 3
+    SMC_SELECT_BANK(ioaddr, 3);
+
+    // Get the current MII register value
+    mii_reg = inw( ioaddr+MII_REG );
+
+    // Turn off all MII Interface bits
+    mii_reg &= ~(MII_MDOE|MII_MCLK|MII_MDI|MII_MDO);
+
+    // Clock all cycles
+    for (i = 0; i < sizeof(bits); ++i)
+    {
+        // Clock Low - output data
+        outw( mii_reg | bits[i], ioaddr+MII_REG );
+        udelay(50);
+
+
+        // Clock Hi - input data
+        outw( mii_reg | bits[i] | MII_MCLK, ioaddr+MII_REG );
+        udelay(50);
+        bits[i] |= inw( ioaddr+MII_REG ) & MII_MDI;
+    }
+
+    // Return to idle state
+    // Set clock to low, data to low, and output tristated
+    outw( mii_reg, ioaddr+MII_REG );
+    udelay(50);
+
+    // Restore original bank select
+    SMC_SELECT_BANK(ioaddr, oldBank);
+
+#if (SMC_DEBUG > 2 )
+        printf("smc_write_phy_register(): phyaddr=%x,phyreg=%x,phydata=%x\n",
+               phyaddr, phyreg, phydata);
+#endif
+}
+
+
+/*------------------------------------------------------------
+ . Finds and reports the PHY address
+ .-------------------------------------------------------------*/
+static int smc_detect_phy(int ioaddr, byte *pphyaddr)
+{
+    word phy_id1;
+    word phy_id2;
+    int phyaddr;
+    int found = 0;
+
+    // Scan all 32 PHY addresses if necessary
+    for (phyaddr = 0; phyaddr < 32; ++phyaddr)
+    {
+        // Read the PHY identifiers
+        phy_id1  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID1_REG);
+        phy_id2  = smc_read_phy_register(ioaddr, phyaddr, PHY_ID2_REG);
+
+        // Make sure it is a valid identifier
+        if ((phy_id2 > 0x0000) && (phy_id2 < 0xffff) &&
+             (phy_id1 > 0x0000) && (phy_id1 < 0xffff))
+        {
+            if ((phy_id1 != 0x8000) && (phy_id2 != 0x8000))
+            {
+                // Save the PHY's address
+                *pphyaddr = phyaddr;
+                found = 1;
+                break;
+            }
+        }
+    }
+
+    if (!found)
+    {
+        printf("No PHY found\n");
+        return(0);
+    }
+
+    // Set the PHY type
+    if ( (phy_id1 == 0x0016) && ((phy_id2 & 0xFFF0) == 0xF840 ) )
+    {
+        printf("PHY=LAN83C183 (LAN91C111 Internal)\n");
+    }
+
+    if ( (phy_id1 == 0x0282) && ((phy_id2 & 0xFFF0) == 0x1C50) )
+    {
+        printf("PHY=LAN83C180\n");
+    }
+
+    return(1);
+}
+
+/*------------------------------------------------------------
+ . Configures the specified PHY using Autonegotiation. Calls
+ . smc_phy_fixed() if the user has requested a certain config.
+ .-------------------------------------------------------------*/
+static void smc_phy_configure(int ioaddr)
+{
+    int timeout;
+    byte phyaddr;
+    word my_phy_caps; // My PHY capabilities
+    word my_ad_caps; // My Advertised capabilities
+    word status;
+    int failed = 0;
+    int rpc_cur_mode = RPC_DEFAULT;
+    int lastPhy18;
+
+    // Find the address and type of our phy
+    if (!smc_detect_phy(ioaddr, &phyaddr))
+    {
+        return;
+    }
+
+    // Reset the PHY, setting all other bits to zero
+    smc_write_phy_register(ioaddr, phyaddr, PHY_CNTL_REG, PHY_CNTL_RST);
+
+    // Wait for the reset to complete, or time out
+    timeout = 6; // Wait up to 3 seconds
+    while (timeout--)
+    {
+        if (!(smc_read_phy_register(ioaddr, phyaddr, PHY_CNTL_REG)
+              & PHY_CNTL_RST))
+        {
+            // reset complete
+            break;
+        }
+
+        mdelay(500); // wait 500 millisecs
+    }
+
+    if (timeout < 1)
+    {
+        PRINTK2("PHY reset timed out\n");
+        return;
+    }
+
+    // Read PHY Register 18, Status Output
+    lastPhy18 = smc_read_phy_register(ioaddr, phyaddr, PHY_INT_REG);
+
+    // Enable PHY Interrupts (for register 18)
+    // Interrupts listed here are disabled
+    smc_write_phy_register(ioaddr, phyaddr, PHY_MASK_REG,
+                           PHY_INT_LOSSSYNC | PHY_INT_CWRD | PHY_INT_SSD |
+                                   PHY_INT_ESD | PHY_INT_RPOL | PHY_INT_JAB |
+                                   PHY_INT_SPDDET | PHY_INT_DPLXDET);
+
+    /* Configure the Receive/Phy Control register */
+    SMC_SELECT_BANK(ioaddr, 0);
+    outw( rpc_cur_mode, ioaddr + RPC_REG );
+
+    // Copy our capabilities from PHY_STAT_REG to PHY_AD_REG
+    my_phy_caps = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+    my_ad_caps  = PHY_AD_CSMA; // I am CSMA capable
+
+    if (my_phy_caps & PHY_STAT_CAP_T4)
+        my_ad_caps |= PHY_AD_T4;
+
+    if (my_phy_caps & PHY_STAT_CAP_TXF)
+        my_ad_caps |= PHY_AD_TX_FDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TXH)
+        my_ad_caps |= PHY_AD_TX_HDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TF)
+        my_ad_caps |= PHY_AD_10_FDX;
+
+    if (my_phy_caps & PHY_STAT_CAP_TH)
+        my_ad_caps |= PHY_AD_10_HDX;
+
+    // Update our Auto-Neg Advertisement Register
+    smc_write_phy_register(ioaddr, phyaddr, PHY_AD_REG, my_ad_caps);
+
+    PRINTK2("phy caps=%x\n", my_phy_caps);
+    PRINTK2("phy advertised caps=%x\n", my_ad_caps);
+
+    // Restart auto-negotiation process in order to advertise my caps
+    smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+                            PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST );
+
+    // Wait for the auto-negotiation to complete.  This may take from
+    // 2 to 3 seconds.
+    // Wait for the reset to complete, or time out
+    timeout = 20; // Wait up to 10 seconds
+    while (timeout--)
+    {
+        status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);
+        if (status & PHY_STAT_ANEG_ACK)
+        {
+            // auto-negotiate complete
+            break;
+        }
+
+        mdelay(500); // wait 500 millisecs
+
+        // Restart auto-negotiation if remote fault
+        if (status & PHY_STAT_REM_FLT)
+        {
+            PRINTK2("PHY remote fault detected\n");
+
+            // Restart auto-negotiation
+            PRINTK2("PHY restarting auto-negotiation\n");
+            smc_write_phy_register( ioaddr, phyaddr, PHY_CNTL_REG,
+                                    PHY_CNTL_ANEG_EN | PHY_CNTL_ANEG_RST |
+                                    PHY_CNTL_SPEED | PHY_CNTL_DPLX);
+        }
+    }
+
+    if (timeout < 1)
+    {
+        PRINTK2("PHY auto-negotiate timed out\n");
+        failed = 1;
+    }
+
+    // Fail if we detected an auto-negotiate remote fault
+    if (status & PHY_STAT_REM_FLT)
+    {
+        PRINTK2("PHY remote fault detected\n");
+        failed = 1;
+    }
+
+    // Set our sysctl parameters to match auto-negotiation results
+    if ( lastPhy18 & PHY_INT_SPDDET )
+    {
+        PRINTK2("PHY 100BaseT\n");
+        rpc_cur_mode |= RPC_SPEED;
+    }
+    else
+    {
+        PRINTK2("PHY 10BaseT\n");
+        rpc_cur_mode &= ~RPC_SPEED;
+    }
+
+    if ( lastPhy18 & PHY_INT_DPLXDET )
+    {
+        PRINTK2("PHY Full Duplex\n");
+        rpc_cur_mode |= RPC_DPLX;
+    }
+    else
+    {
+        PRINTK2("PHY Half Duplex\n");
+        rpc_cur_mode &= ~RPC_DPLX;
+    }
+
+    // Re-Configure the Receive/Phy Control register
+    outw( rpc_cur_mode, ioaddr + RPC_REG );
+}
+
 /*
  * Function: smc_reset( int ioaddr )
  * Purpose:
@@ -516,6 +961,8 @@ static int smc9000_probe(struct dev *dev, unsigned short *probe_addrs)
           smc9000_base + CONFIG );
    }
 
+   smc_phy_configure(smc9000_base);
+
    dev->disable  = smc9000_disable;
    nic->poll     = smc9000_poll;
    nic->transmit = smc9000_transmit;
index ac7f916..ffe5bbd 100644 (file)
@@ -91,6 +91,24 @@ typedef unsigned long int            dword;
 #define        MCR             10
 /* 12 is reserved */
 
+// Receive/Phy Control Register
+/* BANK 0  */
+#define RPC_REG         0x000A
+#define RPC_SPEED       0x2000  // When 1 PHY is in 100Mbps mode.
+#define RPC_DPLX        0x1000  // When 1 PHY is in Full-Duplex Mode
+#define RPC_ANEG        0x0800  // When 1 PHY is in Auto-Negotiate Mode
+#define RPC_LSXA_SHFT   5       // Bits to shift LS2A,LS1A,LS0A to lsb
+#define RPC_LSXB_SHFT   2       // Bits to get LS2B,LS1B,LS0B to lsb
+#define RPC_LED_100_10  (0x00)  // LED = 100Mbps OR's with 10Mbps link detect
+#define RPC_LED_RES     (0x01)  // LED = Reserved
+#define RPC_LED_10      (0x02)  // LED = 10Mbps link detect
+#define RPC_LED_FD      (0x03)  // LED = Full Duplex Mode
+#define RPC_LED_TX_RX   (0x04)  // LED = TX or RX packet occurred
+#define RPC_LED_100     (0x05)  // LED = 100Mbps link dectect
+#define RPC_LED_TX      (0x06)  // LED = TX packet occurred
+#define RPC_LED_RX      (0x07)  // LED = RX packet occurred
+#define RPC_DEFAULT (RPC_ANEG | (RPC_LED_100 << RPC_LSXA_SHFT) | (RPC_LED_FD << RPC_LSXB_SHFT) | RPC_SPEED | RPC_DPLX)
+
 /* BANK 1 */
 #define CONFIG                 0
 #define CFG_AUI_SELECT         0x100
@@ -151,6 +169,13 @@ typedef unsigned long int          dword;
 #define        MGMT            8
 #define        REVISION        10 /* ( hi: chip id   low: rev # ) */
 
+// Management Interface Register (MII)
+#define MII_REG         0x0008
+#define MII_MSK_CRS100  0x4000 // Disables CRS100 detection during tx half dup
+#define MII_MDOE        0x0008 // MII Output Enable
+#define MII_MCLK        0x0004 // MII Clock, pin MDCLK
+#define MII_MDI         0x0002 // MII Input, pin MDI
+#define MII_MDO         0x0001 // MII Output, pin MDO
 
 /* this is NOT on SMC9192 */
 #define        ERCV            12
@@ -186,6 +211,95 @@ typedef unsigned long int          dword;
 #define RS_ERRORS      (RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
 
 
+// PHY Register Addresses (LAN91C111 Internal PHY)
+
+// PHY Control Register
+#define PHY_CNTL_REG            0x00
+#define PHY_CNTL_RST            0x8000  // 1=PHY Reset
+#define PHY_CNTL_LPBK           0x4000  // 1=PHY Loopback
+#define PHY_CNTL_SPEED          0x2000  // 1=100Mbps, 0=10Mpbs
+#define PHY_CNTL_ANEG_EN        0x1000 // 1=Enable Auto negotiation
+#define PHY_CNTL_PDN            0x0800  // 1=PHY Power Down mode
+#define PHY_CNTL_MII_DIS        0x0400  // 1=MII 4 bit interface disabled
+#define PHY_CNTL_ANEG_RST       0x0200 // 1=Reset Auto negotiate
+#define PHY_CNTL_DPLX           0x0100  // 1=Full Duplex, 0=Half Duplex
+#define PHY_CNTL_COLTST         0x0080  // 1= MII Colision Test
+
+// PHY Status Register
+#define PHY_STAT_REG            0x01
+#define PHY_STAT_CAP_T4         0x8000  // 1=100Base-T4 capable
+#define PHY_STAT_CAP_TXF        0x4000  // 1=100Base-X full duplex capable
+#define PHY_STAT_CAP_TXH        0x2000  // 1=100Base-X half duplex capable
+#define PHY_STAT_CAP_TF         0x1000  // 1=10Mbps full duplex capable
+#define PHY_STAT_CAP_TH         0x0800  // 1=10Mbps half duplex capable
+#define PHY_STAT_CAP_SUPR       0x0040  // 1=recv mgmt frames with not preamble
+#define PHY_STAT_ANEG_ACK       0x0020  // 1=ANEG has completed
+#define PHY_STAT_REM_FLT        0x0010  // 1=Remote Fault detected
+#define PHY_STAT_CAP_ANEG       0x0008  // 1=Auto negotiate capable
+#define PHY_STAT_LINK           0x0004  // 1=valid link
+#define PHY_STAT_JAB            0x0002  // 1=10Mbps jabber condition
+#define PHY_STAT_EXREG          0x0001  // 1=extended registers implemented
+
+// PHY Identifier Registers
+#define PHY_ID1_REG             0x02    // PHY Identifier 1
+#define PHY_ID2_REG             0x03    // PHY Identifier 2
+
+// PHY Auto-Negotiation Advertisement Register
+#define PHY_AD_REG              0x04
+#define PHY_AD_NP               0x8000  // 1=PHY requests exchange of Next Page
+#define PHY_AD_ACK              0x4000  // 1=got link code word from remote
+#define PHY_AD_RF               0x2000  // 1=advertise remote fault
+#define PHY_AD_T4               0x0200  // 1=PHY is capable of 100Base-T4
+#define PHY_AD_TX_FDX           0x0100  // 1=PHY is capable of 100Base-TX FDPLX
+#define PHY_AD_TX_HDX           0x0080  // 1=PHY is capable of 100Base-TX HDPLX
+#define PHY_AD_10_FDX           0x0040  // 1=PHY is capable of 10Base-T FDPLX
+#define PHY_AD_10_HDX           0x0020  // 1=PHY is capable of 10Base-T HDPLX
+#define PHY_AD_CSMA             0x0001  // 1=PHY is capable of 802.3 CMSA
+
+// PHY Auto-negotiation Remote End Capability Register
+#define PHY_RMT_REG             0x05
+// Uses same bit definitions as PHY_AD_REG
+
+// PHY Configuration Register 1
+#define PHY_CFG1_REG            0x10
+#define PHY_CFG1_LNKDIS         0x8000  // 1=Rx Link Detect Function disabled
+#define PHY_CFG1_XMTDIS         0x4000  // 1=TP Transmitter Disabled
+#define PHY_CFG1_XMTPDN         0x2000  // 1=TP Transmitter Powered Down
+#define PHY_CFG1_BYPSCR         0x0400  // 1=Bypass scrambler/descrambler
+#define PHY_CFG1_UNSCDS         0x0200  // 1=Unscramble Idle Reception Disable
+#define PHY_CFG1_EQLZR          0x0100  // 1=Rx Equalizer Disabled
+#define PHY_CFG1_CABLE          0x0080  // 1=STP(150ohm), 0=UTP(100ohm)
+#define PHY_CFG1_RLVL0          0x0040  // 1=Rx Squelch level reduced by 4.5db
+#define PHY_CFG1_TLVL_SHIFT     2       // Transmit Output Level Adjust
+#define PHY_CFG1_TLVL_MASK      0x003C
+#define PHY_CFG1_TRF_MASK       0x0003  // Transmitter Rise/Fall time
+
+
+// PHY Configuration Register 2
+#define PHY_CFG2_REG            0x11
+#define PHY_CFG2_APOLDIS        0x0020  // 1=Auto Polarity Correction disabled
+#define PHY_CFG2_JABDIS         0x0010  // 1=Jabber disabled
+#define PHY_CFG2_MREG           0x0008  // 1=Multiple register access (MII mgt)
+#define PHY_CFG2_INTMDIO        0x0004  // 1=Interrupt signaled with MDIO pulseo
+
+// PHY Status Output (and Interrupt status) Register
+#define PHY_INT_REG             0x12    // Status Output (Interrupt Status)
+#define PHY_INT_INT             0x8000  // 1=bits have changed since last read
+#define PHY_INT_LNKFAIL         0x4000  // 1=Link Not detected
+#define PHY_INT_LOSSSYNC        0x2000  // 1=Descrambler has lost sync
+#define PHY_INT_CWRD            0x1000  // 1=Invalid 4B5B code detected on rx
+#define PHY_INT_SSD             0x0800  // 1=No Start Of Stream detected on rx
+#define PHY_INT_ESD             0x0400  // 1=No End Of Stream detected on rx
+#define PHY_INT_RPOL            0x0200  // 1=Reverse Polarity detected
+#define PHY_INT_JAB             0x0100  // 1=Jabber detected
+#define PHY_INT_SPDDET          0x0080  // 1=100Base-TX mode, 0=10Base-T mode
+#define PHY_INT_DPLXDET         0x0040  // 1=Device in Full Duplex
+
+// PHY Interrupt/Status Mask Register
+#define PHY_MASK_REG            0x13    // Interrupt Mask
+// Uses the same bit definitions as PHY_INT_REG
+
+
 /*-------------------------------------------------------------------------
  *  I define some macros to make it easier to do somewhat common
  * or slightly complicated, repeated tasks.