Add support for em(4) on Teak 3020, a Tolopai (EP80579)
authordms <dms@openbsd.org>
Thu, 4 Jun 2015 18:33:41 +0000 (18:33 +0000)
committerdms <dms@openbsd.org>
Thu, 4 Jun 2015 18:33:41 +0000 (18:33 +0000)
based devices. This introduces Realtek PHY into em driver
code and is only a temporary solution to the problem.

OK deraadt@

sys/dev/mii/rgephyreg.h
sys/dev/pci/if_em.c
sys/dev/pci/if_em_hw.c
sys/dev/pci/if_em_hw.h
sys/dev/pci/if_em_soc.h

index 6c9f8db..5e3db5d 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rgephyreg.h,v 1.6 2014/11/24 00:13:42 brad Exp $      */
+/*     $OpenBSD: rgephyreg.h,v 1.7 2015/06/04 18:33:41 dms Exp $       */
 /*
  * Copyright (c) 2003
  *     Bill Paul <wpaul@windriver.com>.  All rights reserved.
 #define RGEPHY_ANER_LPNP       0x0008  /* Link partner can next page */
 #define RGEPHY_ANER_NP         0x0004  /* Local PHY can next page */
 #define RGEPHY_ANER_RX         0x0002  /* Next page received */
+
 #define RGEPHY_ANER_LPAN       0x0001  /* Link partner autoneg capable */
 
 #define RGEPHY_MII_NEXTP       0x07    /* Next page */
 #define RGEPHY_SR_JABBER               0x0001  /* Jabber */
 #define RGEPHY_SR_SPEED(X)             ((X) & RGEPHY_SR_SPEED_MASK)
 
+#define RGEPHY_LC              0x18    /* PHY LED Control Register */
+#define RGEPHY_LC_P2           0x1A    /* PHY LED Control Register, Page 2 */
+#define RGEPHY_LC_DISABLE      0x8000  /* disable leds */
+/* Led pusle strething */
+#define RGEPHY_LC_PULSE_1_3S   0x7000
+#define RGEPHY_LC_PULSE_670MS  0x6000  
+#define RGEPHY_LC_PULSE_340MS  0x5000  
+#define RGEPHY_LC_PULSE_170MS  0x4000  
+#define RGEPHY_LC_PULSE_84MS   0x3000  
+#define RGEPHY_LC_PULSE_42MS   0x2000  
+#define RGEPHY_LC_PULSE_21MS   0x1000  
+#define RGEPHY_LC_PULSE_0MS    0x0000  
+#define RGEPHY_LC_LINK         0x0008 /* Link and speed indicated by combination of leds */
+#define RGEPHY_LC_DUPLEX       0x0004
+#define RGEPHY_LC_RX           0x0002
+#define RGEPHY_LC_TX           0x0001
+
+#define RGEPHY_PS              0x1F    /* Page Select Register */
+#define RGEPHY_PS_PAGE_0       0x0000
+#define RGEPHY_PS_PAGE_1       0x0001
+#define RGEPHY_PS_PAGE_2       0x0002
+#define RGEPHY_PS_PAGE_3       0x0003
+#define RGEPHY_PS_PAGE_4       0x0004
+
 #endif /* _DEV_RGEPHY_MIIREG_H_ */
index 908e74f..efc3f7f 100644 (file)
@@ -31,7 +31,7 @@ POSSIBILITY OF SUCH DAMAGE.
 
 ***************************************************************************/
 
-/* $OpenBSD: if_em.c,v 1.297 2015/05/12 20:20:18 kettenis Exp $ */
+/* $OpenBSD: if_em.c,v 1.298 2015/06/04 18:33:41 dms Exp $ */
 /* $FreeBSD: if_em.c,v 1.46 2004/09/29 18:28:28 mlaier Exp $ */
 
 #include <dev/pci/if_em.h>
@@ -187,7 +187,10 @@ const struct pci_matchid em_devices[] = {
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_ICH10_R_BM_V },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_1 },
        { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_2 },
-       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_3 }
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_3 },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_4 },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_5 },
+       { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_EP80579_LAN_6 }
 };
 
 /*********************************************************************
@@ -298,6 +301,8 @@ em_defer_attach(struct device *self)
        pci_chipset_tag_t       pc = pa->pa_pc;
        void *gcu;
 
+       INIT_DEBUGOUT("em_defer_attach: begin");
+
        if ((gcu = em_lookup_gcu(self)) == 0) {
                printf("%s: No GCU found, defered attachment failed\n",
                    sc->sc_dv.dv_xname);
@@ -321,9 +326,9 @@ em_defer_attach(struct device *self)
 
        em_setup_interface(sc);                 
 
-       em_update_link_status(sc);              
-
        em_setup_link(&sc->hw);                 
+
+       em_update_link_status(sc);
 }
 
 /*********************************************************************
index 6a0d4ea..8556347 100644 (file)
@@ -31,7 +31,7 @@
 
 *******************************************************************************/
 
