Hi,

Attached patch implements support for yet another Tolopai (EP80579)
based soho router. As some of you might remeber I wrote the original
support for this platform during h2k9.

In this case, the board is named Teak 3020, and not only it does
not follow intel recomedation on GCU usage, but also uses Realtek PHY!

Attached diff was tested by me on my old Axiomtek Tolopai board, and on 
Teak 3020 board by Holger Gleass.

Comments?

greets
dms
Index: if_em.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em.c,v
retrieving revision 1.297
diff -u -p -r1.297 if_em.c
--- if_em.c     12 May 2015 20:20:18 -0000      1.297
+++ if_em.c     16 May 2015 21:37:54 -0000
@@ -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: if_em_hw.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.c,v
retrieving revision 1.84
diff -u -p -r1.84 if_em_hw.c
--- if_em_hw.c  12 May 2015 02:33:39 -0000      1.84
+++ if_em_hw.c  16 May 2015 21:37:54 -0000
@@ -266,6 +266,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;
@@ -608,14 +611,26 @@ em_set_mac_type(struct em_hw *hw)
                hw->mac_type = em_icp_xxxx;
                hw->icp_xxxx_port_num = 0;
                break;
+       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_2:
                hw->mac_type = em_icp_xxxx;
                hw->icp_xxxx_port_num = 1;
                break;
+       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_3:
                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 +722,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 +2495,131 @@ 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, RTL8211_PHY_SPEC_CTRL, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_PHY_SPEC_CTRL 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 |= RTL8211_PSCR_ASSERT_CRS_ON_TX;
