From c2b52203b5cdedf98f0831950ceab2cb6c91bc0f Mon Sep 17 00:00:00 2001 From: dms Date: Thu, 4 Jun 2015 18:33:41 +0000 Subject: [PATCH] Add support for em(4) on Teak 3020, a Tolopai (EP80579) 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 | 27 +++++- sys/dev/pci/if_em.c | 13 ++- sys/dev/pci/if_em_hw.c | 203 +++++++++++++++++++++++++++++++++++++++- sys/dev/pci/if_em_hw.h | 6 +- sys/dev/pci/if_em_soc.h | 5 +- 5 files changed, 243 insertions(+), 11 deletions(-) diff --git a/sys/dev/mii/rgephyreg.h b/sys/dev/mii/rgephyreg.h index 6c9f8db1a51..5e3db5ddf37 100644 --- a/sys/dev/mii/rgephyreg.h +++ b/sys/dev/mii/rgephyreg.h @@ -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 . All rights reserved. @@ -104,6 +104,7 @@ #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 */ @@ -164,4 +165,28 @@ #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_ */ diff --git a/sys/dev/pci/if_em.c b/sys/dev/pci/if_em.c index 908e74ff506..efc3f7f3ad5 100644 --- a/sys/dev/pci/if_em.c +++ b/sys/dev/pci/if_em.c @@ -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 @@ -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); } /********************************************************************* diff --git a/sys/dev/pci/if_em_hw.c b/sys/dev/pci/if_em_hw.c index 6a0d4ea0d30..8556347c4e0 100644 --- a/sys/dev/pci/if_em_hw.c +++ b/sys/dev/pci/if_em_hw.c @@ -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 #include +#include + #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 : diff --git a/sys/dev/pci/if_em_hw.h b/sys/dev/pci/if_em_hw.h index bded07a53c4..779d2051dd6 100644 --- a/sys/dev/pci/if_em_hw.h +++ b/sys/dev/pci/if_em_hw.h @@ -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 diff --git a/sys/dev/pci/if_em_soc.h b/sys/dev/pci/if_em_soc.h index ddadf55130e..5866bf257ac 100644 --- a/sys/dev/pci/if_em_soc.h +++ b/sys/dev/pci/if_em_soc.h @@ -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 @@ -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 + -- 2.20.1