-/* $OpenBSD: if_em_hw.c,v 1.84 2015/05/12 02:33:39 jsg Exp $ */
+/* $OpenBSD: if_em_hw.c,v 1.85 2015/06/04 18:33:41 dms Exp $ */
 /*
  * if_em_hw.c Shared functions for accessing and configuring the MAC
  */
@@ -60,6 +60,8 @@
 #include <dev/pci/if_em_hw.h>
 #include <dev/pci/if_em_soc.h>
 
+#include <dev/mii/rgephyreg.h>
+
 #define STATIC
 
 static int32_t em_swfw_sync_acquire(struct em_hw *, uint16_t);
@@ -266,6 +268,9 @@ em_set_phy_type(struct em_hw *hw)
        case I350_I_PHY_ID:
                hw->phy_type = em_phy_82580;
                break;
+       case RTL8211_E_PHY_ID:
+               hw->phy_type = em_phy_rtl8211;
+               break;
        case BME1000_E_PHY_ID:
                if (hw->phy_revision == 1) {
                        hw->phy_type = em_phy_bm;
@@ -609,13 +614,19 @@ em_set_mac_type(struct em_hw *hw)
                hw->icp_xxxx_port_num = 0;
                break;
        case E1000_DEV_ID_EP80579_LAN_2:
+       case E1000_DEV_ID_EP80579_LAN_4:
                hw->mac_type = em_icp_xxxx;
                hw->icp_xxxx_port_num = 1;
                break;
        case E1000_DEV_ID_EP80579_LAN_3:
+       case E1000_DEV_ID_EP80579_LAN_5:
                hw->mac_type = em_icp_xxxx;
                hw->icp_xxxx_port_num = 2;
                break;
+       case E1000_DEV_ID_EP80579_LAN_6:
+               hw->mac_type = em_icp_xxxx;
+               hw->icp_xxxx_port_num = 3;
+               break;
        default:
                /* Should never have loaded on this device */
                return -E1000_ERR_MAC_TYPE;
@@ -707,7 +718,10 @@ em_set_media_type(struct em_hw *hw)
        case E1000_DEV_ID_EP80579_LAN_1:
        case E1000_DEV_ID_EP80579_LAN_2:
        case E1000_DEV_ID_EP80579_LAN_3:
-               hw->media_type = em_media_type_oem;
+       case E1000_DEV_ID_EP80579_LAN_4:
+       case E1000_DEV_ID_EP80579_LAN_5:
+       case E1000_DEV_ID_EP80579_LAN_6:
+               hw->media_type = em_media_type_copper;
                break;
        default:
                switch (hw->mac_type) {
@@ -2477,6 +2491,134 @@ out:
        return ret_val;
 }
 
+static int32_t
+em_copper_link_rtl8211_setup(struct em_hw *hw)
+{
+       int32_t ret_val;
+       uint16_t phy_data;
+
+       DEBUGFUNC("em_copper_link_rtl8211_setup: begin");
+
+       if (!hw) {
+               return -1;
+       }
+       /* SW Reset the PHY so all changes take effect */
+       em_phy_hw_reset(hw);
+
+       /* Enable CRS on TX. This must be set for half-duplex operation. */
+       phy_data = 0;
+
+       ret_val = em_read_phy_reg_ex(hw, RGEPHY_CR, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_CR register\n");
+               return ret_val;
+       }
+       DEBUGOUT3("RTL8211: Rx phy_id=%X addr=%X SPEC_CTRL=%X\n", hw->phy_id,
+           hw->phy_addr, phy_data);
+       phy_data |= RGEPHY_CR_ASSERT_CRS;
+
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_CR, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_CR register\n");
+               return ret_val;
+       }
+
+       phy_data = 0; /* LED Control Register 0x18 */
+       ret_val = em_read_phy_reg_ex(hw, RGEPHY_LC, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_LC register\n");
+               return ret_val;
+       }
+
+       phy_data &= 0x80FF; /* bit-15=0 disable, clear bit 8-10 */
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_LC, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_CR register\n");
+               return ret_val;
+       }
+       /* LED Control and Definition Register 0x11, PHY spec status reg */
+       phy_data = 0;
+       ret_val = em_read_phy_reg_ex(hw, RGEPHY_SR, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_SRregister\n");
+               return ret_val;
+       }
+
+       phy_data |= 0x0010; /* LED active Low */
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_SR, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_SR register\n");
+               return ret_val;
+       }
+
+       phy_data = 0;
+       ret_val = em_read_phy_reg_ex(hw, RGEPHY_SR, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_SR register\n");
+               return ret_val;
+       }
+
+       /* Switch to Page2 */
+       phy_data = RGEPHY_PS_PAGE_2;
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_PS, phy_data);
+       if (ret_val) {
+               printf("Unable to write PHY RGEPHY_PS register\n");
+               return ret_val;
+       }
+
+       phy_data = 0x0000;
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_LC_P2, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_LC_P2 register\n");
+               return ret_val;
+       }
+       usec_delay(5);
+
+
+       /* LED Configuration Control Reg for setting for 0x1A Register */
+       phy_data = 0;
+       ret_val = em_read_phy_reg_ex(hw, RGEPHY_LC_P2, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_LC_P2 register\n");
+               return ret_val;
+       }
+
+       phy_data &= 0xF000;
+       phy_data |= 0x0F24;
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_LC_P2, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_LC_P2 register\n");
+               return ret_val;
+       }
+       phy_data = 0;
+       ret_val= em_read_phy_reg_ex(hw, RGEPHY_LC_P2, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RGEPHY_LC_P2 register\n");
+               return ret_val;
+       }
+       DEBUGOUT1("RTL8211:ReadBack for check, LED_CFG->data=%X\n", phy_data);
+
+
+       /* After setting Page2, go back to Page 0 */
+       phy_data = 0;
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_PS, phy_data);
+       if (ret_val) {
+               printf("Unable to write PHY RGEPHY_PS register\n");
+               return ret_val;
+       }
+
+       /* pulse streching= 42-84ms, blink rate=84mm */
+       phy_data = 0x140 | RGEPHY_LC_PULSE_42MS | RGEPHY_LC_LINK | 
+           RGEPHY_LC_DUPLEX | RGEPHY_LC_RX;
+
+       ret_val = em_write_phy_reg_ex(hw, RGEPHY_LC, phy_data);
+       if (ret_val) {
+               printf("Unable to write RGEPHY_LC register\n");
+               return ret_val;
+       }
+       return E1000_SUCCESS;
+}
+
 /******************************************************************************
  * Setup auto-negotiation and flow control advertisements,
  * and then perform auto-negotiation.
@@ -2675,6 +2817,10 @@ em_setup_copper_link(struct em_hw *hw)
                ret_val = em_copper_link_82580_setup(hw);
                if (ret_val)
                        return ret_val;
+       } else if (hw->phy_type == em_phy_rtl8211) {
+               ret_val = em_copper_link_rtl8211_setup(hw);
+               if (ret_val)
+                       return ret_val;
        }
        if (hw->autoneg) {
                /*
@@ -3050,6 +3196,28 @@ em_phy_force_speed_duplex(struct em_hw *hw)
                /* Need to reset the PHY or these changes will be ignored */
                mii_ctrl_reg |= MII_CR_RESET;
 