+
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_PHY_SPEC_CTRL, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_PHY_SPEC_CTRL register\n");
+               return ret_val;
+       }
+
+       phy_data = 0; /* LED Control Register 0x18 */
+       ret_val = em_read_phy_reg_ex(hw, RTL8211_LED_CTRL, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_LED_CTRL register\n");
+               return ret_val;
+       }
+
+       phy_data &= 0x80FF; /* bit-15=0 disable, clear bit 8-10 */
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_LED_CTRL, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_PHY_SPEC_CTRL 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, RTL8211_PHY_SPEC_STATUS, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_PHY_SPEC_STATUS register\n");
+               return ret_val;
+       }
+
+       phy_data |= 0x0010; /* LED active Low */
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_PHY_SPEC_STATUS, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_PHY_SPEC_STATUS register\n");
+               return ret_val;
+       }
+
+       phy_data = 0;
+       ret_val = em_read_phy_reg_ex(hw, RTL8211_PHY_SPEC_STATUS, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_PHY_SPEC_STATUS register\n");
+               return ret_val;
+       }
+
+       /* Switch to Page2 Set Register 31 Data= 0x0002 */
+       phy_data = 0x0002;
+       ret_val = em_write_phy_reg_ex(hw, 0x1F, phy_data);
+       if (ret_val) {
+               printf("Unable to write PHY 0x1F register\n");
+               return ret_val;
+       }
+
+       phy_data = 0x0000;
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_LED_CFG_CTRL, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_LED_CFG_CTRL 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, RTL8211_LED_CFG_CTRL, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_LED_CFG_CTRL register\n");
+               return ret_val;
+       }
+
+       phy_data &= 0xF000;
+       phy_data |= 0x0F24;
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_LED_CFG_CTRL, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_LED_CFG_CTRL register\n");
+               return ret_val;
+       }
+       phy_data = 0;
+       ret_val= em_read_phy_reg_ex(hw, RTL8211_LED_CFG_CTRL, &phy_data);
+       if (ret_val) {
+               printf("Unable to read RTL8211_LED_CFG_CTRL register\n");
+               return ret_val;
+       }
+       DEBUGOUT1("RTL8211:ReadBack for check, LED_CFG->data=%X\n", phy_data);
+
+
+       /* After setting Page2, go back to normal Set Register 31 Data=0x0000 */
+       phy_data = 0;
+       ret_val = em_write_phy_reg_ex(hw, 0x1F, phy_data);
+       if (ret_val) {
+               printf("Unable to write PHY 0x1F register\n");
+               return ret_val;
+       }
+
+       phy_data = 0x214E; /* pulse streching= 42-84ms, blink rate=84mm */
+       ret_val = em_write_phy_reg_ex(hw, RTL8211_LED_CTRL, phy_data);
+       if (ret_val) {
+               printf("Unable to write RTL8211_PHY_SPEC_CTRL register\n");
+               return ret_val;
+       }
+       return E1000_SUCCESS;
+}
+
 /******************************************************************************
  * Setup auto-negotiation and flow control advertisements,
  * and then perform auto-negotiation.
@@ -2675,6 +2818,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) {
                /*
@@ -3051,6 +3198,31 @@ em_phy_force_speed_duplex(struct em_hw *
                mii_ctrl_reg |= MII_CR_RESET;
 
        }
+       else if (hw->phy_type == em_phy_rtl8211) {
+               ret_val = em_read_phy_reg_ex(hw, RTL8211_PHY_SPEC_CTRL,
+                   &phy_data);
+               if(ret_val) {
+                       printf("Unable to read RTL8211_PHY_SPEC_CTRL register\n"
+                           );
+                       return ret_val;
+               }
+
+               /*
+                * Clear Auto-Crossover to force MDI manually. RTL8211 requires
+                * MDI forced whenever speed are duplex are forced.
+                */
+
+               phy_data |= RTL8211_PSCR_AUTO_X_MODE;  // enable MDIX
+               ret_val = em_write_phy_reg_ex(hw, RTL8211_PHY_SPEC_CTRL,
+                   phy_data);
+               if(ret_val) {
+                       printf("Unable to write RTL8211_PHY_SPEC_CTRL "
+                           "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) {
                ret_val = em_read_phy_reg(hw, IFE_PHY_MDIX_CONTROL, &phy_data);
@@ -3206,6 +3378,29 @@ em_phy_force_speed_duplex(struct em_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, RTL8211_PHY_SPEC_CTRL,
+                   &phy_data);
+               if(ret_val) {
+                       printf("Unable to read RTL8211_PHY_SPEC_CTRL register\n"
+                           );
+                       return ret_val;
+               }
+
+               phy_data &= ~RTL8211_PSCR_ASSERT_CRS_ON_TX;
+               ret_val = em_write_phy_reg_ex(hw, RTL8211_PHY_SPEC_CTRL,
+                   phy_data);
+               if(ret_val) {
+                       printf("Unable to write RTL8211_PHY_SPEC_CTRL "
+                           "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 +3974,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 +5461,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 +7854,42 @@ em_get_cable_length(struct em_hw *hw, ui
                        return -E1000_ERR_PHY;
                        break;
                }
+       } else if (hw->phy_type == em_phy_rtl8211) {
+               ret_val = em_read_phy_reg_ex(hw, RTL8211_PHY_SPEC_STATUS,
+                   &phy_data);
+               if(ret_val) {
+                       return ret_val;
+               }
+
+               cable_length = (phy_data & RTL8211_PSSR_CABLE_LENGTH)
+                   >> RTL8211_PSSR_CABLE_LENGTH_SHIFT;
+
+               /* Convert the enum value to ranged values */
+               switch (cable_length) {
+               case em_cable_length_50:
+                       *min_length = 0;
+                       *max_length = em_igp_cable_length_50;
+                       break;
+               case em_cable_length_50_80:
+                       *min_length = em_igp_cable_length_50;
+                       *max_length = em_igp_cable_length_80;
+                       break;
+               case em_cable_length_80_110:
+                       *min_length = em_igp_cable_length_80;
+                       *max_length = em_igp_cable_length_110;
+                       break;
+               case em_cable_length_110_140:
+                       *min_length = em_igp_cable_length_110;
+                       *max_length = em_igp_cable_length_140;
+                       break;
+               case em_cable_length_140:
+                       *min_length = em_igp_cable_length_140;
+                       *max_length = em_igp_cable_length_170;
+                       break;
+               default:
+                       return -E1000_ERR_PHY;
+                       break;
+               }
        } else if (hw->phy_type == em_phy_gg82563) {
                ret_val = em_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE,
                    &phy_data);
@@ -7834,6 +8067,14 @@ em_check_downshift(struct em_hw *hw)
 
                hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
                    M88E1000_PSSR_DOWNSHIFT_SHIFT;
+       } else if (hw->phy_type == em_phy_rtl8211) {
+               ret_val = em_read_phy_reg(hw, RTL8211_PHY_SPEC_STATUS,
+                   &phy_data);
+               if (ret_val)
+                       return ret_val;
+
+               hw->speed_downgraded = (phy_data & RTL8211_PSSR_DOWNSHIFT) >>
+                   RTL8211_PSSR_DOWNSHIFT_SHIFT;
        } else if (hw->phy_type == em_phy_ife) {
                /* em_phy_ife supports 10/100 speed only */
                hw->speed_downgraded = FALSE;
@@ -8961,6 +9202,8 @@ em_check_phy_reset_block(struct em_hw *h
 {
        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: if_em_hw.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_hw.h,v
retrieving revision 1.64
diff -u -p -r1.64 if_em_hw.h
--- if_em_hw.h  12 May 2015 02:33:39 -0000      1.64
+++ if_em_hw.h  16 May 2015 21:37:55 -0000
@@ -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 
 #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: if_em_soc.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/if_em_soc.h,v
retrieving revision 1.1
diff -u -p -r1.1 if_em_soc.h
--- if_em_soc.h 25 Nov 2009 13:28:13 -0000      1.1
+++ if_em_soc.h 16 May 2015 21:37:55 -0000
@@ -26,3 +26,50 @@ void gcu_miibus_statchg(struct device *)
 
 #define GCU_MAX_ATTEMPTS       64
 #define GCU_CMD_DELAY          50 /* microseconds */
+
+#define RTL8211_E_PHY_ID  0x001CC912
+
+
+/* RTL8211CL Specific Registers */
+#define RTL8211_PHY_SPEC_CTRL     0x10  /* PHY Specific Control Register */
+#define RTL8211_PHY_SPEC_STATUS   0x11  /* PHY Specific Status Register */
+#define RTL8211_INT_ENABLE        0x12  /* Interrupt Enable Register */
+#define RTL8211_INT_STATUS        0x13  /* Interrupt Status Register */
+#define RTL8211_EXT_PHY_SPEC_CTRL 0x14  /* Extended PHY Specific Control */
+#define RTL8211_RX_ERR_CNTR       0x15  /* Receive Error Counter */
+#define RTL8211_LED_CTRL          0x18  /* LED Control Reg */
+#define RTL8211_LED_CFG_CTRL      0x1A  /* LED Configuration Control Reg */
+/* RTL8211 PHY Specific Control Register */
+#define RTL8211_PSCR_JABBER_DISABLE    0x0001 /* 1=Jabber Function disabled */
+#define RTL8211_PSCR_POLARITY_REVERSAL 0x0002 /* 1=Polarity Reversal enabled */
+#define RTL8211_PSCR_SQE_TEST          0x0004 /* 1=SQE Test enabled */
+#define RTL8211_PSCR_CLK125_DISABLE    0x0010 /* 1=CLK125 low, */
+#define RTL8211_PSCR_MDI_MANUAL_MODE   0x0000  /* MDI Crossover Mode bits 6 */
+#define RTL8211_PSCR_MDIX_MANUAL_MODE  0x0020  /* Manual MDIX configuration */
+#define RTL8211_PSCR_AUTO_X_1000T      0x0040  /* 1000BASE-T */
+#define RTL8211_PSCR_AUTO_X_MODE       0x0060  /* Auto crossover enabled */
+#define RTL8211_PSCR_10BT_EXT_DIST_ENABLE 0x0080
+#define RTL8211_PSCR_MII_5BIT_ENABLE      0x0100
+#define RTL8211_PSCR_SCRAMBLER_DISABLE    0x0200 /* 1=Scrambler disable */
+#define RTL8211_PSCR_FORCE_LINK_GOOD      0x0400 /* 1=Force link good */
+#define RTL8211_PSCR_ASSERT_CRS_ON_TX     0x0800 /* 1=Assert CRS on Transmit */
+#define RTL8211_PSCR_POLARITY_REVERSAL_SHIFT    1
+#define RTL8211_PSCR_AUTO_X_MODE_SHIFT          5
+#define RTL8211_PSCR_10BT_EXT_DIST_ENABLE_SHIFT 7
+#define RTL8211_PSSR_JABBER             0x0001 /* 1=Jabber */
+#define RTL8211_PSSR_REV_POLARITY       0x0002 /* 1=Polarity reversed */
+#define RTL8211_PSSR_DOWNSHIFT          0x0020 /* 1=Downshifted */
+#define RTL8211_PSSR_MDIX               0x0040 /* 1=MDIX; 0=MDI */
+#define RTL8211_PSSR_CABLE_LENGTH       0x0380 /* 0=<50M;1=50-80M;2=80-110M; */
+#define RTL8211_PSSR_LINK               0x0400 /* 1=Link up, 0=Link down */
+#define RTL8211_PSSR_SPD_DPLX_RESOLVED  0x0800 /* 1=Speed & Duplex resolved */
+#define RTL8211_PSSR_PAGE_RCVD          0x1000 /* 1=Page received */
+#define RTL8211_PSSR_DPLX               0x2000 /* 1=Duplex 0=Half Duplex */
+#define RTL8211_PSSR_SPEED              0xC000 /* Speed, bits 14 */
+#define RTL8211_PSSR_10MBS              0x0000 /* 00=10Mbs */
+#define RTL8211_PSSR_100MBS             0x4000 /* 01=100Mbs */
+#define RTL8211_PSSR_1000MBS            0x8000 /* 10=1000Mbs */
+#define RTL8211_PSSR_REV_POLARITY_SHIFT 1
+#define RTL8211_PSSR_DOWNSHIFT_SHIFT    5
+#define RTL8211_PSSR_MDIX_SHIFT         6
+#define RTL8211_PSSR_CABLE_LENGTH_SHIFT 7
Index: pcidevs
===================================================================
RCS file: /cvs/src/sys/dev/pci/pcidevs,v
retrieving revision 1.1762
diff -u -p -r1.1762 pcidevs
--- pcidevs     11 May 2015 20:20:03 -0000      1.1762
+++ pcidevs     16 May 2015 21:37:55 -0000
@@ -4370,8 +4370,11 @@ product INTEL EP80579_LEB        0x503d  EP80579
 product INTEL EP80579_GCU      0x503e  EP80579 GCU
 product INTEL EP80579_RESERVED2        0x503f  EP80579 Reserved
 product INTEL EP80579_LAN_1    0x5040  EP80579 LAN
+product INTEL EP80579_LAN_4    0x5041  EP80579 LAN
 product INTEL EP80579_LAN_2    0x5044  EP80579 LAN
+product INTEL EP80579_LAN_5    0x5045  EP80579 LAN
 product INTEL EP80579_LAN_3    0x5048  EP80579 LAN
+product INTEL EP80579_LAN_6    0x5049  EP80579 LAN
 product INTEL 80960RD          0x5200  i960 RD
 product INTEL PRO_100_SERVER   0x5201  PRO 100 Server
 product INTEL QEMU_NVME                0x5845  QEMU NVM Express Controller

Reply via email to