+       }
+       else if (hw->phy_type == em_phy_rtl8211) {
+               ret_val = em_read_phy_reg_ex(hw, RGEPHY_CR, &phy_data);
+               if(ret_val) {
+                       printf("Unable to read RGEPHY_CR register\n"
+                           );
+                       return ret_val;
+               }
+
+               /*
+                * Clear Auto-Crossover to force MDI manually. RTL8211 requires
+                * MDI forced whenever speed are duplex are forced.
+                */
+
+               phy_data |= RGEPHY_CR_MDI_MASK;  // enable MDIX
+               ret_val = em_write_phy_reg_ex(hw, RGEPHY_CR, phy_data);
+               if(ret_val) {
+                       printf("Unable to write RGEPHY_CR register\n");
+                       return ret_val;
+               }
+               mii_ctrl_reg |= MII_CR_RESET;
+
        }
        /* Disable MDI-X support for 10/100 */
        else if (hw->phy_type == em_phy_ife) {
@@ -3206,6 +3374,25 @@ em_phy_force_speed_duplex(struct em_hw *hw)
                        if (ret_val)
                                return ret_val;
                }
+       } else if (hw->phy_type == em_phy_rtl8211) {
+               /*
+               * In addition, because of the s/w reset above, we need to enable
+               * CRX on TX.  This must be set for both full and half duplex
+               * operation.
+               */
+
+               ret_val = em_read_phy_reg_ex(hw, RGEPHY_CR, &phy_data);
+               if(ret_val) {
+                       printf("Unable to read RGEPHY_CR register\n");
+                       return ret_val;
+               }
+
+               phy_data &= ~RGEPHY_CR_ASSERT_CRS;
+               ret_val = em_write_phy_reg_ex(hw, RGEPHY_CR, phy_data);
+               if(ret_val) {
+                       printf("Unable to write RGEPHY_CR register\n");
+                       return ret_val;
+               }
        } else if (hw->phy_type == em_phy_gg82563) {
                /*
                 * The TX_CLK of the Extended PHY Specific Control Register
@@ -3779,9 +3966,9 @@ em_check_for_link(struct em_hw *hw)
                 * MAC.  Otherwise, we need to force speed/duplex on the MAC
                 * to the current PHY speed/duplex settings.
                 */
-               if (hw->mac_type >= em_82544 && hw->mac_type != em_icp_xxxx)
+               if (hw->mac_type >= em_82544 && hw->mac_type != em_icp_xxxx) {
                        em_config_collision_dist(hw);
-               else {
+               else {
                        ret_val = em_config_mac_to_phy(hw);
                        if (ret_val) {
                                DEBUGOUT("Error configuring MAC to PHY"
@@ -5266,6 +5453,8 @@ em_match_gig_phy(struct em_hw *hw)
        case em_icp_xxxx:
                if (hw->phy_id == M88E1141_E_PHY_ID)
                        match = TRUE;
+               if (hw->phy_id == RTL8211_E_PHY_ID)
+                       match = TRUE;
                break;
        default:
                DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type);
@@ -7657,6 +7846,10 @@ em_get_cable_length(struct em_hw *hw, uint16_t *min_length,
                        return -E1000_ERR_PHY;
                        break;
                }
+       } else if (hw->phy_type == em_phy_rtl8211) {
+               /* no cable length info on RTL8211, fake */
+               *min_length = 0;
+               *max_length = em_igp_cable_length_50;
        } else if (hw->phy_type == em_phy_gg82563) {
                ret_val = em_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
                    &phy_data);
@@ -8961,6 +9154,8 @@ em_check_phy_reset_block(struct em_hw *hw)
 {
        uint32_t manc = 0;
        uint32_t fwsm = 0;
+       DEBUGFUNC("em_check_phy_reset_block\n");
+
        if (IS_ICH8(hw->mac_type)) {
                fwsm = E1000_READ_REG(hw, FWSM);
                return (fwsm & E1000_FWSM_RSPCIPHY) ? E1000_SUCCESS :
index bded07a..779d205 100644 (file)
@@ -31,7 +31,7 @@
 
 *******************************************************************************/
 
-/* $OpenBSD: if_em_hw.h,v 1.64 2015/05/12 02:33:39 jsg Exp $ */
+/* $OpenBSD: if_em_hw.h,v 1.65 2015/06/04 18:33:41 dms Exp $ */
 /* $FreeBSD: if_em_hw.h,v 1.15 2005/05/26 23:32:02 tackerman Exp $ */
 
 /* if_em_hw.h
@@ -251,6 +251,7 @@ typedef enum {
     em_phy_82579,
     em_phy_i217,
     em_phy_82580,
+    em_phy_rtl8211,
     em_phy_undefined = 0xFF
 } em_phy_type;
 
@@ -596,6 +597,9 @@ int32_t em_check_phy_reset_block(struct em_hw *hw);
 #define E1000_DEV_ID_EP80579_LAN_1       0x5040
 #define E1000_DEV_ID_EP80579_LAN_2       0x5044
 #define E1000_DEV_ID_EP80579_LAN_3       0x5048
+#define E1000_DEV_ID_EP80579_LAN_4       0x5041
+#define E1000_DEV_ID_EP80579_LAN_5       0x5045
+#define E1000_DEV_ID_EP80579_LAN_6       0x5049
 
 #define NODE_ADDRESS_SIZE 6
 #define ETH_LENGTH_OF_ADDRESS 6
index ddadf55..5866bf2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: if_em_soc.h,v 1.1 2009/11/25 13:28:13 dms Exp $       */
+/*     $OpenBSD: if_em_soc.h,v 1.2 2015/06/04 18:33:41 dms Exp $       */
 
 /*
  * Copyright (c) 2009 Dariusz Swiderski <sfires@sfires.net>
@@ -26,3 +26,6 @@ void gcu_miibus_statchg(struct device *);
 
 #define GCU_MAX_ATTEMPTS       64
 #define GCU_CMD_DELAY          50 /* microseconds */
+
+#define RTL8211_E_PHY_ID  0x001CC912
+