summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/ethernet/intel/e1000/Makefile4
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c43
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.c406
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_hw.h35
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c212
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_oem_phy.c2449
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_oem_phy.h225
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_osdep.h14
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_param.c7
9 files changed, 3297 insertions, 98 deletions
diff --git a/drivers/net/ethernet/intel/e1000/Makefile b/drivers/net/ethernet/intel/e1000/Makefile
index 8a0f2c0ad22..880e9e53ff9 100644
--- a/drivers/net/ethernet/intel/e1000/Makefile
+++ b/drivers/net/ethernet/intel/e1000/Makefile
@@ -30,12 +30,14 @@
# Makefile for the Intel(R) PRO/1000 ethernet driver
#
+ccflags-y += -DEXTERNAL_MDIO
+
gcu-objs := gcu_main.o gcu_if.o
ifeq ($(CONFIG_E1000_EP80579),y)
obj-$(CONFIG_E1000) += gcu.o
endif
-e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o
+e1000-objs := e1000_main.o e1000_hw.o e1000_ethtool.o e1000_param.o e1000_oem_phy.o
obj-$(CONFIG_E1000) += e1000.o
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index 3103f0b6bf5..6e50ca426cc 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -29,6 +29,7 @@
/* ethtool support for e1000 */
#include "e1000.h"
+#include "e1000_oem_phy.h"
#include <asm/uaccess.h>
enum {NETDEV_STATS, E1000_STATS};
@@ -112,7 +113,8 @@ static int e1000_get_settings(struct net_device *netdev,
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
- if (hw->media_type == e1000_media_type_copper) {
+ if ((hw->media_type == e1000_media_type_copper) ||
+ (hw->media_type == e1000_media_type_oem)) {
ecmd->supported = (SUPPORTED_10baseT_Half |
SUPPORTED_10baseT_Full |
@@ -283,7 +285,9 @@ static int e1000_set_pauseparam(struct net_device *netdev,
} else
e1000_reset(adapter);
} else
- retval = ((hw->media_type == e1000_media_type_fiber) ?
+ retval = ((hw->media_type == e1000_media_type_fiber)
+ || (hw->media_type == e1000_media_type_oem
+ && !e1000_oem_phy_is_copper(&adapter->hw)) ?
e1000_setup_link(hw) : e1000_force_mac_fc(hw));
clear_bit(__E1000_RESETTING, &adapter->flags);
@@ -371,6 +375,8 @@ static void e1000_get_regs(struct net_device *netdev, struct ethtool_regs *regs,
regs_buff[22] = 0; /* phy receive errors (unavailable) */
regs_buff[23] = regs_buff[18]; /* mdix mode */
e1000_write_phy_reg(hw, IGP01E1000_PHY_PAGE_SELECT, 0x0);
+ } else if (hw->phy_type == e1000_phy_oem) {
+ e1000_oem_get_phy_regs(adapter, &regs_buff[0xd], (0xb));
} else {
e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data);
regs_buff[13] = (u32)phy_data; /* cable length */
@@ -748,7 +754,8 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
REG_SET_AND_CHECK(RCTL, before, 0xFFFFFFFF);
REG_PATTERN_TEST(RDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
- REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
+ if (adapter->hw.mac_type != e1000_icp_xxxx)
+ REG_PATTERN_TEST(TXCW, 0xC000FFFF, 0x0000FFFF);
REG_PATTERN_TEST(TDBAL, 0xFFFFFFF0, 0xFFFFFFFF);
REG_PATTERN_TEST(TIDV, 0x0000FFFF, 0x0000FFFF);
value = E1000_RAR_ENTRIES;
@@ -1264,6 +1271,9 @@ static int e1000_set_phy_loopback(struct e1000_adapter *adapter)
case e1000_82540:
case e1000_82545:
case e1000_82545_rev_3:
+ case e1000_icp_xxxx:
+ return e1000_oem_phy_loopback(adapter);
+ break;
case e1000_82546:
case e1000_82546_rev_3:
case e1000_82541:
@@ -1306,8 +1316,11 @@ static int e1000_setup_loopback_test(struct e1000_adapter *adapter)
ew32(RCTL, rctl);
return 0;
}
- } else if (hw->media_type == e1000_media_type_copper)
+ } else if (adapter->hw.media_type == e1000_media_type_copper
+ || (adapter->hw.media_type == e1000_media_type_oem
+ && e1000_oem_phy_is_copper(&adapter->hw))) {
return e1000_set_phy_loopback(adapter);
+ }
return 7;
}
@@ -1337,6 +1350,10 @@ static void e1000_loopback_cleanup(struct e1000_adapter *adapter)
}
break;
}
+
+ if (adapter->hw.media_type == e1000_media_type_oem) {
+ e1000_oem_loopback_cleanup(adapter);
+ }
}
static void e1000_create_lbtest_frame(struct sk_buff *skb,
@@ -1468,8 +1485,16 @@ static int e1000_link_test(struct e1000_adapter *adapter, u64 *data)
if (hw->autoneg) /* if auto_neg is set wait for it */
msleep(4000);
- if (!(er32(STATUS) & E1000_STATUS_LU)) {
- *data = 1;
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ int isUp = 0;
+ if (e1000_oem_phy_is_link_up(&adapter->hw, &isUp) !=
+ E1000_SUCCESS)
+ printk(KERN_WARNING "unable to determine Link Status!\n");
+ else
+ *data = !isUp;
+ } else {
+ if (!(er32(STATUS) & E1000_STATUS_LU))
+ *data = 1;
}
}
return *data;
@@ -1694,12 +1719,18 @@ static int e1000_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
return 0;
}
+
static int e1000_set_phys_id(struct net_device *netdev,
enum ethtool_phys_id_state state)
{
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ /* No LED control on ICP family of gigE controllers */
+ return 0;
+ }
+
switch (state) {
case ETHTOOL_ID_ACTIVE:
e1000_setup_led(hw);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.c b/drivers/net/ethernet/intel/e1000/e1000_hw.c
index 36ee76bf4cb..99dfec3b412 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.c
@@ -30,6 +30,8 @@
* Shared functions for accessing and configuring the MAC
*/
+#include "e1000_oem_phy.h"
+#include "e1000_hw.h"
#include "e1000.h"
static s32 e1000_check_downshift(struct e1000_hw *hw);
@@ -37,21 +39,16 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
e1000_rev_polarity *polarity);
static void e1000_clear_hw_cntrs(struct e1000_hw *hw);
static void e1000_clear_vfta(struct e1000_hw *hw);
-static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw,
- bool link_up);
static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw);
static s32 e1000_detect_gig_phy(struct e1000_hw *hw);
-static s32 e1000_get_auto_rd_done(struct e1000_hw *hw);
static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
u16 *max_length);
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);
static s32 e1000_id_led_init(struct e1000_hw *hw);
static void e1000_init_rx_addrs(struct e1000_hw *hw);
static s32 e1000_phy_igp_get_info(struct e1000_hw *hw,
struct e1000_phy_info *phy_info);
static s32 e1000_phy_m88_get_info(struct e1000_hw *hw,
struct e1000_phy_info *phy_info);
-static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active);
static s32 e1000_wait_autoneg(struct e1000_hw *hw);
static void e1000_write_reg_io(struct e1000_hw *hw, u32 offset, u32 value);
static s32 e1000_set_phy_type(struct e1000_hw *hw);
@@ -59,7 +56,7 @@ static void e1000_phy_init_script(struct e1000_hw *hw);
static s32 e1000_setup_copper_link(struct e1000_hw *hw);
static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw);
static s32 e1000_adjust_serdes_amplitude(struct e1000_hw *hw);
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw);
static s32 e1000_config_mac_to_phy(struct e1000_hw *hw);
static void e1000_raise_mdi_clk(struct e1000_hw *hw, u32 *ctrl);
static void e1000_lower_mdi_clk(struct e1000_hw *hw, u32 *ctrl);
@@ -324,6 +321,20 @@ s32 e1000_set_mac_type(struct e1000_hw *hw)
case E1000_DEV_ID_82547GI:
hw->mac_type = e1000_82547_rev_2;
break;
+ case E1000_DEV_ID_ICP_5040:
+ case E1000_DEV_ID_ICP_5041:
+ case E1000_DEV_ID_ICP_5042:
+ case E1000_DEV_ID_ICP_5043:
+ case E1000_DEV_ID_ICP_5044:
+ case E1000_DEV_ID_ICP_5045:
+ case E1000_DEV_ID_ICP_5046:
+ case E1000_DEV_ID_ICP_5047:
+ case E1000_DEV_ID_ICP_5048:
+ case E1000_DEV_ID_ICP_5049:
+ case E1000_DEV_ID_ICP_504A:
+ case E1000_DEV_ID_ICP_504B:
+ hw->mac_type = e1000_icp_xxxx;
+ break;
case E1000_DEV_ID_INTEL_CE4100_GBE:
hw->mac_type = e1000_ce4100;
break;
@@ -365,16 +376,29 @@ void e1000_set_media_type(struct e1000_hw *hw)
e_dbg("e1000_set_media_type");
- if (hw->mac_type != e1000_82543) {
+ if (hw->mac_type != e1000_82543)
/* tbi_compatibility is only valid on 82543 */
hw->tbi_compatibility_en = false;
- }
switch (hw->device_id) {
case E1000_DEV_ID_82545GM_SERDES:
case E1000_DEV_ID_82546GB_SERDES:
hw->media_type = e1000_media_type_internal_serdes;
break;
+ case E1000_DEV_ID_ICP_5040:
+ case E1000_DEV_ID_ICP_5041:
+ case E1000_DEV_ID_ICP_5042:
+ case E1000_DEV_ID_ICP_5043:
+ case E1000_DEV_ID_ICP_5044:
+ case E1000_DEV_ID_ICP_5045:
+ case E1000_DEV_ID_ICP_5046:
+ case E1000_DEV_ID_ICP_5047:
+ case E1000_DEV_ID_ICP_5048:
+ case E1000_DEV_ID_ICP_5049:
+ case E1000_DEV_ID_ICP_504A:
+ case E1000_DEV_ID_ICP_504B:
+ hw->media_type = e1000_media_type_oem;
+ break;
default:
switch (hw->mac_type) {
case e1000_82542_rev2_0:
@@ -450,6 +474,13 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
msleep(5);
}
+ if (hw->phy_type == e1000_phy_oem
+ && e1000_oem_phy_needs_reset_with_mac(hw)) {
+ ret_val = e1000_oem_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
/* Issue a global reset to the MAC. This will reset the chip's
* transmit, receive, DMA, and link units. It will not effect
* the current PCI configuration. The global reset bit is self-
@@ -513,7 +544,7 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
}
/* Disable HW ARPs on ASF enabled adapters */
- if (hw->mac_type >= e1000_82540) {
+ if (hw->mac_type >= e1000_82540 && hw->mac_type != e1000_icp_xxxx) {
manc = er32(MANC);
manc &= ~(E1000_MANC_ARP_EN);
ew32(MANC, manc);
@@ -529,6 +560,12 @@ s32 e1000_reset_hw(struct e1000_hw *hw)
ew32(LEDCTL, led_ctrl);
}
+ /* default configure the oem phy */
+ if (hw->phy_type == e1000_phy_oem
+ && e1000_oem_phy_needs_reset_with_mac(hw)) {
+ e1000_oem_phy_init_script(hw);
+ }
+
/* Clear interrupt mask to stop board from generating interrupts */
e_dbg("Masking off all interrupts\n");
ew32(IMC, 0xffffffff);
@@ -722,9 +759,18 @@ s32 e1000_setup_link(struct e1000_hw *hw)
u32 ctrl_ext;
s32 ret_val;
u16 eeprom_data;
+ u16 eeprom_control2_reg_offset = 0;
e_dbg("e1000_setup_link");
+ /* for icp_xxxx style controllers, the init control 2 and 3 are packed
+ * into a single word, with the top byte being occupied by control 2
+ */
+ eeprom_control2_reg_offset =
+ hw->mac_type != e1000_icp_xxxx
+ ? EEPROM_INIT_CONTROL2_REG
+ : EEPROM_INIT_CONTROL3_ICP_xxxx(e1000_oem_get_phy_dev_number(hw));
+
/* Read and store word 0x0F of the EEPROM. This word contains bits
* that determine the hardware's default PAUSE (flow control) mode,
* a bit that determines whether the HW defaults to enabling or
@@ -734,7 +780,7 @@ s32 e1000_setup_link(struct e1000_hw *hw)
* be initialized based on a value in the EEPROM.
*/
if (hw->fc == E1000_FC_DEFAULT) {
- ret_val = e1000_read_eeprom(hw, EEPROM_INIT_CONTROL2_REG,
+ ret_val = e1000_read_eeprom(hw, eeprom_control2_reg_offset,
1, &eeprom_data);
if (ret_val) {
e_dbg("EEPROM Read Error\n");
@@ -783,8 +829,19 @@ s32 e1000_setup_link(struct e1000_hw *hw)
}
/* Call the necessary subroutine to configure the link. */
- ret_val = (hw->media_type == e1000_media_type_copper) ?
- e1000_setup_copper_link(hw) : e1000_setup_fiber_serdes_link(hw);
+ switch (hw->media_type) {
+ case e1000_media_type_copper:
+ ret_val = e1000_setup_copper_link(hw);
+ break;
+
+ case e1000_media_type_oem:
+ ret_val = e1000_oem_setup_link(hw);
+ break;
+
+ default:
+ ret_val = e1000_setup_fiber_serdes_link(hw);
+ break;
+ }
/* Initialize the flow control address, type, and PAUSE timer
* registers to their default values. This is done even if flow
@@ -874,12 +931,12 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
* configure the two flow control enable bits in the CTRL register.
*
* The possible values of the "fc" parameter are:
- * 0: Flow control is completely disabled
- * 1: Rx flow control is enabled (we can receive pause frames, but
- * not send pause frames).
- * 2: Tx flow control is enabled (we can send pause frames but we do
- * not support receiving pause frames).
- * 3: Both Rx and TX flow control (symmetric) are enabled.
+ * 0: Flow control is completely disabled
+ * 1: Rx flow control is enabled (we can receive pause frames, but
+ * not send pause frames).
+ * 2: Tx flow control is enabled (we can send pause frames but we
+ * do not support receiving pause frames).
+ * 3: Both Rx and TX flow control (symmetric) are enabled.
*/
switch (hw->fc) {
case E1000_FC_NONE:
@@ -937,9 +994,16 @@ static s32 e1000_setup_fiber_serdes_link(struct e1000_hw *hw)
e_dbg("Looking for Link\n");
for (i = 0; i < (LINK_UP_TIMEOUT / 10); i++) {
msleep(10);
- status = er32(STATUS);
- if (status & E1000_STATUS_LU)
- break;
+ if (hw->mac_type != e1000_icp_xxxx) {
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ break;
+ } else {
+ int isUp = 0;
+ if (e1000_oem_phy_is_link_up(hw, &isUp) ==
+ E1000_SUCCESS && isUp)
+ break;
+ }
}
if (i == (LINK_UP_TIMEOUT / 10)) {
e_dbg("Never got a valid link from auto-neg!!!\n");
@@ -1343,7 +1407,7 @@ static s32 e1000_copper_link_mgp_setup(struct e1000_hw *hw)
* Setup auto-negotiation and flow control advertisements,
* and then perform auto-negotiation.
*/
-static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
+s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
{
s32 ret_val;
u16 phy_data;
@@ -1408,19 +1472,20 @@ static s32 e1000_copper_link_autoneg(struct e1000_hw *hw)
*
* Config the MAC and the PHY after link is up.
* 1) Set up the MAC to the current PHY speed/duplex
- * if we are on 82543. If we
- * are on newer silicon, we only need to configure
- * collision distance in the Transmit Control Register.
+ * if we are on 82543. If we
+ * are on newer silicon, we only need to configure
+ * collision distance in the Transmit Control Register.
* 2) Set up flow control on the MAC to that established with
- * the link partner.
+ * the link partner.
* 3) Config DSP to improve Gigabit link quality for some PHY revisions.
*/
-static s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
+s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
{
s32 ret_val;
e_dbg("e1000_copper_link_postconfig");
- if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100)) {
+ if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100) &&
+ (hw->mac_type != e1000_icp_xxxx)) {
e1000_config_collision_dist(hw);
} else {
ret_val = e1000_config_mac_to_phy(hw);
@@ -1442,6 +1507,12 @@ static s32 e1000_copper_link_postconfig(struct e1000_hw *hw)
e_dbg("Error Configuring DSP after link up\n");
return ret_val;
}
+ } else if (hw->phy_type == e1000_phy_oem) {
+ ret_val = e1000_oem_config_dsp_after_link_change(hw, true);
+ if (ret_val) {
+ e_dbg("Error Configuring OEM PHY DSP after link up\n");
+ return ret_val;
+ }
}
return E1000_SUCCESS;
@@ -1593,10 +1664,9 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
}
/* We do not allow the Phy to advertise 1000 Mb Half Duplex */
- if (hw->autoneg_advertised & ADVERTISE_1000_HALF) {
+ if (hw->autoneg_advertised & ADVERTISE_1000_HALF)
e_dbg
("Advertise 1000mb Half duplex requested, request denied!\n");
- }
/* Do we want to advertise 1000 Mb Full Duplex? */
if (hw->autoneg_advertised & ADVERTISE_1000_FULL) {
@@ -1681,7 +1751,7 @@ s32 e1000_phy_setup_autoneg(struct e1000_hw *hw)
*
* Force PHY speed and duplex settings to hw->forced_speed_duplex
*/
-static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
+s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
{
u32 ctrl;
s32 ret_val;
@@ -1689,6 +1759,7 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
u16 mii_status_reg;
u16 phy_data;
u16 i;
+ bool resetPhy = false;
e_dbg("e1000_phy_force_speed_duplex");
@@ -1776,8 +1847,17 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
mii_ctrl_reg |= MII_CR_RESET;
/* Disable MDI-X support for 10/100 */
+ } else if (hw->phy_type == e1000_phy_oem) {
+ ret_val = e1000_oem_force_mdi(hw, (int *)&resetPhy);
+ if (ret_val)
+ return ret_val;
+ if (resetPhy) {
+ ret_val = e1000_oem_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+ }
} else {
- /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
+ /* Clear Auto-Crossover to force MDI manually. IGP requires MDI
* forced whenever speed or duplex are forced.
*/
ret_val =
@@ -1833,7 +1913,8 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
msleep(100);
}
if ((i == 0) && (hw->phy_type == e1000_phy_m88)) {
- /* We didn't get link. Reset the DSP and wait again for link. */
+ /* We didn't get link. Reset the DSP and wait again
+ * for link. */
ret_val = e1000_phy_reset_dsp(hw);
if (ret_val) {
e_dbg("Error Resetting PHY DSP\n");
@@ -1878,8 +1959,9 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
if (ret_val)
return ret_val;
- /* In addition, because of the s/w reset above, we need to enable CRS on
- * TX. This must be set for both full and half duplex operation.
+ /* In addition, because of the s/w reset above, we need to
+ * enable CRS on TX. This must be set for both full and half
+ * duplex operation.
*/
ret_val =
e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
@@ -1901,6 +1983,13 @@ static s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw)
return ret_val;
}
}
+
+ if (hw->phy_type == e1000_phy_oem && resetPhy) {
+ ret_val = e1000_oem_cleanup_after_phy_reset(hw);
+ if (ret_val)
+ return ret_val;
+ }
+
return E1000_SUCCESS;
}
@@ -1946,12 +2035,19 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
u32 ctrl;
s32 ret_val;
u16 phy_data;
+ int is_FullDuplex = false;
+ int is_1000MBS = false;
+ int is_100MBS = false;
e_dbg("e1000_config_mac_to_phy");
/* 82544 or newer MAC, Auto Speed Detection takes care of
* MAC speed/duplex configuration.*/
- if ((hw->mac_type >= e1000_82544) && (hw->mac_type != e1000_ce4100))
+
+ if ((hw->mac_type >= e1000_82544)
+ && (hw->mac_type != e1000_ce4100)
+ && (hw->mac_type != e1000_icp_xxxx))
+
return E1000_SUCCESS;
/* Read the Device Control Register and set the bits to Force Speed
@@ -1979,6 +2075,41 @@ static s32 e1000_config_mac_to_phy(struct e1000_hw *hw)
e1000_config_collision_dist(hw);
break;
+ case e1000_phy_oem:
+ ret_val = e1000_oem_set_trans_gasket(hw);
+ if (ret_val)
+ return ret_val;
+ ret_val =
+ e1000_oem_phy_is_full_duplex(hw, (int *)&is_FullDuplex);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_oem_phy_is_speed_1000(hw, (int *)&is_1000MBS);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_oem_phy_is_speed_100(hw, (int *)&is_100MBS);
+ if (ret_val)
+ return ret_val;
+
+ // nru: FIXME duplication
+ /* Set up duplex in the Device Control and Transmit Control
+ * registers depending on negotiated values.
+ */
+ if (is_FullDuplex)
+ ctrl |= E1000_CTRL_FD;
+ else
+ ctrl &= ~E1000_CTRL_FD;
+
+ e1000_config_collision_dist(hw);
+
+ /* Set up speed in the Device Control register depending on
+ * negotiated values.
+ */
+ if (is_1000MBS)
+ ctrl |= E1000_CTRL_SPD_1000;
+ else if (is_100MBS)
+ ctrl |= E1000_CTRL_SPD_100;
+
+ break;
default:
/* Set up duplex in the Device Control and Transmit Control
* registers depending on negotiated values.
@@ -2105,8 +2236,15 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
if (((hw->media_type == e1000_media_type_fiber) && (hw->autoneg_failed))
|| ((hw->media_type == e1000_media_type_internal_serdes)
&& (hw->autoneg_failed))
+ || ((hw->media_type == e1000_media_type_oem)
+ && !e1000_oem_phy_is_copper(hw)
+ && (hw->autoneg_failed))
|| ((hw->media_type == e1000_media_type_copper)
+ && (!hw->autoneg))
+ || ((hw->media_type == e1000_media_type_oem)
+ && e1000_oem_phy_is_copper(hw)
&& (!hw->autoneg))) {
+
ret_val = e1000_force_mac_fc(hw);
if (ret_val) {
e_dbg("Error forcing flow control settings\n");
@@ -2119,7 +2257,10 @@ static s32 e1000_config_fc_after_link_up(struct e1000_hw *hw)
* has completed, and if so, how the PHY and link partner has
* flow control configured.
*/
- if ((hw->media_type == e1000_media_type_copper) && hw->autoneg) {
+ if ((hw->media_type == e1000_media_type_copper
+ || (hw->media_type == e1000_media_type_oem
+ && e1000_oem_phy_is_copper(hw)))
+ && hw->autoneg) {
/* Read the MII Status Register and check to see if AutoNeg
* has completed. We read this twice because this reg has
* some "sticky" (latched) bits.
@@ -2308,6 +2449,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
u32 ctrl;
u32 status;
s32 ret_val = E1000_SUCCESS;
+ int isUp;
e_dbg("e1000_check_for_serdes_link_generic");
@@ -2315,6 +2457,18 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
status = er32(STATUS);
rxcw = er32(RXCW);
+ isUp = 0;
+
+ // SDG - this is potential issue. Should not cause problems on E1000
+ // though but may cause a problem for ETH1
+ if (hw->mac_type == e1000_icp_xxxx) {
+ ret_val = e1000_oem_phy_is_link_up(hw, &isUp);
+ if (ret_val)
+ return ret_val;
+ } else {
+ isUp = status & E1000_STATUS_LU;
+ }
+
/*
* If we don't have link (auto-negotiation failed or link partner
* cannot auto-negotiate), and our link partner is not trying to
@@ -2323,7 +2477,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
* time to complete.
*/
/* (ctrl & E1000_CTRL_SWDPIN1) == 1 == have signal */
- if ((!(status & E1000_STATUS_LU)) && (!(rxcw & E1000_RXCW_C))) {
+ if ((!(isUp)) && (!(rxcw & E1000_RXCW_C))) {
if (hw->autoneg_failed == 0) {
hw->autoneg_failed = 1;
goto out;
@@ -2377,8 +2531,7 @@ static s32 e1000_check_for_serdes_link_generic(struct e1000_hw *hw)
}
if (E1000_TXCW_ANE & er32(TXCW)) {
- status = er32(STATUS);
- if (status & E1000_STATUS_LU) {
+ if (isUp) { // SDG scary change here as well
/* SYNCH bit and IV bit are sticky, so reread rxcw. */
udelay(10);
rxcw = er32(RXCW);
@@ -2433,26 +2586,33 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
* set when the optics detect a signal. On older adapters, it will be
* cleared when there is a signal. This applies to fiber media only.
*/
- if ((hw->media_type == e1000_media_type_fiber) ||
- (hw->media_type == e1000_media_type_internal_serdes)) {
+ if ((hw->media_type == e1000_media_type_fiber)
+ || (hw->media_type == e1000_media_type_internal_serdes)
+ || (hw->media_type == e1000_media_type_oem
+ && !e1000_oem_phy_is_copper(hw))) {
rxcw = er32(RXCW);
if (hw->media_type == e1000_media_type_fiber) {
signal =
(hw->mac_type >
e1000_82544) ? E1000_CTRL_SWDPIN1 : 0;
- if (status & E1000_STATUS_LU)
- hw->get_link_status = false;
+ if (hw->mac_type != e1000_icp_xxxx) {
+ if (status & E1000_STATUS_LU)
+ hw->get_link_status = false;
+ }
}
}
/* If we have a copper PHY then we only want to go out to the PHY
* registers to see if Auto-Neg has completed and/or if our link
- * status has changed. The get_link_status flag will be set if we
+ * status has changed. The get_link_status flag will be set if we
* receive a Link Status Change interrupt or we have Rx Sequence
* Errors.
*/
- if ((hw->media_type == e1000_media_type_copper) && hw->get_link_status) {
+ if ((hw->media_type == e1000_media_type_copper
+ || (hw->media_type == e1000_media_type_oem
+ && e1000_oem_phy_is_copper(hw)))
+ && hw->get_link_status) {
/* First we want to see if the MII Status Register reports
* link. If so, then we want to get the current speed/duplex
* of the PHY.
@@ -2464,6 +2624,7 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
ret_val = e1000_read_phy_reg(hw, PHY_STATUS, &phy_data);
if (ret_val)
return ret_val;
+ hw->icp_xxxx_is_link_up = (phy_data & MII_SR_LINK_STATUS) != 0;
if (phy_data & MII_SR_LINK_STATUS) {
hw->get_link_status = false;
@@ -2494,6 +2655,11 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
} else {
/* No link detected */
e1000_config_dsp_after_link_change(hw, false);
+
+ if (hw->phy_type == e1000_phy_oem)
+ e1000_oem_config_dsp_after_link_change(hw,
+ false);
+
return 0;
}
@@ -2506,6 +2672,9 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
/* optimize the dsp settings for the igp phy */
e1000_config_dsp_after_link_change(hw, true);
+ if (hw->phy_type == e1000_phy_oem)
+ e1000_oem_config_dsp_after_link_change(hw, true);
+
/* We have a M88E1000 PHY and Auto-Neg is enabled. If we
* have Si on board that is 82544 or newer, Auto
* Speed Detection takes care of MAC speed/duplex
@@ -2514,8 +2683,14 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
* speed/duplex on the MAC to the current PHY speed/duplex
* settings.
*/
+
+
+
+
if ((hw->mac_type >= e1000_82544) &&
- (hw->mac_type != e1000_ce4100))
+ (hw->mac_type != e1000_ce4100) &&
+ (hw->mac_type != e1000_icp_xxxx))
+
e1000_config_collision_dist(hw);
else {
ret_val = e1000_config_mac_to_phy(hw);
@@ -2580,7 +2755,9 @@ s32 e1000_check_for_link(struct e1000_hw *hw)
}
if ((hw->media_type == e1000_media_type_fiber) ||
- (hw->media_type == e1000_media_type_internal_serdes))
+ (hw->media_type == e1000_media_type_internal_serdes) ||
+ (hw->media_type == e1000_media_type_oem
+ && !e1000_oem_phy_is_copper(hw))) // SDG - this was a dodgy port from iegbe
e1000_check_for_serdes_link_generic(hw);
return E1000_SUCCESS;
@@ -2861,7 +3038,8 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
return -E1000_ERR_PARAM;
}
- if (hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543
+ && hw->mac_type != e1000_icp_xxxx) {
/* Set up Op-code, Phy Address, and register address in the MDI
* Control register. The MAC will take care of interfacing with the
* PHY to retrieve the desired data.
@@ -2921,7 +3099,8 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
}
*phy_data = (u16) mdic;
}
- } else {
+ } else if (hw->mac_type != e1000_icp_xxxx) {
+
/* We must first send a preamble through the MDIO pin to signal the
* beginning of an MII instruction. This is done by sending 32
* consecutive "1" bits.
@@ -2949,7 +3128,13 @@ static s32 e1000_read_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
* register address.
*/
*phy_data = e1000_shift_in_mdi_bits(hw);
+ } else {
+ int32_t ret_val =
+ e1000_oem_read_phy_reg_ex(hw, reg_addr, phy_data);
+ if (ret_val)
+ return ret_val;
}
+
return E1000_SUCCESS;
}
@@ -2996,7 +3181,8 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
return -E1000_ERR_PARAM;
}
- if (hw->mac_type > e1000_82543) {
+ if (hw->mac_type > e1000_82543 &&
+ hw->mac_type != e1000_icp_xxxx) {
/* Set up Op-code, Phy Address, register address, and data
* intended for the PHY register in the MDI Control register.
* The MAC will take care of interfacing with the PHY to send
@@ -3046,7 +3232,7 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
return -E1000_ERR_PHY;
}
}
- } else {
+ } else if (hw->mac_type != e1000_icp_xxxx) {
/* We'll need to use the SW defined pins to shift the write command
* out to the PHY. We first send a preamble to the PHY to signal the
* beginning of the MII instruction. This is done by sending 32
@@ -3066,6 +3252,11 @@ static s32 e1000_write_phy_reg_ex(struct e1000_hw *hw, u32 reg_addr,
mdic |= (u32) phy_data;
e1000_shift_out_mdi_bits(hw, mdic, 32);
+ } else {
+ int32_t ret_val =
+ e1000_oem_write_phy_reg_ex(hw, reg_addr, phy_data);
+ if (ret_val)
+ return ret_val;
}
return E1000_SUCCESS;
@@ -3081,11 +3272,21 @@ s32 e1000_phy_hw_reset(struct e1000_hw *hw)
{
u32 ctrl, ctrl_ext;
u32 led_ctrl;
+ s32 ret_val;
e_dbg("e1000_phy_hw_reset");
e_dbg("Resetting Phy...\n");
+ if (hw->mac_type == e1000_icp_xxxx) {
+ ret_val = e1000_oem_phy_hw_reset(hw);
+ if (ret_val)
+ return ret_val;
+
+ e1000_oem_phy_init_script(hw);
+ return ret_val;
+ }
+
if (hw->mac_type > e1000_82543) {
/* Read the device control register and assert the E1000_CTRL_PHY_RST
* bit. Then, take it out of reset.
@@ -3125,6 +3326,9 @@ s32 e1000_phy_hw_reset(struct e1000_hw *hw)
ew32(LEDCTL, led_ctrl);
}
+ if (hw->phy_type == e1000_phy_oem)
+ e1000_oem_phy_init_script(hw);
+
/* Wait for FW to finish PHY configuration. */
return e1000_get_phy_cfg_done(hw);
}
@@ -3145,6 +3349,7 @@ s32 e1000_phy_reset(struct e1000_hw *hw)
switch (hw->phy_type) {
case e1000_phy_igp:
+ case e1000_icp_xxxx:
ret_val = e1000_phy_hw_reset(hw);
if (ret_val)
return ret_val;
@@ -3446,7 +3651,9 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
phy_info->local_rx = e1000_1000t_rx_status_undefined;
phy_info->remote_rx = e1000_1000t_rx_status_undefined;
- if (hw->media_type != e1000_media_type_copper) {
+ if (hw->media_type != e1000_media_type_copper
+ && (hw->media_type == e1000_media_type_oem
+ && !e1000_oem_phy_is_copper(hw))) {
e_dbg("PHY info is only valid for copper media\n");
return -E1000_ERR_CONFIG;
}
@@ -3466,6 +3673,8 @@ s32 e1000_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
if (hw->phy_type == e1000_phy_igp)
return e1000_phy_igp_get_info(hw, phy_info);
+ else if (hw->phy_type == e1000_phy_oem)
+ return e1000_oem_phy_get_info(hw, phy_info);
else if ((hw->phy_type == e1000_phy_8211) ||
(hw->phy_type == e1000_phy_8201))
return E1000_SUCCESS;
@@ -3517,6 +3726,7 @@ s32 e1000_init_eeprom_params(struct e1000_hw *hw)
case e1000_82545_rev_3:
case e1000_82546:
case e1000_82546_rev_3:
+ case e1000_icp_xxxx:
eeprom->type = e1000_eeprom_microwire;
eeprom->opcode_bits = 3;
eeprom->delay_usec = 50;
@@ -3932,8 +4142,8 @@ static s32 e1000_do_read_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
- /* A check for invalid values: offset too large, too many words, and not
- * enough words.
+ /* A check for invalid values: offset too large, too many words, and
+ * not enough words.
*/
if ((offset >= eeprom->word_size)
|| (words > eeprom->word_size - offset) || (words == 0)) {
@@ -4106,8 +4316,8 @@ static s32 e1000_do_write_eeprom(struct e1000_hw *hw, u16 offset, u16 words,
if (eeprom->word_size == 0)
e1000_init_eeprom_params(hw);
- /* A check for invalid values: offset too large, too many words, and not
- * enough words.
+ /* A check for invalid values: offset too large, too many words, and
+ * not enough words.
*/
if ((offset >= eeprom->word_size)
|| (words > eeprom->word_size - offset) || (words == 0)) {
@@ -4236,14 +4446,15 @@ static s32 e1000_write_eeprom_microwire(struct e1000_hw *hw, u16 offset,
/* Send the data */
e1000_shift_out_ee_bits(hw, data[words_written], 16);
- /* Toggle the CS line. This in effect tells the EEPROM to execute
- * the previous command.
+ /* Toggle the CS line. This in effect tells the EEPROM to
+ * execute the previous command.
*/
e1000_standby_eeprom(hw);
- /* Read DO repeatedly until it is high (equal to '1'). The EEPROM will
- * signal that the command has been completed by raising the DO signal.
- * If DO does not go high in 10 milliseconds, then error out.
+ /* Read DO repeatedly until it is high (equal to '1'). The
+ * EEPROM will signal that the command has been completed by
+ * raising the DO signal. If DO does not go high in 10
+ * milliseconds, then error out.
*/
for (i = 0; i < 200; i++) {
eecd = er32(EECD);
@@ -4287,12 +4498,24 @@ s32 e1000_read_mac_addr(struct e1000_hw *hw)
{
u16 offset;
u16 eeprom_data, i;
+ uint16_t ia_base_addr = 0;
e_dbg("e1000_read_mac_addr");
+ if (hw->mac_type == e1000_icp_xxxx) {
+ struct e1000_adapter *adapter;
+ uint32_t device_number;
+
+ adapter = (struct e1000_adapter *)hw->back;
+ device_number = PCI_SLOT(adapter->pdev->devfn);
+ ia_base_addr =
+ (uint16_t) EEPROM_IA_START_ICP_xxxx(device_number);
+ }
+
for (i = 0; i < NODE_ADDRESS_SIZE; i += 2) {
offset = i >> 1;
- if (e1000_read_eeprom(hw, offset, 1, &eeprom_data) < 0) {
+ if (e1000_read_eeprom(hw, ia_base_addr + offset, 1,
+ &eeprom_data) < 0) {
e_dbg("EEPROM Read Error\n");
return -E1000_ERR_EEPROM;
}
@@ -4488,7 +4711,8 @@ static s32 e1000_id_led_init(struct e1000_hw *hw)
e_dbg("e1000_id_led_init");
- if (hw->mac_type < e1000_82540) {
+ if (hw->mac_type < e1000_82540
+ || hw->mac_type == e1000_icp_xxxx) {
/* Nothing to do */
return E1000_SUCCESS;
}
@@ -4566,6 +4790,7 @@ s32 e1000_setup_led(struct e1000_hw *hw)
case e1000_82542_rev2_1:
case e1000_82543:
case e1000_82544:
+ case e1000_icp_xxxx:
/* No setup necessary */
break;
case e1000_82541:
@@ -4618,6 +4843,7 @@ s32 e1000_cleanup_led(struct e1000_hw *hw)
case e1000_82542_rev2_1:
case e1000_82543:
case e1000_82544:
+ case e1000_icp_xxxx:
/* No cleanup necessary */
break;
case e1000_82541:
@@ -4650,6 +4876,9 @@ s32 e1000_led_on(struct e1000_hw *hw)
e_dbg("e1000_led_on");
switch (hw->mac_type) {
+ case e1000_icp_xxxx:
+ /* No LED control on ICP family of gigE controllers */
+ return E1000_SUCCESS;
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -4696,6 +4925,9 @@ s32 e1000_led_off(struct e1000_hw *hw)
e_dbg("e1000_led_off");
switch (hw->mac_type) {
+ case e1000_icp_xxxx:
+ /* No LED control on ICP family of gigE controllers */
+ return E1000_SUCCESS;
case e1000_82542_rev2_0:
case e1000_82542_rev2_1:
case e1000_82543:
@@ -4803,7 +5035,7 @@ static void e1000_clear_hw_cntrs(struct e1000_hw *hw)
temp = er32(TSCTC);
temp = er32(TSCTFC);
- if (hw->mac_type <= e1000_82544)
+ if (hw->mac_type <= e1000_82544 || hw->mac_type == e1000_icp_xxxx)
return;
temp = er32(MGTPRC);
@@ -4974,6 +5206,11 @@ void e1000_get_bus_info(struct e1000_hw *hw)
hw->bus_speed = e1000_bus_speed_unknown;
hw->bus_width = e1000_bus_width_unknown;
break;
+ case e1000_icp_xxxx:
+ hw->bus_type = e1000_bus_type_cpp;
+ hw->bus_speed = e1000_bus_speed_unknown;
+ hw->bus_width = e1000_bus_width_unknown;
+ break;
default:
status = er32(STATUS);
hw->bus_type = (status & E1000_STATUS_PCIX_MODE) ?
@@ -5138,6 +5375,11 @@ static s32 e1000_get_cable_length(struct e1000_hw *hw, u16 *min_length,
IGP01E1000_AGC_RANGE) : 0;
*max_length = e1000_igp_cable_length_table[agc_value] +
IGP01E1000_AGC_RANGE;
+ } else if (hw->phy_type == e1000_phy_oem) {
+ ret_val = e1000_oem_get_cable_length(hw,
+ min_length, max_length);
+ if (ret_val)
+ return ret_val;
}
return E1000_SUCCESS;
@@ -5207,7 +5449,10 @@ static s32 e1000_check_polarity(struct e1000_hw *hw,
e1000_rev_polarity_reversed :
e1000_rev_polarity_normal;
}
+ } else if (hw->phy_type == e1000_phy_oem) {
+ return e1000_oem_check_polarity(hw, (uint16_t *) polarity);
}
+
return E1000_SUCCESS;
}
@@ -5248,8 +5493,15 @@ static s32 e1000_check_downshift(struct e1000_hw *hw)
hw->speed_downgraded = (phy_data & M88E1000_PSSR_DOWNSHIFT) >>
M88E1000_PSSR_DOWNSHIFT_SHIFT;
+ } else if (hw->phy_type == e1000_phy_oem) {
+ ret_val = e1000_oem_phy_speed_downgraded(hw, &phy_data);
+
+ if (ret_val)
+ return ret_val;
+ hw->speed_downgraded = phy_data > 0;
}
+
return E1000_SUCCESS;
}
@@ -5259,13 +5511,13 @@ static s32 e1000_check_downshift(struct e1000_hw *hw)
* @link_up: was link up at the time this was called
*
* returns: - E1000_ERR_PHY if fail to read/write the PHY
- * E1000_SUCCESS at any other case.
+ * E1000_SUCCESS at any other case.
*
* 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
* gigabit link is achieved to improve link quality.
*/
-static s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
+s32 e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up)
{
s32 ret_val;
u16 phy_data, phy_saved_data, speed, duplex, i;
@@ -5527,9 +5779,9 @@ static s32 e1000_set_phy_mode(struct e1000_hw *hw)
* meets standards of either 10 or 10/100 or 10/100/1000 at all duplexes.
*
* returns: - E1000_ERR_PHY if fail to read/write the PHY
- * E1000_SUCCESS at any other case.
+ * E1000_SUCCESS at any other case.
*/
-static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
+s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
{
s32 ret_val;
u16 phy_data;
@@ -5560,10 +5812,10 @@ static s32 e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active)
return ret_val;
}
- /* LPLU and SmartSpeed are mutually exclusive. LPLU is used during
- * Dx states where the power conservation is most important. During
- * driver activity we should enable SmartSpeed, so performance is
- * maintained. */
+ /* LPLU and SmartSpeed are mutually exclusive. LPLU is used
+ * during Dx states where the power conservation is most
+ * important. During driver activity we should enable
+ * SmartSpeed, so performance is maintained. */
if (hw->smart_speed == e1000_smart_speed_on) {
ret_val =
e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
@@ -5805,9 +6057,9 @@ static s32 e1000_polarity_reversal_workaround(struct e1000_hw *hw)
*
* Check for EEPROM Auto Read bit done.
* returns: - E1000_ERR_RESET if fail to reset MAC
- * E1000_SUCCESS at any other case.
+ * E1000_SUCCESS at any other case.
*/
-static s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
+s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
{
e_dbg("e1000_get_auto_rd_done");
msleep(5);
@@ -5820,9 +6072,9 @@ static s32 e1000_get_auto_rd_done(struct e1000_hw *hw)
*
* Checks if the PHY configuration is done
* returns: - E1000_ERR_RESET if fail to reset MAC
- * E1000_SUCCESS at any other case.
+ * E1000_SUCCESS at any other case.
*/
-static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
+s32 e1000_get_phy_cfg_done(struct e1000_hw *hw)
{
e_dbg("e1000_get_phy_cfg_done");
msleep(10);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_hw.h b/drivers/net/ethernet/intel/e1000/e1000_hw.h
index 11578c8978d..c275be83c6d 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_hw.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_hw.h
@@ -51,6 +51,7 @@ typedef enum {
e1000_82540,
e1000_82545,
e1000_82545_rev_3,
+ e1000_icp_xxxx,
e1000_82546,
e1000_ce4100,
e1000_82546_rev_3,
@@ -75,6 +76,7 @@ typedef enum {
e1000_media_type_copper = 0,
e1000_media_type_fiber = 1,
e1000_media_type_internal_serdes = 2,
+ e1000_media_type_oem = 3,
e1000_num_media_types
} e1000_media_type;
@@ -104,6 +106,8 @@ typedef enum {
e1000_bus_type_unknown = 0,
e1000_bus_type_pci,
e1000_bus_type_pcix,
+ e1000_bus_type_pci_express,
+ e1000_bus_type_cpp,
e1000_bus_type_reserved
} e1000_bus_type;
@@ -212,6 +216,7 @@ typedef enum {
typedef enum {
e1000_phy_m88 = 0,
e1000_phy_igp,
+ e1000_phy_oem,
e1000_phy_8211,
e1000_phy_8201,
e1000_phy_undefined = 0xFF
@@ -403,11 +408,28 @@ int e1000_pcix_get_mmrbc(struct e1000_hw *hw);
/* Port I/O is only supported on 82544 and newer */
void e1000_io_write(struct e1000_hw *hw, unsigned long port, u32 value);
+
+int32_t e1000_config_dsp_after_link_change(struct e1000_hw *hw, bool link_up);
+int32_t e1000_get_auto_rd_done(struct e1000_hw *hw);
+int32_t e1000_get_phy_cfg_done(struct e1000_hw *hw);
+int32_t e1000_set_d3_lplu_state(struct e1000_hw *hw, bool active);
+
#define E1000_READ_REG_IO(a, reg) \
e1000_read_reg_io((a), E1000_##reg)
#define E1000_WRITE_REG_IO(a, reg, val) \
e1000_write_reg_io((a), E1000_##reg, val)
+/* ICP xxxx Signal Target Capability */
+#define PCI_CAP_ID_ST 0x09
+#define PCI_ST_SCID_MASK 0x000000FF
+#define PCI_ST_SCP_MASK 0x0000FF00
+#define PCI_ST_SBC_MASK 0x00FF0000
+#define PCI_ST_STYP_MASK 0xFF000000
+#define PCI_ST_SMIA_MASK 0x000000FF
+#define PCI_ST_SMACC_MASK 0x0000FF00
+#define PCI_ST_SDATA_MASK 0xFFFF0000
+#define PCI_ST_SMIA_OFFSET 0x00000004
+
/* PCI Device IDs */
#define E1000_DEV_ID_82542 0x1000
#define E1000_DEV_ID_82543GC_FIBER 0x1001
@@ -875,6 +897,8 @@ struct e1000_ffvt_entry {
#define E1000_TIPG 0x00410 /* TX Inter-packet gap -RW */
#define E1000_TBT 0x00448 /* TX Burst Timer - RW */
#define E1000_AIT 0x00458 /* Adaptive Interframe Spacing Throttle - RW */
+#define E1000_IMC1 0x008D8 /* Interrupt Mask Clear 1 - RW */
+#define E1000_IMC2 0x008F8 /* Interrupt Mask 2 Clear - WO */
#define E1000_LEDCTL 0x00E00 /* LED Control - RW */
#define E1000_EXTCNF_CTRL 0x00F00 /* Extended Configuration Control */
#define E1000_EXTCNF_SIZE 0x00F08 /* Extended Configuration Size */
@@ -1077,6 +1101,8 @@ struct e1000_ffvt_entry {
#define E1000_82542_ICS E1000_ICS
#define E1000_82542_IMS E1000_IMS
#define E1000_82542_IMC E1000_IMC
+#define E1000_82542_IMC1 E1000_IMC1
+#define E1000_82542_IMC2 E1000_IMC2
#define E1000_82542_RCTL E1000_RCTL
#define E1000_82542_RDTR 0x00108
#define E1000_82542_RDFH E1000_RDFH
@@ -1433,6 +1459,7 @@ struct e1000_hw {
bool leave_av_bit_off;
bool bad_tx_carr_stats_fd;
bool has_smbus;
+ bool icp_xxxx_is_link_up;
};
#define E1000_EEPROM_SWDPIN0 0x0001 /* SWDPIN 0 EEPROM Value */
@@ -2252,6 +2279,14 @@ struct e1000_host_command_info {
#define EEPROM_FLASH_VERSION 0x0032
#define EEPROM_CHECKSUM_REG 0x003F
+/* ICP PCI Dev ID xxxx macros to calculate word offsets for IA, IPv4 and IPv6 */
+#define EEPROM_CTRL3_APME_ICP_xxxx 0x0004
+#define EEPROM_MGMT_CONTROL_ICP_xxxx(dev_num) (((dev_num) + 1) << 4)
+#define EEPROM_INIT_CONTROL3_ICP_xxxx(dev_num) ((((dev_num) + 1) << 4) + 1)
+#define EEPROM_IA_START_ICP_xxxx(dev_num) ((((dev_num) + 1) << 4) + 2)
+#define EEPROM_IPV4_START_ICP_xxxx(dev_num) ((((dev_num) + 1) << 4) + 5)
+#define EEPROM_IPV6_START_ICP_xxxx(dev_num) ((((dev_num) + 1) << 4) + 7)
+
#define E1000_EEPROM_CFG_DONE 0x00040000 /* MNG config cycle done */
#define E1000_EEPROM_CFG_DONE_PORT_1 0x00080000 /* ...for second port */
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 1f86a70b88a..ea12cc65646 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -27,6 +27,11 @@
*******************************************************************************/
#include "e1000.h"
+#include "e1000_oem_phy.h"
+#ifdef CONFIG_E1000_EP80579
+#include "gcu_if.h"
+#endif
+
#include <net/ip6_checksum.h>
#include <linux/io.h>
#include <linux/prefetch.h>
@@ -83,6 +88,18 @@ static DEFINE_PCI_DEVICE_TABLE(e1000_pci_tbl) = {
INTEL_E1000_ETHERNET_DEVICE(0x108A),
INTEL_E1000_ETHERNET_DEVICE(0x1099),
INTEL_E1000_ETHERNET_DEVICE(0x10B5),
+ INTEL_E1000_ETHERNET_DEVICE(0x5040),
+ INTEL_E1000_ETHERNET_DEVICE(0x5041),
+ INTEL_E1000_ETHERNET_DEVICE(0x5042),
+ INTEL_E1000_ETHERNET_DEVICE(0x5043),
+ INTEL_E1000_ETHERNET_DEVICE(0x5044),
+ INTEL_E1000_ETHERNET_DEVICE(0x5045),
+ INTEL_E1000_ETHERNET_DEVICE(0x5046),
+ INTEL_E1000_ETHERNET_DEVICE(0x5047),
+ INTEL_E1000_ETHERNET_DEVICE(0x5048),
+ INTEL_E1000_ETHERNET_DEVICE(0x5049),
+ INTEL_E1000_ETHERNET_DEVICE(0x504A),
+ INTEL_E1000_ETHERNET_DEVICE(0x504B),
INTEL_E1000_ETHERNET_DEVICE(0x2E6E),
/* required last entry */
{0,}
@@ -219,6 +236,13 @@ static int debug = NETIF_MSG_DRV | NETIF_MSG_PROBE;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+#ifdef CONFIG_E1000_EP80579
+static uint8_t gcu_suspend = 0x0;
+static uint8_t gcu_resume = 0x0;
+static struct pci_dev *gcu;
+#endif
+
+
/**
* e1000_get_hw_dev - return device
* used by hardware layer to print debugging information
@@ -252,10 +276,15 @@ static int __init e1000_init_module(void)
pr_info("copybreak enabled for "
"packets <= %u bytes\n", copybreak);
}
+
return ret;
}
+#ifdef CONFIG_E1000_EP80579
+late_initcall(e1000_init_module);
+#else
module_init(e1000_init_module);
+#endif
/**
* e1000_exit_module - Driver Exit Cleanup Routine
@@ -580,6 +609,7 @@ void e1000_reset(struct e1000_adapter *adapter)
case e1000_82540:
case e1000_82541:
case e1000_82541_rev_2:
+ case e1000_icp_xxxx:
legacy_pba_adjust = true;
pba = E1000_PBA_48K;
break;
@@ -912,12 +942,13 @@ static int e1000_init_hw_struct(struct e1000_adapter *adapter,
/* Copper options */
- if (hw->media_type == e1000_media_type_copper) {
+ if (hw->media_type == e1000_media_type_copper
+ || (hw->media_type == e1000_media_type_oem
+ && e1000_oem_phy_is_copper(&adapter->hw))) {
hw->mdix = AUTO_ALL_MODES;
hw->disable_polarity_correction = false;
hw->master_slave = E1000_MASTER_SLAVE;
}
-
return 0;
}
@@ -1143,6 +1174,12 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
EEPROM_INIT_CONTROL2_REG, 1, &eeprom_data);
eeprom_apme_mask = E1000_EEPROM_82544_APM;
break;
+ case e1000_icp_xxxx:
+ e1000_read_eeprom(&adapter->hw,
+ EEPROM_INIT_CONTROL3_ICP_xxxx(adapter->bd_number),
+ 1, &eeprom_data);
+ eeprom_apme_mask = EEPROM_CTRL3_APME_ICP_xxxx;
+ break;
case e1000_82546:
case e1000_82546_rev_3:
if (er32(STATUS) & E1000_STATUS_FUNC_1){
@@ -1189,6 +1226,17 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
adapter->wol = adapter->eeprom_wol;
device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+ /* The ICP_xxxx device has multiple, duplicate interrupt
+ * registers, so disable all but the first one
+ */
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ int offset = pci_find_capability(adapter->pdev, PCI_CAP_ID_ST)
+ + PCI_ST_SMIA_OFFSET;
+ pci_write_config_dword(adapter->pdev, offset, 0x00000006);
+ E1000_WRITE_REG(&adapter->hw, IMC1, ~0UL);
+ E1000_WRITE_REG(&adapter->hw, IMC2, ~0UL);
+ }
+
/* Auto detect PHY address */
if (hw->mac_type == e1000_ce4100) {
for (i = 0; i < 32; i++) {
@@ -1206,7 +1254,28 @@ static int __devinit e1000_probe(struct pci_dev *pdev,
/* reset the hardware with the new settings */
e1000_reset(adapter);
- strcpy(netdev->name, "eth%d");
+ if (adapter->hw.mac_type != e1000_icp_xxxx) {
+ strcpy(netdev->name, "eth%d");
+ } else {
+ uint32_t dev_num;
+ dev_num = PCI_SLOT(adapter->pdev->devfn);
+
+ switch (dev_num) {
+ case ICP_XXXX_MAC_0:
+ strcpy(netdev->name,
+ CONFIG_E1000_EP80579_MAC0_BASE_NAME "%d");
+ break;
+ case ICP_XXXX_MAC_1:
+ strcpy(netdev->name,
+ CONFIG_E1000_EP80579_MAC1_BASE_NAME "%d");
+ break;
+ case ICP_XXXX_MAC_2:
+ strcpy(netdev->name,
+ CONFIG_E1000_EP80579_MAC2_BASE_NAME "%d");
+ break;
+ }
+ }
+
err = register_netdev(netdev);
if (err)
goto err_register;
@@ -1314,6 +1383,14 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter)
/* Explicitly disable IRQ since the NIC can be in any state. */
e1000_irq_disable(adapter);
+ /*
+ * for ICP_XXXX style controllers, it is necessary to keep
+ * track of the last known state of the link to determine if
+ * the link experienced a change in state when e1000_watchdog
+ * fires
+ */
+ adapter->hw.icp_xxxx_is_link_up = false;
+
spin_lock_init(&adapter->stats_lock);
mutex_init(&adapter->mutex);
@@ -1624,8 +1701,12 @@ static void e1000_configure_tx(struct e1000_adapter *adapter)
if ((hw->media_type == e1000_media_type_fiber ||
hw->media_type == e1000_media_type_internal_serdes))
tipg = DEFAULT_82543_TIPG_IPGT_FIBER;
- else
+ else if (hw->media_type != e1000_media_type_oem)
tipg = DEFAULT_82543_TIPG_IPGT_COPPER;
+ else
+ tipg = (0xFFFFFFFFUL >> (sizeof(tipg)*0x8 -
+ E1000_TIPG_IPGR1_SHIFT))
+ & e1000_oem_get_tipg(&adapter->hw);
switch (hw->mac_type) {
case e1000_82542_rev2_0:
@@ -2381,6 +2462,23 @@ bool e1000_has_link(struct e1000_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
bool link_active = false;
+ /*
+ * Test the PHY for link status on icp_xxxx MACs.
+ * If the link status is different than the last link status stored
+ * in the adapter->hw structure, then set hw->get_link_status = 1
+ */
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ int isUp = 0;
+ int32_t ret_val;
+
+ ret_val = e1000_oem_phy_is_link_up(&adapter->hw, &isUp);
+ if (ret_val != E1000_SUCCESS)
+ isUp = 0;
+
+ if (isUp != adapter->hw.icp_xxxx_is_link_up)
+ adapter->hw.get_link_status = 1;
+ }
+
/* get_link_status is set on LSC (link status) interrupt or rx
* sequence error interrupt (except on intel ce4100).
* get_link_status will stay false until the
@@ -2406,10 +2504,23 @@ bool e1000_has_link(struct e1000_adapter *adapter)
e1000_check_for_link(hw);
link_active = hw->serdes_has_link;
break;
+ case e1000_media_type_oem:
+ e1000_check_for_link(hw);
+ break;
default:
break;
}
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ int isUp = 0x0;
+
+ if (e1000_oem_phy_is_link_up(&adapter->hw, &isUp) !=
+ E1000_SUCCESS)
+ isUp = 0x0;
+
+ link_active = isUp;
+ }
+
return link_active;
}
@@ -3708,7 +3819,9 @@ void e1000_update_stats(struct e1000_adapter *adapter)
/* Tx Dropped needs to be maintained elsewhere */
/* Phy Stats */
- if (hw->media_type == e1000_media_type_copper) {
+ if (hw->media_type == e1000_media_type_copper
+ || (hw->media_type == e1000_media_type_oem
+ && e1000_oem_phy_is_copper(&adapter->hw))) {
if ((adapter->link_speed == SPEED_1000) &&
(!e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) {
phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK;
@@ -4648,7 +4761,10 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
u16 mii_reg;
unsigned long flags;
- if (hw->media_type != e1000_media_type_copper)
+ if ((adapter->hw.media_type == e1000_media_type_oem
+ && !e1000_oem_phy_is_copper(&adapter->hw))
+ || (adapter->hw.media_type != e1000_media_type_copper
+ && adapter->hw.media_type != e1000_media_type_oem))
return -EOPNOTSUPP;
switch (cmd) {
@@ -4675,7 +4791,11 @@ static int e1000_mii_ioctl(struct net_device *netdev, struct ifreq *ifr,
return -EIO;
}
spin_unlock_irqrestore(&adapter->stats_lock, flags);
- if (hw->media_type == e1000_media_type_copper) {
+ if (adapter->hw.phy_type == e1000_phy_oem) {
+ retval = e1000_oem_mii_ioctl(adapter, flags, ifr, cmd);
+ if (retval)
+ return retval;
+ } else if (hw->media_type == e1000_media_type_copper) {
switch (data->reg_num) {
case PHY_CTRL:
if (mii_reg & MII_CR_POWER_DOWN)
@@ -4897,11 +5017,14 @@ int e1000_set_spd_dplx(struct e1000_adapter *adapter, u32 spd, u8 dplx)
goto err_inval;
/* Fiber NICs only allow 1000 gbps Full duplex */
- if ((hw->media_type == e1000_media_type_fiber) &&
+ if ((hw->media_type == e1000_media_type_fiber ||
+ (adapter->hw.media_type == e1000_media_type_oem &&
+ !e1000_oem_phy_is_copper(&adapter->hw))) &&
spd != SPEED_1000 &&
dplx != DUPLEX_FULL)
goto err_inval;
+
switch (spd + dplx) {
case SPEED_10 + DUPLEX_HALF:
hw->forced_speed_duplex = e1000_10_half;
@@ -4954,9 +5077,22 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
return retval;
#endif
- status = er32(STATUS);
- if (status & E1000_STATUS_LU)
- wufc &= ~E1000_WUFC_LNKC;
+ /*
+ * ICP_XXXX style MACs do not have a link up bit in
+ * the STATUS register, query the PHY directly
+ */
+ if (adapter->hw.mac_type != e1000_icp_xxxx) {
+ status = er32(STATUS);
+ if (status & E1000_STATUS_LU)
+ wufc &= ~E1000_WUFC_LNKC;
+ } else {
+ int isUp = 0;
+ if (e1000_oem_phy_is_link_up(&adapter->hw, &isUp) !=
+ E1000_SUCCESS)
+ isUp = 0;
+ if (isUp)
+ wufc &= ~E1000_WUFC_LNKC;
+ }
if (wufc) {
e1000_setup_rctl(adapter);
@@ -4976,7 +5112,8 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
/* phy power management enable */
#define E1000_CTRL_EN_PHY_PWR_MGMT 0x00200000
ctrl |= E1000_CTRL_ADVD3WUC |
- E1000_CTRL_EN_PHY_PWR_MGMT;
+ (adapter->hw.mac_type != e1000_icp_xxxx
+ ? E1000_CTRL_EN_PHY_PWR_MGMT : 0x0);
ew32(CTRL, ctrl);
}
@@ -5014,8 +5151,11 @@ static int __e1000_shutdown(struct pci_dev *pdev, bool *enable_wake)
#ifdef CONFIG_PM
static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
{
+ struct net_device *netdev = pci_get_drvdata(pdev);
+ struct e1000_adapter *adapter = netdev_priv(netdev);
int retval;
bool wake;
+ u16 cmd_word;
retval = __e1000_shutdown(pdev, &wake);
if (retval)
@@ -5028,6 +5168,34 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state)
pci_set_power_state(pdev, PCI_D3hot);
}
+ if (adapter->hw.mac_type == e1000_icp_xxxx) {
+ /*
+ * ICP xxxx devices are not true PCI devices, in the context
+ * of power management, disabling the bus mastership is not
+ * sufficient to disable the device, it is also necessary to
+ * disable IO, Memory, and Interrupts if they are enabled.
+ */
+ pci_read_config_word(pdev, PCI_COMMAND, &cmd_word);
+
+ cmd_word &= ~PCI_COMMAND_IO;
+ cmd_word &= ~PCI_COMMAND_MEMORY;
+ cmd_word &= ~PCI_COMMAND_INTX_DISABLE;
+
+ pci_write_config_word(pdev, PCI_COMMAND, cmd_word);
+ }
+
+#ifdef CONFIG_E1000_EP80579
+ if (gcu_suspend == 0x0) {
+ if (gcu == NULL)
+ gcu =
+ pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID,
+ NULL);
+ gcu_e1000_suspend(gcu, 0x3);
+ gcu_suspend = 0x1;
+ gcu_resume = 0x0;
+ }
+#endif
+
return 0;
}
@@ -5037,6 +5205,26 @@ static int e1000_resume(struct pci_dev *pdev)
struct e1000_adapter *adapter = netdev_priv(netdev);
struct e1000_hw *hw = &adapter->hw;
u32 err;
+ u32 vdid;
+
+#ifdef CONFIG_E1000_EP80579
+ if (gcu_resume == 0x0) {
+ if (gcu == NULL) {
+ gcu =
+ pci_get_device(PCI_VENDOR_ID_INTEL, GCU_DEVID,
+ NULL);
+ pci_read_config_dword(gcu, 0x00, &vdid);
+ }
+
+ if (gcu) {
+ gcu_e1000_resume(gcu);
+ gcu_resume = 0x1;
+ gcu_suspend = 0x0;
+ } else {
+ printk(KERN_ERR "Unable to resume GCU!\n");
+ }
+ }
+#endif
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
diff --git a/drivers/net/ethernet/intel/e1000/e1000_oem_phy.c b/drivers/net/ethernet/intel/e1000/e1000_oem_phy.c
new file mode 100644
index 00000000000..92c39c90473
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/e1000_oem_phy.c
@@ -0,0 +1,2449 @@
+/*****************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+*****************************************************************************/
+/**************************************************************************
+ * @ingroup OEM_PHY_GENERAL
+ *
+ * @file oem_phy.c
+ *
+ * @description
+ * This module contains oem functions.
+ *
+ **************************************************************************/
+
+#include "e1000_oem_phy.h"
+#include "e1000.h"
+#include "e1000_hw.h"
+#include "gcu_if.h"
+/*
+ * List of functions leveraged from the base e1000 driver.
+ *
+ * Ideally, it would have been nice to keep e1000_oem_phy.c
+ * minimally dependent on the e1000. Any function taking
+ * a struct e1000_hw as a parameter can be implemented in
+ * this file. It was chosen to reuse as much code as possible
+ * to save time (isn't that always the case ;)
+ */
+extern int e1000_up(struct e1000_adapter *adapter);
+extern void e1000_down(struct e1000_adapter *adapter);
+extern void e1000_reset(struct e1000_adapter *adapter);
+extern int32_t e1000_copper_link_autoneg(struct e1000_hw *hw);
+extern int32_t e1000_phy_force_speed_duplex(struct e1000_hw *hw);
+extern int32_t e1000_copper_link_postconfig(struct e1000_hw *hw);
+extern int32_t e1000_oem_set_trans_gasket(struct e1000_hw *hw);
+
+/* forward declarations for static support functions */
+static int32_t e1000_oem_link_m88_setup(struct e1000_hw *hw);
+static int32_t e1000_oem_link_v8211_setup(struct e1000_hw *hw);
+static int32_t e1000_oem_link_v8601_setup(struct e1000_hw *hw);
+static int32_t e1000_oem_set_phy_mode(struct e1000_hw *hw);
+static int32_t e1000_oem_detect_phy(struct e1000_hw *hw);
+
+#define NON_PHY_PORT 0xFFFFFFFF
+#define SILVERTIP_BC5860
+
+/**
+ * e1000_oem_setup_link
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * Performs OEM Transceiver specific link setup as part of the
+ * global e1000_setup_link() function.
+ **/
+int32_t e1000_oem_setup_link(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ /*
+ * see e1000_setup_copper_link() as the primary example. Look at both
+ * the M88 and IGP functions that are called for ideas, possibly for
+ * power management.
+ */
+
+ int32_t ret_val;
+ uint32_t ctrl;
+ uint16_t i;
+ uint16_t phy_data;
+
+ e_dbg("%s", __func__);
+
+ if (!hw)
+ return -1;
+
+ /* AFU: add test to exit out if improper phy type
+ */
+ /* relevent parts of e1000_copper_link_preconfig */
+ ctrl = E1000_READ_REG(hw, CTRL);
+ ctrl |= E1000_CTRL_SLU;
+ ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
+ E1000_WRITE_REG(hw, CTRL, ctrl);
+
+ /* this is required for *hw init */
+ ret_val = e1000_oem_detect_phy(hw);
+ if (ret_val)
+ return ret_val;
+ ret_val = e1000_oem_set_phy_mode(hw);
+ if (ret_val)
+ return ret_val;
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val = e1000_oem_link_m88_setup(hw);
+ if (ret_val)
+ return ret_val;
+ break;
+ case VSC8211_E_PHY_ID:
+ ret_val = e1000_oem_link_v8211_setup(hw);
+ if (ret_val)
+ return ret_val;
+ break;
+ case VSC8601_E_PHY_ID:
+ ret_val = e1000_oem_link_v8601_setup(hw);
+ if (ret_val)
+ return ret_val;
+ break;
+
+ case NON_PHY_PORT:
+ hw->icp_xxxx_is_link_up = true;
+ /* Reture for skipping the latter blocks about autoneg and
+ link status checking */
+ return E1000_SUCCESS;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ if (hw->autoneg) {
+ ret_val = e1000_copper_link_autoneg(hw);
+ if (ret_val)
+ return ret_val;
+ } else {
+ e_dbg("Forcing speed and duplex\n");
+ ret_val = e1000_phy_force_speed_duplex(hw);
+ }
+
+ /*
+ * Check link status. Wait up to 100 microseconds for link to become
+ * valid.
+ */
+ for (i = 0; i < 0xa; i++) {
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_STATUS, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register PHY_STATUS\n");
+ return ret_val;
+ }
+
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_STATUS, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register PHY_STATUS\n");
+ return ret_val;
+ }
+
+ hw->icp_xxxx_is_link_up = (phy_data & MII_SR_LINK_STATUS) != 0;
+
+ if (phy_data & MII_SR_LINK_STATUS) {
+ /* Config the MAC and PHY after link is up */
+ ret_val = e1000_copper_link_postconfig(hw);
+ if (ret_val)
+ return ret_val;
+ e_dbg("Valid link established!!!\n");
+ return E1000_SUCCESS;
+ }
+ udelay(0xa);
+ }
+
+ e_dbg("Unable to establish link!!!\n");
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ e_dbg("Invalid value for hw->media_type");
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_link_m88_setup
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * lifted from e1000_copper_link_mgp_setup, pretty much
+ * copied verbatim except replace e1000_phy_reset with e1000_phy_hw_reset
+ **/
+static int32_t e1000_oem_link_m88_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data = 0;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ ret_val = e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ phy_data |= 0x00000008;
+ ret_val =
+ e1000_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+
+ /* phy_reset_disable is set in e1000_oem_set_phy_mode */
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /* Enable CRS on TX. This must be set for half-duplex operation. */
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read M88E1000_PHY_SPEC_CTRL register\n");
+ return ret_val;
+ }
+
+ phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX;
+
+ /*
+ * Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+
+ switch (hw->mdix) {
+ case 0x1:
+ phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE;
+ break;
+ case 0x2:
+ phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE;
+ break;
+ case 0x3:
+ phy_data |= M88E1000_PSCR_AUTO_X_1000T;
+ break;
+ case 0:
+ default:
+ phy_data |= M88E1000_PSCR_AUTO_X_MODE;
+ break;
+ }
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ phy_data &= ~M88E1000_PSCR_POLARITY_REVERSAL;
+
+ if (hw->disable_polarity_correction == 1)
+ phy_data |= M88E1000_PSCR_POLARITY_REVERSAL;
+
+ ret_val =
+ e1000_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL, phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write M88E1000_PHY_SPEC_CTRL register\n");
+ return ret_val;
+ }
+
+ /*
+ * Force TX_CLK in the Extended PHY Specific Control Register
+ * to 25MHz clock.
+ */
+ ret_val = e1000_oem_read_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read M88E1000_EXT_PHY_SPEC_CTRL register\n");
+ return ret_val;
+ }
+
+ /*
+ * For Truxton, it is necessary to add RGMII tx and rx
+ * timing delay though the EXT_PHY_SPEC_CTRL register
+ */
+ phy_data |= M88E1000_EPSCR_TX_TIME_CTRL;
+ phy_data |= M88E1000_EPSCR_RX_TIME_CTRL;
+
+ if (hw->phy_revision < M88E1011_I_REV_4) {
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ /* Configure Master and Slave downshift values */
+ phy_data &= ~(M88E1000_EPSCR_MASTER_DOWNSHIFT_MASK |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_MASK);
+ phy_data |= (M88E1000_EPSCR_MASTER_DOWNSHIFT_1X |
+ M88E1000_EPSCR_SLAVE_DOWNSHIFT_1X);
+ }
+ ret_val = e1000_oem_write_phy_reg_ex(hw, M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read M88E1000_EXT_PHY_SPEC_CTRL register\n");
+ return ret_val;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val) {
+ e_dbg("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_oem_link_v8211_setup
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * lifted from e1000_copper_link_mgp_setup, pretty much
+ * copied verbatim except replace e1000_phy_reset with e1000_phy_hw_reset
+ **/
+static int32_t e1000_oem_link_v8211_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /* phy_reset_disable is set in e1000_oem_set_phy_mode */
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ ret_val = e1000_oem_read_phy_reg_ex(hw, VSC8211_BYPASS_CTRL, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read VSC8211_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ if (hw->disable_polarity_correction)
+ phy_data |= VSC8211_BYPASS_POLAR_INVERS_DISABLE;
+ else
+ phy_data &= ~VSC8211_BYPASS_POLAR_INVERS_DISABLE;
+
+ e1000_oem_write_phy_reg_ex(hw, VSC8211_BYPASS_CTRL, phy_data);
+
+ if (ret_val) {
+ e_dbg("Unable to write VSC8211_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ switch (hw->mdix) {
+ default:
+ break;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val) {
+ e_dbg("Error Resetting the PHY\n");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_oem_link_v8601_setup
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * lifted from e1000_copper_link_mgp_setup, pretty much
+ * copied verbatim except replace e1000_phy_reset with e1000_phy_hw_reset
+ **/
+static int32_t e1000_oem_link_v8601_setup(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /* phy_reset_disable is set in e1000_oem_set_phy_mode */
+ if (hw->phy_reset_disable)
+ return E1000_SUCCESS;
+
+ /*
+ * Options:
+ * disable_polarity_correction = 0 (default)
+ * Automatic Correction for Reversed Cable Polarity
+ * 0 - Disabled
+ * 1 - Enabled
+ */
+ ret_val = e1000_oem_read_phy_reg_ex(hw, VSC8601_BYPASS_CTRL, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read VSC8601_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ if (hw->disable_polarity_correction)
+ phy_data |= VSC8601_BYPASS_POLAR_INVERS_DISABLE;
+ else
+ phy_data &= ~VSC8601_BYPASS_POLAR_INVERS_DISABLE;
+
+ e1000_oem_write_phy_reg_ex(hw, VSC8601_BYPASS_CTRL, phy_data);
+
+ if (ret_val) {
+ e_dbg("Unable to write VSC8601_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+
+ /* Options:
+ * MDI/MDI-X = 0 (default)
+ * 0 - Auto for all speeds
+ * 1 - MDI mode
+ * 2 - MDI-X mode
+ * 3 - Auto for 1000Base-T only (MDI-X for 10/100Base-T modes)
+ */
+ switch (hw->mdix) {
+ default:
+ break;
+ }
+
+ /* SW Reset the PHY so all changes take effect */
+ ret_val = e1000_phy_hw_reset(hw);
+ if (ret_val) {
+ e_dbg("Error Resetting the PHY\n");
+ return ret_val;
+ }
+ // SDG - this is done to setup the LED mode correctly but should really
+ // be fixed in the hardware
+ phy_data = 0x0001;
+ e1000_oem_write_phy_reg_ex(hw, 31, phy_data); // switch to extended page registers
+ // phy_data = 0x0C17; // just link
+ phy_data = 0x0410; // blink mode
+ e1000_oem_write_phy_reg_ex(hw, 17, phy_data); // enhanced led mode,
+ // no activity (done by turning off combination feature)
+ phy_data = 0x0021;
+ e1000_oem_write_phy_reg_ex(hw, 16, phy_data); // link100 and link1000
+ phy_data = 0x0000;
+ e1000_oem_write_phy_reg_ex(hw, 31, phy_data); // switch back to standard page registers
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_oem_force_mdi
+ * @hw: e1000_hw struct containing device specific information
+ * @resetPhy: returns true if after calling this function the
+ * PHY requires a reset
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * This is called from e1000_phy_force_speed_duplex, which is
+ * called from e1000_oem_setup_link.
+ **/
+int32_t e1000_oem_force_mdi(struct e1000_hw *hw, int *resetPhy)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ int32_t ret_val;
+
+ if (!hw || !resetPhy)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * a boolean to indicate if the phy needs to be reset
+ *
+ * Make note that the M88 phy is what'll be used on Truxton
+ * see e1000_phy_force_speed_duplex, which does the following for M88
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read M88E1000_PHY_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+
+ /*
+ * Clear Auto-Crossover to force MDI manually. M88E1000 requires
+ * MDI forced whenever speed are duplex are forced.
+ */
+
+ phy_data &= ~M88E1000_PSCR_AUTO_X_MODE;
+ ret_val = e1000_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write M88E1000_PHY_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+ *resetPhy = true;
+ break;
+ case VSC8211_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8211_BYPASS_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read VSC8211_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ /* disable automatic MDI and MDI-X */
+ phy_data |= VSC8211_BYPASS_AUTO_MDI_DISABLE;
+ e1000_oem_write_phy_reg_ex(hw, VSC8211_BYPASS_CTRL, phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to write VSC8211_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ *resetPhy = true;
+ break;
+ case VSC8601_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8601_BYPASS_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read VSC8601_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ /* disable automatic MDI and MDI-X */
+ phy_data |= VSC8601_BYPASS_AUTO_MDI_DISABLE;
+ e1000_oem_write_phy_reg_ex(hw, VSC8601_BYPASS_CTRL, phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to write VSC8601_BYPASS_CTRL register\n");
+ return ret_val;
+ }
+ *resetPhy = true;
+ break;
+
+ case NON_PHY_PORT:
+ *resetPhy = false;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !resetPhy)
+ return -1;
+
+ *resetPhy = false;
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_reset_dsp
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * This is called from e1000_phy_force_speed_duplex, which is
+ * called from e1000_oem_setup_link.
+ **/
+int32_t e1000_oem_phy_reset_dsp(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton.
+ *
+ * See e1000_phy_force_speed_duplex, which calls e1000_phy_reset_dsp
+ * for the M88 PHY. The code as written references registers 29 and 30,
+ * which are reserved for the M88 used on Truxton, so this will be a
+ * no-op.
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ case NON_PHY_PORT:
+ e_dbg("No DSP to reset on OEM PHY\n");
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_cleanup_after_phy_reset
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * This is called from e1000_phy_force_speed_duplex, which is
+ * called from e1000_oem_setup_link.
+ **/
+int32_t e1000_oem_cleanup_after_phy_reset(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ int32_t ret_val;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton.
+ * see e1000_phy_force_speed_duplex, which does the following for M88
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ /*
+ * Because we reset the PHY above, we need to re-force
+ * TX_CLK in the Extended PHY Specific Control Register to
+ * 25MHz clock. This value defaults back to a 2.5MHz clock
+ * when the PHY is reset.
+ */
+
+ ret_val = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read M88E1000_EXT_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+
+ phy_data |= M88E1000_EPSCR_TX_CLK_25;
+ ret_val = e1000_oem_write_phy_reg_ex(hw,
+ M88E1000_EXT_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write M88E1000_EXT_PHY_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+
+ /*
+ * 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 = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read M88E1000_PHY_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+
+ phy_data &= ~M88E1000_PSCR_ASSERT_CRS_ON_TX;
+ ret_val = e1000_oem_write_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL,
+ phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write M88E1000_PHY_SPEC_CTRL "
+ "register\n");
+ return ret_val;
+ }
+ break;
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ case NON_PHY_PORT:
+ /* do nothing */
+ break;
+
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_set_phy_mode
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * This is called from e1000_oem_setup_link which is
+ * called from e1000_setup_link.
+ **/
+static int32_t e1000_oem_set_phy_mode(struct e1000_hw *hw)
+{
+ /*
+ * it is unclear if it is necessary to set the phy mode. Right now only
+ * one MAC 82545 Rev 3 does it, but the other MACs like tola do not.
+ * Leave the functionality off for now until it is determined that
+ * Tolapai needs it as well.
+ */
+#ifdef skip_set_mode
+#undef skip_set_mode
+#endif
+
+#ifdef skip_set_mode
+ int32_t ret_val;
+ uint16_t eeprom_data;
+#endif
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * e1000_set_phy_mode specifically works for 82545 Rev 3 only,
+ * since it is a 'loner' compared to the 82545, 82546, and
+ * 82546 Rev 3, assume for now it is anomaly and don't repeat
+ * for Truxton/Haxton.
+ * Note that this is the approach taken in both the Windows and
+ * FreeBSD drivers
+ */
+
+ switch (hw->phy_id) {
+ case VSC8211_E_PHY_ID:
+ {
+ int32_t ret_val;
+ int16_t phy_data;
+ /* Set CMODE to the RGMII-CAT5 combination */
+ phy_data =
+ VSC8211_PHY_CTRL1_INTF_MODE1_RGMII |
+ VSC8211_PHY_CTRL1_TXC_SKEW_2NS |
+ VSC8211_PHY_CTRL1_RXC_SKEW_2NS |
+ VSC8211_PHY_CTRL1_RX_IDLE_CLK_ENABLE |
+ VSC8211_PHY_CTRL1_INTF_MODE2_CAT5;
+ ret_val =
+ e1000_oem_write_phy_reg_ex(hw, VSC8211_PHY_CTRL_1,
+ phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write VSC8211_PHY_CTRL_1 "
+ "register\n");
+ return ret_val;
+ }
+ break;
+ }
+ }
+
+#ifndef skip_set_mode
+ e_dbg("No need to call oem_set_phy_mode on Truxton\n");
+#else
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton.
+ *
+ * use e1000_set_phy_mode as example
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val = e1000_read_eeprom(hw,
+ EEPROM_PHY_CLASS_WORD,
+ 1, &eeprom_data);
+ if (ret_val)
+ return ret_val;
+
+ if ((eeprom_data != EEPROM_RESERVED_WORD) &&
+ (eeprom_data & EEPROM_PHY_CLASS_A)) {
+ ret_val = e1000_oem_write_phy_reg_ex(hw,
+ M88E1000_PHY_PAGE_SELECT, 0x000B);
+ if (ret_val) {
+ e_dbg("Unable to write to "
+ "M88E1000_PHY_PAGE_SELECT register "
+ "on PHY\n");
+ return ret_val;
+ }
+
+ ret_val = e1000_oem_write_phy_reg_ex(hw,
+ M88E1000_PHY_GEN_CONTROL, 0x8104);
+ if (ret_val) {
+ e_dbg("Unable to write to "
+ "M88E1000_PHY_GEN_CONTROL register"
+ "on PHY\n");
+ return ret_val;
+ }
+
+ hw->phy_reset_disable = false;
+ }
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+#endif
+
+ return E1000_SUCCESS;
+
+}
+
+/**
+ * e1000_oem_detect_phy
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Fills hw->phy_type, hw->phy_id and hw->phy_revision fields as well
+ * as verifies that the PHY identified is one that is comprehended
+ * by the driver.
+ *
+ * This borrows heavily from e1000_detect_gig_phy
+ **/
+static int32_t e1000_oem_detect_phy(struct e1000_hw *hw)
+{
+ int32_t ret_val;
+ uint16_t phy_id_high, phy_id_low;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ hw->phy_type = e1000_phy_oem;
+
+ {
+ struct e1000_adapter *adapter;
+ uint32_t dev_num;
+ adapter = (struct e1000_adapter *)hw->back;
+ dev_num = PCI_SLOT(adapter->pdev->devfn);
+ switch (dev_num) {
+#ifndef CONFIG_E1000_EP80579_PHY0
+ case ICP_XXXX_MAC_0:
+ hw->phy_id = NON_PHY_PORT;
+ return E1000_SUCCESS;
+#endif
+#ifndef CONFIG_E1000_EP80579_PHY1
+ case ICP_XXXX_MAC_1:
+ hw->phy_id = NON_PHY_PORT;
+ return E1000_SUCCESS;
+#endif
+#ifndef CONFIG_E1000_EP80579_PHY2
+ case ICP_XXXX_MAC_2:
+ hw->phy_id = NON_PHY_PORT;
+ return E1000_SUCCESS;
+#endif
+ }
+ }
+
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_ID1, &phy_id_high);
+ if (ret_val) {
+ e_dbg("Unable to read PHY register PHY_ID1\n");
+ return ret_val;
+ }
+
+ udelay(0x14);
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_ID2, &phy_id_low);
+ if (ret_val) {
+ e_dbg("Unable to read PHY register PHY_ID2\n");
+ return ret_val;
+ }
+ hw->phy_id = (uint32_t) ((phy_id_high << 0x10) +
+ (phy_id_low & PHY_REVISION_MASK));
+ hw->phy_revision = (uint32_t) phy_id_low & ~PHY_REVISION_MASK;
+
+ return E1000_SUCCESS;
+}
+
+/**
+ * e1000_oem_get_tipg
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns the value of the Inter Packet Gap (IPG) Transmit Time (IPGT) in the
+ * Transmit IPG register appropriate for the given PHY. This field is only 10
+ * bits wide.
+ *
+ * In the original e1000 code, only the IPGT field varied between media types.
+ * If the OEM phy requires setting IPG Receive Time 1 & 2 Registers, it would
+ * be required to modify the e1000_config_tx() function to accomdate the change
+ *
+ **/
+uint32_t e1000_oem_get_tipg(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint32_t phy_num;
+
+ if (!hw)
+ return DEFAULT_ICP_XXXX_TIPG_IPGT;
+
+ e_dbg("%s", __func__);
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ case NON_PHY_PORT:
+ phy_num = DEFAULT_ICP_XXXX_TIPG_IPGT;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return DEFAULT_ICP_XXXX_TIPG_IPGT;
+ }
+
+ return phy_num;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ /* return the default value required by ICP_xxxx style MACS */
+ e_dbg("Invalid value for transceiver type, return default"
+ " TIPG.IPGT value\n");
+ return DEFAULT_ICP_XXXX_TIPG_IPGT;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_is_copper
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Test for media type within the e1000 driver is common, so this is a simple
+ * test for copper PHYs. The ICP_XXXX family of controllers initially only
+ * supported copper interconnects (no TBI (ten bit interface) for Fiber
+ * existed). If future revs support either Fiber or an internal SERDES, it
+ * may become necessary to evaluate where this function is used to go beyond
+ * determining whether or not media type is just copper.
+ *
+ **/
+int e1000_oem_phy_is_copper(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ int isCopper = true;
+
+ if (!hw)
+ return isCopper;
+
+ e_dbg("%s", __func__);
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ isCopper = true;
+ break;
+ case NON_PHY_PORT:
+ isCopper = false;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return isCopper;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ /*
+ * caught between returning true or false. True allows it to
+ * be entered into && statements w/o ill effect, but false
+ * would make more sense
+ */
+ e_dbg("Invalid value for transceiver type, return false\n");
+ return false;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_get_phy_dev_number
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * For ICP_XXXX family of devices, there are 3 MACs, each of which may
+ * have a different PHY (and indeed a different media interface). This
+ * function is used to indicate which of the MAC/PHY pairs we are interested
+ * in.
+ *
+ **/
+uint32_t e1000_oem_get_phy_dev_number(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ /*
+ * for ICP_XXXX family of devices, the three network interfaces are
+ * differentiated by their PCI device number, where the three share
+ * the same PCI bus
+ */
+ struct e1000_adapter *adapter;
+ uint32_t device_number;
+
+ if (!hw)
+ return 0;
+
+ e_dbg("%s", __func__);
+
+ adapter = (struct e1000_adapter *)hw->back;
+ device_number = PCI_SLOT(adapter->pdev->devfn);
+
+ switch (device_number) {
+ case ICP_XXXX_MAC_0:
+ hw->phy_addr = 0x00;
+ break;
+ case ICP_XXXX_MAC_1:
+ hw->phy_addr = 0x01;
+ break;
+ case ICP_XXXX_MAC_2:
+ hw->phy_addr = 0x02;
+ break;
+ default:
+ hw->phy_addr = 0x00;
+ }
+ return hw->phy_addr;
+
+#else /* ifdef EXTERNAL_MDIO */
+ e_dbg("Invalid value for transceiver type, return 0\n");
+ return 0;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_mii_ioctl
+ * @adapter: e1000_hw struct containing device specific information
+ * @flags: The saved adapter->stats_lock flags from the initiating spinlock
+ * @ifr: interface request structure for socket ioctls
+ * @cmd: the original IOCTL command that instigated the call chain.
+ *
+ * This function abstracts out the code necessary to service the
+ * SIOCSMIIREG case within the e1000_mii_ioctl() for oem PHYs.
+ * e1000_mii_ioctl() was implemented for copper phy's only and this
+ * function will only be called if e1000_oem_phy_is_copper() returns true for
+ * a given MAC. Note that e1000_mii_ioctl() has a compile flag
+ * and exists only if SIOCGMIIPHY is defined.
+ *
+ * NOTE: a spinlock is in effect for the duration of this call. It is
+ * imperative that a negative value be returned on any error, so
+ * the spinlock can be released properly.
+ *
+ **/
+int
+e1000_oem_mii_ioctl(struct e1000_adapter *adapter, unsigned long flags,
+ struct ifreq *ifr, int cmd)
+{
+#ifdef EXTERNAL_MDIO
+
+ struct mii_ioctl_data *data = if_mii(ifr);
+ uint16_t mii_reg = data->val_in;
+ uint32_t spd;
+ uint8_t dplx;
+ struct e1000_hw *hw;
+ int retval;
+
+ if (!adapter || !ifr)
+ return -1;
+
+ hw = &adapter->hw;
+
+ e_dbg("%s", __func__);
+
+ switch (data->reg_num) {
+ case PHY_CTRL:
+ if (mii_reg & MII_CR_POWER_DOWN)
+ break;
+
+ if (mii_reg & MII_CR_AUTO_NEG_EN) {
+ adapter->hw.autoneg = 1;
+ adapter->hw.autoneg_advertised =
+ ICP_XXXX_AUTONEG_ADV_DEFAULT;
+ } else {
+ if (mii_reg & 0x40)
+ spd = SPEED_1000;
+ else if (mii_reg & 0x2000)
+ spd = SPEED_100;
+ else
+ spd = SPEED_10;
+
+ dplx = (mii_reg & 0x100) ? FULL_DUPLEX : HALF_DUPLEX;
+ retval = e1000_set_spd_dplx(adapter, spd, dplx);
+ if (retval)
+ return retval;
+
+ }
+ if (netif_running(adapter->netdev)) {
+ e1000_down(adapter);
+ e1000_up(adapter);
+ } else {
+ e1000_reset(adapter);
+ }
+ break;
+ case M88E1000_PHY_SPEC_CTRL:
+ case M88E1000_EXT_PHY_SPEC_CTRL:
+ retval = e1000_phy_reset(&adapter->hw);
+ if (retval) {
+ e_dbg("Error resetting the PHY\n");
+ return -EIO;
+ }
+ break;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -EOPNOTSUPP;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_get_phy_regs
+ * @adapter e1000_adapter struct containing device specific information
+ * @data unsigned integer array of size data_len
+ * @data_len number of elements in data
+ *
+ * This is called by e1000_get_regs() in response to an ethtool request
+ * to return the data of the controller. Most of the data returned is from
+ * the MAC, but some data comes from the PHY, thus from this f().
+ *
+ * Note: The call to e1000_get_regs() assumed an array of 24 elements
+ * where the last 11 are passed to this function. If the array
+ * that is passed to the calling function has its size or element
+ * defintions changed, this function becomes broken.
+ *
+ **/
+void e1000_oem_get_phy_regs(struct e1000_adapter *adapter, uint32_t *data,
+ uint32_t data_len)
+{
+ struct e1000_hw *hw;
+#define EXPECTED_ARRAY_LEN 11
+ uint32_t corrected_len;
+
+ if (!adapter || !data)
+ return;
+
+ hw = &adapter->hw;
+
+ e_dbg("%s", __func__);
+
+ /* This f(n) expects to have EXPECTED_ARRAY_LEN elements to initialize.
+ * Use the corrected_length variable to make sure we don't exceed that
+ * length
+ */
+ corrected_len = data_len > EXPECTED_ARRAY_LEN
+ ? EXPECTED_ARRAY_LEN : data_len;
+ memset(data, 0, corrected_len * sizeof(uint32_t));
+
+#ifdef EXTERNAL_MDIO
+
+ /*
+ * Fill data[] with...
+ *
+ * [0] = cable length
+ * [1] = cable length
+ * [2] = cable length
+ * [3] = cable length
+ * [4] = extended 10bt distance
+ * [5] = cable polarity
+ * [6] = cable polarity
+ * [7] = polarity correction enabled
+ * [8] = undefined
+ * [9] = phy receive errors
+ * [10] = mdix mode
+ */
+ switch (adapter->hw.phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ if (corrected_len > 0)
+ e1000_oem_read_phy_reg_ex(&adapter->hw,
+ M88E1000_PHY_SPEC_STATUS,
+ (uint16_t *) &data[0]);
+
+ if (corrected_len > 0x1)
+ data[0x1] = 0x0;
+ /* Dummy (to align w/ IGP phy reg dump) */
+
+ if (corrected_len > 0x2)
+ data[0x2] = 0x0;
+ /* Dummy (to align w/ IGP phy reg dump) */
+
+ if (corrected_len > 0x3)
+ data[0x3] = 0x0;
+ /* Dummy (to align w/ IGP phy reg dump) */
+
+ if (corrected_len > 0x4)
+ e1000_oem_read_phy_reg_ex(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL,
+ (uint16_t *) &data[0x4]);
+
+ if (corrected_len > 0x5)
+ data[0x5] = data[0x0];
+
+ if (corrected_len > 0x6)
+ data[0x6] = 0x0;
+ /* Dummy (to align w/ IGP phy reg dump) */
+
+ if (corrected_len > 0x7)
+ data[0x7] = data[0x4];
+
+ /* phy receive errors */
+ if (corrected_len > 0x9)
+ data[0x9] = adapter->phy_stats.receive_errors;
+
+ if (corrected_len > 0xa)
+ data[0xa] = data[0x0];
+
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return;
+ }
+#endif /* ifdef EXTERNAL_MDIO */
+
+#undef EXPECTED_ARRAY_LEN
+ return;
+}
+
+/**
+ * e1000_oem_phy_loopback
+ * @adapter e1000_adapter struct containing device specific information
+ *
+ * This is called from e1000_set_phy_loopback in response from call from
+ * ethtool to place the PHY into loopback mode.
+ **/
+int e1000_oem_phy_loopback(struct e1000_adapter *adapter)
+{
+#ifdef EXTERNAL_MDIO
+
+ int ret_val;
+ uint32_t ctrl_reg = 0;
+ struct e1000_hw *hw;
+
+ if (!adapter)
+ return -1;
+
+ hw = &adapter->hw;
+ e_dbg("%s", __func__);
+
+ /*
+ * This borrows liberally from e1000_integrated_phy_loopback().
+ * e1000_nonintegrated_phy_loopback() was also a point of reference
+ * since it was similar. The biggest difference between the two
+ * was that nonintegrated called e1000_phy_reset_clk_and_crs(),
+ * hopefully this won't matter as CRS required for half-duplex
+ * operation and this is set to full duplex.
+ *
+ * Make note that the M88 phy is what'll be used on Truxton
+ * Loopback configuration is the same for each of the supported PHYs.
+ */
+ switch (adapter->hw.phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+
+ adapter->hw.autoneg = false;
+
+ /* turn off Auto-MDI/MDIX */
+ /*ret_val = e1000_oem_write_phy_reg_ex(&adapter->hw,
+ M88E1000_PHY_SPEC_CTRL, 0x0808);
+ if(ret_val)
+ {
+ e_dbg("Unable to write to register M88E1000_PHY_SPEC_CTRL\n");
+ return ret_val;
+ }
+ */
+ /* reset to update Auto-MDI/MDIX */
+ /* ret_val = e1000_oem_write_phy_reg_ex(&adapter->hw,
+ PHY_CTRL, 0x9140);
+ if(ret_val)
+ {
+ e_dbg("Unable to write to register PHY__CTRL\n");
+ return ret_val;
+ }
+ */
+ /* autoneg off */
+ /*ret_val = e1000_oem_write_phy_reg_ex(&adapter->hw,
+ PHY_CTRL, 0x8140); */
+ ret_val =
+ e1000_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, 0xa100);
+ if (ret_val) {
+ e_dbg("Unable to write to register PHY_CTRL\n");
+ return ret_val;
+ }
+
+ /* force 1000, set loopback */
+ /*ret_val =
+ e1000_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, 0x4140); */
+ ret_val =
+ e1000_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL, 0x6100);
+ if (ret_val) {
+ e_dbg("Unable to write to register PHY_CTRL\n");
+ return ret_val;
+ }
+
+ ctrl_reg = E1000_READ_REG(&adapter->hw, CTRL);
+ ctrl_reg &= ~E1000_CTRL_SPD_SEL; /* Clear the speed sel bits */
+ ctrl_reg |= (E1000_CTRL_FRCSPD /* Set the Force Speed Bit */
+ | E1000_CTRL_FRCDPX /* Set the Force Duplex Bit */
+ | E1000_CTRL_SPD_100 /* Force Speed to 1000 */
+ | E1000_CTRL_FD); /* Force Duplex to FULL */
+ /* | E1000_CTRL_ILOS); *//* Invert Loss of Signal */
+
+ E1000_WRITE_REG(&adapter->hw, CTRL, ctrl_reg);
+
+ /*
+ * Write out to PHY registers 29 and 30 to disable the Receiver.
+ * This directly lifted from e1000_phy_disable_receiver().
+ *
+ * The code is currently commented out as for the M88 used in
+ * Truxton, registers 29 and 30 are unutilized. Leave in, just
+ * in case we are on the receiving end of an 'undocumented'
+ * feature
+ */
+ /*
+ * e1000_oem_write_phy_reg_ex(&adapter->hw, 29, 0x001F);
+ * e1000_oem_write_phy_reg_ex(&adapter->hw, 30, 0x8FFC);
+ * e1000_oem_write_phy_reg_ex(&adapter->hw, 29, 0x001A);
+ * e1000_oem_write_phy_reg_ex(&adapter->hw, 30, 0x8FF0);
+ */
+
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return 0;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+
+}
+
+/**
+ * e1000_oem_loopback_cleanup
+ * @adapter e1000_adapter struct containing device specific information
+ *
+ * This is called from e1000_loopback_cleanup in response from call from
+ * ethtool to place the PHY out of loopback mode. This handles the OEM
+ * specific part of loopback cleanup.
+ **/
+void e1000_oem_loopback_cleanup(struct e1000_adapter *adapter)
+{
+#ifdef EXTERNAL_MDIO
+
+ /*
+ * This borrows liberally from e1000_loopback_cleanup().
+ * making note that the M88 phy is what'll be used on Truxton
+ *
+ * Loopback cleanup is the same for all supported PHYs.
+ */
+ int32_t ret_val;
+ uint16_t phy_reg;
+ struct e1000_hw *hw;
+
+ if (!adapter)
+ return;
+ hw = &adapter->hw;
+ e_dbg("%s", __func__);
+
+ switch (adapter->hw.phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ default:
+ adapter->hw.autoneg = true;
+
+ ret_val = e1000_oem_read_phy_reg_ex(&adapter->hw, PHY_CTRL,
+ &phy_reg);
+ if (ret_val) {
+ e_dbg("Unable to read to register PHY_CTRL\n");
+ return;
+ }
+
+ if (phy_reg & MII_CR_LOOPBACK) {
+ phy_reg &= ~MII_CR_LOOPBACK;
+
+ ret_val =
+ e1000_oem_write_phy_reg_ex(&adapter->hw, PHY_CTRL,
+ phy_reg);
+ if (ret_val) {
+ e_dbg
+ ("Unable to write to register PHY_CTRL\n");
+ return;
+ }
+
+ e1000_phy_reset(&adapter->hw);
+ }
+ }
+
+#endif /* ifdef EXTERNAL_MDIO */
+ return;
+
+}
+
+/**
+ * e1000_oem_phy_speed_downgraded
+ * @hw e1000_hw struct containing device specific information
+ * @isDowngraded returns with value > 0 if the link belonging to hw
+ * has been downshifted
+ *
+ * Called by e1000_check_downshift(), checks the PHY to see if it running
+ * at as speed slower than its maximum.
+ **/
+uint32_t
+e1000_oem_phy_speed_downgraded(struct e1000_hw *hw, uint16_t *isDowngraded)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint32_t ret_val;
+ uint16_t phy_data;
+
+ if (!hw || !isDowngraded)
+ return 1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * borrow liberally from E1000_check_downshift e1000_phy_m88 case.
+ * Make note that the M88 phy is what'll be used on Truxton
+ */
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+
+ *isDowngraded = (phy_data & M88E1000_PSSR_DOWNSHIFT)
+ >> M88E1000_PSSR_DOWNSHIFT_SHIFT;
+
+ break;
+
+ case VSC8211_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw, VSC8211_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8211_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *isDowngraded = (phy_data & VSC8211_AUX_SPEED_MASK) !=
+ VSC8211_AUX_SPEED_IS_1000;
+ break;
+
+ case VSC8601_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw, VSC8601_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8601_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *isDowngraded = (phy_data & VSC8601_AUX_SPEED_MASK) !=
+ VSC8601_AUX_SPEED_IS_1000;
+ break;
+
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return 1;
+ }
+
+ return 0;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !isDowngraded)
+ return 1;
+
+ *isDowngraded = 0;
+ return 0;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_check_polarity
+ * @hw e1000_hw struct containing device specific information
+ * @isDowngraded returns with value > 0 if the link belonging to hw
+ * has its polarity shifted.
+ *
+ * Called by e1000_check_downshift(), checks the PHY to see if it running
+ * at as speed slower than its maximum.
+ **/
+int32_t e1000_oem_check_polarity(struct e1000_hw *hw, uint16_t *polarity)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (!hw || !polarity)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * borrow liberally from e1000_check_polarity.
+ * Make note that the M88 phy is what'll be used on Truxton
+ */
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ /* return the Polarity bit in the Status register. */
+ ret_val = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+
+ *polarity = (phy_data & M88E1000_PSSR_REV_POLARITY)
+ >> M88E1000_PSSR_REV_POLARITY_SHIFT;
+
+ break;
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ e_dbg("check polarity is not supported by VSC8XXX\n");
+ return -E1000_ERR_PHY_TYPE;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+ return 0;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !polarity)
+ return -1;
+
+ *polarity = 0;
+ return -1;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_is_full_duplex
+ * @hw e1000_hw struct containing device specific information
+ * @isFD a boolean returning true if phy is full duplex
+ *
+ * This is called as part of e1000_config_mac_to_phy() to align
+ * the MAC with the PHY. It turns out on ICP_XXXX, this is not
+ * done automagically.
+ **/
+int32_t e1000_oem_phy_is_full_duplex(struct e1000_hw *hw, int *isFD)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ int32_t ret_val;
+
+ if (!hw || !isFD)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton
+ * see e1000_config_mac_to_phy
+ */
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+ *isFD = (phy_data & M88E1000_PSSR_DPLX) != 0;
+
+ break;
+ case VSC8211_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8211_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8211_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *isFD =
+ (phy_data & VSC8211_AUX_FDX_MASK) ==
+ VSC8211_AUX_FDX_IS_FULL;
+ break;
+ case VSC8601_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8601_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8601_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *isFD =
+ (phy_data & VSC8601_AUX_FDX_MASK) ==
+ VSC8601_AUX_FDX_IS_FULL;
+ break;
+
+ case NON_PHY_PORT:
+ *isFD = true;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !isFD)
+ return -1;
+ *isFD = false;
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_is_speed_1000
+ * @hw e1000_hw struct containing device specific information
+ * @is1000 a boolean returning true if phy is running at 1000
+ *
+ * This is called as part of e1000_config_mac_to_phy() to align
+ * the MAC with the PHY. It turns out on ICP_XXXX, this is not
+ * done automagically.
+ **/
+int32_t e1000_oem_phy_is_speed_1000(struct e1000_hw *hw, int *is1000)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ int32_t ret_val;
+
+ if (!hw || !is1000)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton.
+ * see e1000_config_mac_to_phy
+ */
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+ *is1000 =
+ (phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS;
+ break;
+ case VSC8211_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8211_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8211_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *is1000 = (phy_data & VSC8211_AUX_SPEED_MASK) ==
+ VSC8211_AUX_SPEED_IS_1000;
+ break;
+ case VSC8601_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8601_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8601_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *is1000 = (phy_data & VSC8601_AUX_SPEED_MASK) ==
+ VSC8601_AUX_SPEED_IS_1000;
+ break;
+
+ case NON_PHY_PORT:
+ *is1000 = true;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !is1000)
+ return -1;
+ *is1000 = false;
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_is_speed_100
+ * @hw e1000_hw struct containing device specific information
+ * @is100 a boolean returning true if phy is running at 100
+ *
+ * This is called as part of e1000_config_mac_to_phy() to align
+ * the MAC with the PHY. It turns out on ICP_XXXX, this is not
+ * done automagically.
+ **/
+int32_t e1000_oem_phy_is_speed_100(struct e1000_hw *hw, int *is100)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ int32_t ret_val;
+
+ if (!hw || !is100)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton
+ * see e1000_config_mac_to_phy
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+ *is100 =
+ (phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_100MBS;
+ break;
+ case VSC8211_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8211_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8211_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *is100 = (phy_data & VSC8211_AUX_SPEED_MASK) ==
+ VSC8211_AUX_SPEED_IS_100;
+ break;
+ case VSC8601_E_PHY_ID:
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, VSC8601_AUX_CTRL_STS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg
+ ("Unable to read register VSC8601_AUX_CTRL_STS\n");
+ return ret_val;
+ }
+ *is100 = (phy_data & VSC8601_AUX_SPEED_MASK) ==
+ VSC8601_AUX_SPEED_IS_100;
+ break;
+ case NON_PHY_PORT:
+ *is100 = false;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !is100)
+ return -1;
+ *is100 = false;
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_get_info
+ * @hw struct e1000_hw containing hardware specific data
+ * @phy_info struct e1000_phy_info that returned
+ *
+ * This is called by e1000_phy_get_info to gather PHY specific
+ * data. This is called for copper media based phys.
+ **/
+int32_t
+e1000_oem_phy_get_info(struct e1000_hw *hw, struct e1000_phy_info *phy_info)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+ uint16_t phy_data, polarity;
+
+ if (!hw || !phy_info)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton
+ * see e1000_phy_m88_get_info
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ /* The downshift status is checked only once, after link is
+ * established and it stored in the hw->speed_downgraded
+ * parameter.*/
+ phy_info->downshift = (e1000_downshift) hw->speed_downgraded;
+
+ ret_val = e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_CTRL,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_CTRL\n");
+ return ret_val;
+ }
+
+ phy_info->extended_10bt_distance =
+ (phy_data & M88E1000_PSCR_10BT_EXT_DIST_ENABLE)
+ >> M88E1000_PSCR_10BT_EXT_DIST_ENABLE_SHIFT;
+ phy_info->polarity_correction =
+ (phy_data & M88E1000_PSCR_POLARITY_REVERSAL)
+ >> M88E1000_PSCR_POLARITY_REVERSAL_SHIFT;
+
+ /* Check polarity status */
+ ret_val = e1000_oem_check_polarity(hw, &polarity);
+ if (ret_val)
+ return ret_val;
+
+ phy_info->cable_polarity = polarity;
+
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "M88E1000_PHY_SPEC_STATUS\n");
+ return ret_val;
+ }
+
+ phy_info->mdix_mode = (phy_data & M88E1000_PSSR_MDIX)
+ >> M88E1000_PSSR_MDIX_SHIFT;
+
+ if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) {
+ /* Cable Length Estimation and Local/Remote Receiver
+ * Information are only valid at 1000 Mbps.
+ */
+ phy_info->cable_length =
+ (phy_data & M88E1000_PSSR_CABLE_LENGTH)
+ >> M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw, PHY_1000T_STATUS,
+ &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register "
+ "PHY_1000T_STATUS\n");
+ return ret_val;
+ }
+
+ phy_info->local_rx =
+ (phy_data & SR_1000T_LOCAL_RX_STATUS)
+ >> SR_1000T_LOCAL_RX_STATUS_SHIFT;
+
+ phy_info->remote_rx =
+ (phy_data & SR_1000T_REMOTE_RX_STATUS)
+ >> SR_1000T_REMOTE_RX_STATUS_SHIFT;
+ }
+
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_hw_reset
+ * @hw struct e1000_hw containing hardware specific data
+ *
+ * This function will perform a software initiated reset of
+ * the PHY
+ **/
+int32_t e1000_oem_phy_hw_reset(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+ uint16_t phy_data;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * This code pretty much copies the default case from
+ * e1000_phy_reset() as that is what is appropriate for
+ * the M88 used in truxton.
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_CTRL, &phy_data);
+ if (ret_val) {
+ e_dbg("Unable to read register PHY_CTRL\n");
+ return ret_val;
+ }
+
+ phy_data |= MII_CR_RESET;
+ ret_val = e1000_oem_write_phy_reg_ex(hw, PHY_CTRL, phy_data);
+ if (ret_val) {
+ e_dbg("Unable to write register PHY_CTRL\n");
+ return ret_val;
+ }
+
+ udelay(1);
+ break;
+ case NON_PHY_PORT:
+ /* do nothing */
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_init_script
+ * @hw struct e1000_hw containing hardware specific data
+ *
+ * This gets called in three places, after egbe_oem_phy_hw_reset()
+ * to perform and post reset initialiation. Not all PHYs require
+ * this, which is why it was split off as a seperate function.
+ **/
+void e1000_oem_phy_init_script(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ if (!hw)
+ return;
+
+ e_dbg("%s", __func__);
+
+ /* call the GCU func that can do any phy specific init
+ * functions after a reset
+ *
+ * Make note that the M88 phy is what'll be used on Truxton
+ *
+ * The closest thing is in e1000_phy_init_script, however this is
+ * for the IGP style of phy. This is probably a no-op for truxton
+ * but may be needed by OEM's later on
+ *
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ case NON_PHY_PORT:
+ e_dbg("Nothing to do for OEM PHY Init");
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return;
+ }
+
+#endif /* ifdef EXTERNAL_MDIO */
+ return;
+
+}
+
+/**
+ * e1000_oem_read_phy_reg_ex
+ * @hw struct e1000_hw containing hardware specific data
+ * @reg_addr address location within the PHY register set
+ * @phy_data returns the data read from reg_addr
+ *
+ * This encapsulates the interface call to the GCU for access
+ * to the MDIO for the PHY.
+ **/
+int32_t
+e1000_oem_read_phy_reg_ex(struct e1000_hw *hw,
+ uint32_t reg_addr, uint16_t *phy_data)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+
+ if (!hw || !phy_data)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /* call the GCU func that will read the phy
+ *
+ * Make note that the M88 phy is what'll be used on Truxton.
+ *
+ * The closest thing is in e1000_read_phy_reg_ex.
+ *
+ * NOTE: this is 1 (of 2) functions that is truly dependant on the
+ * gcu module
+ */
+
+ ret_val = gcu_read_eth_phy(e1000_oem_get_phy_dev_number(hw),
+ reg_addr, phy_data);
+ if (ret_val) {
+ e_dbg("Error reading GCU");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_set_trans_gasket
+ * @hw: e1000_hw struct containing device specific information
+ *
+ * Returns E1000_SUCCESS, negative E1000 error code on failure
+ *
+ * This is called from e1000_config_mac_to_phy. Various supported
+ * Phys may require the RGMII/RMII Translation gasket be set to RMII.
+ **/
+int32_t e1000_oem_set_trans_gasket(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ /* Gasket set correctly for Marvell Phys, so nothing to do */
+ break;
+#if 0
+ /* Add your PHY_ID here if your device requires an RMII
+ * interface */
+ case YOUR_PHY_ID:
+ ctrl_aux_reg = E1000_READ_REG(hw, CTRL_AUX);
+ /* Set the RGMII_RMII bit */
+ ctrl_aux_reg |= E1000_CTRL_AUX_ICP_xxxx_MII_TGS;
+ E1000_WRITE_REG(hw, CTRL_AUX, ctrl_aux_reg);
+ break;
+#endif
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_write_phy_reg_ex
+ * @hw struct e1000_hw containing hardware specific data
+ * @reg_addr address location within the PHY register set
+ * @phy_data data to be written to reg_addr
+ *
+ * This encapsulates the interface call to the GCU for access
+ * to the MDIO for the PHY.
+ **/
+int32_t
+e1000_oem_write_phy_reg_ex(struct e1000_hw *hw,
+ uint32_t reg_addr, uint16_t phy_data)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /* call the GCU func that will write to the phy
+ *
+ * Make note that the M88 phy is what'll be used on Truxton.
+ *
+ * The closest thing is in e1000_write_phy_reg_ex
+ *
+ * NOTE: this is 2 (of 2) functions that is truly dependant on the
+ * gcu module
+ */
+ ret_val = gcu_write_eth_phy(e1000_oem_get_phy_dev_number(hw),
+ reg_addr, phy_data);
+ if (ret_val) {
+ e_dbg("Error writing to GCU");
+ return ret_val;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_needs_reset_with_mac
+ * @hw struct e1000_hw hardware specific data
+ *
+ * e1000_reset_hw is called to reset the MAC. If, for
+ * some reason the PHY needs to be reset as well, this
+ * should return true and then e1000_oem_phy_hw_reset()
+ * will be called.
+ **/
+int e1000_oem_phy_needs_reset_with_mac(struct e1000_hw *hw)
+{
+#ifdef EXTERNAL_MDIO
+
+ int ret_val;
+
+ if (!hw)
+ return false;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * From the original e1000 driver, the M88
+ * PHYs did not seem to need this reset,
+ * so returning false.
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ case NON_PHY_PORT:
+ ret_val = false;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return false;
+ }
+
+ return ret_val;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return false;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_config_dsp_after_link_change
+ * @hw struct e1000_hw containing hardware specific data
+ * @link_up allows different configurations based on whether
+ * not the link was up.
+ *
+ * This is called from e1000_check_for_link, and allows for
+ * tweaking of the PHY, for PHYs that support a DSP.
+ *
+ **/
+int32_t
+e1000_oem_config_dsp_after_link_change(struct e1000_hw *hw, int link_up)
+{
+#ifdef EXTERNAL_MDIO
+
+ if (!hw)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton,
+ * but in the e1000 driver, it had no such func. This is a no-op
+ * for M88, but may be useful for other phys
+ *
+ * use e1000_config_dsp_after_link_change as example
+ */
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ e_dbg("No DSP to configure on OEM PHY");
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_get_cable_length
+ * @hw struct e1000_hw containing hardware specific data
+ * @min_length pointer to return the approx minimum length
+ * @max_length pointer to return the approx maximum length
+ *
+ *
+ **/
+int32_t
+e1000_oem_get_cable_length(struct e1000_hw *hw,
+ uint16_t *min_length, uint16_t *max_length)
+{
+#ifdef EXTERNAL_MDIO
+
+ int32_t ret_val;
+ uint16_t cable_length;
+ uint16_t phy_data;
+
+ if (!hw || !min_length || !max_length)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ if (ret_val)
+ return ret_val;
+
+ cable_length = (phy_data & M88E1000_PSSR_CABLE_LENGTH)
+ >> M88E1000_PSSR_CABLE_LENGTH_SHIFT;
+
+ /* Convert the enum value to ranged values */
+ switch (cable_length) {
+ case e1000_cable_length_50:
+ *min_length = 0;
+ *max_length = e1000_igp_cable_length_50;
+ break;
+ case e1000_cable_length_50_80:
+ *min_length = e1000_igp_cable_length_50;
+ *max_length = e1000_igp_cable_length_80;
+ break;
+ case e1000_cable_length_80_110:
+ *min_length = e1000_igp_cable_length_80;
+ *max_length = e1000_igp_cable_length_110;
+ break;
+ case e1000_cable_length_110_140:
+ *min_length = e1000_igp_cable_length_110;
+ *max_length = e1000_igp_cable_length_140;
+ break;
+ case e1000_cable_length_140:
+ *min_length = e1000_igp_cable_length_140;
+ *max_length = e1000_igp_cable_length_170;
+ break;
+ default:
+ return -E1000_ERR_PHY;
+ break;
+ }
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
+
+/**
+ * e1000_oem_phy_is_link_up
+ * @hw e1000_hw struct containing device specific information
+ * @isUp a boolean returning true if link is up
+ *
+ * This is called as part of e1000_config_mac_to_phy() to align
+ * the MAC with the PHY. It turns out on ICP_XXXX, this is not
+ * done automagically.
+ **/
+int32_t e1000_oem_phy_is_link_up(struct e1000_hw *hw, int *isUp)
+{
+#ifdef EXTERNAL_MDIO
+
+ uint16_t phy_data;
+ uint16_t statusMask;
+ int32_t ret_val;
+
+ if (!hw || !isUp)
+ return -1;
+
+ e_dbg("%s", __func__);
+
+ /*
+ * Make note that the M88 phy is what'll be used on Truxton
+ * see e1000_config_mac_to_phy
+ */
+
+ if (hw->phy_id == NON_PHY_PORT) {
+ *isUp = 1;
+ } else {
+ switch (hw->phy_id) {
+ case M88E1000_I_PHY_ID:
+ case M88E1141_E_PHY_ID:
+ e1000_oem_read_phy_reg_ex(hw, M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ ret_val =
+ e1000_oem_read_phy_reg_ex(hw,
+ M88E1000_PHY_SPEC_STATUS,
+ &phy_data);
+ statusMask = M88E1000_PSSR_LINK;
+ break;
+ case VSC8211_E_PHY_ID:
+ case VSC8601_E_PHY_ID:
+ ret_val = e1000_oem_read_phy_reg_ex(hw, PHY_STATUS,
+ &phy_data);
+ statusMask = MII_SR_LINK_STATUS;
+ break;
+ default:
+ e_dbg("Invalid PHY ID\n");
+ return -E1000_ERR_PHY_TYPE;
+ }
+
+ if (ret_val) {
+ e_dbg("Unable to read PHY register\n");
+ return ret_val;
+ }
+
+ *isUp = (phy_data & statusMask) != 0;
+ }
+
+ return E1000_SUCCESS;
+
+#else /* ifdef EXTERNAL_MDIO */
+
+ if (!hw || !isFD)
+ return -1;
+ *isUp = false;
+ return -E1000_ERR_PHY_TYPE;
+
+#endif /* ifdef EXTERNAL_MDIO */
+}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_oem_phy.h b/drivers/net/ethernet/intel/e1000/e1000_oem_phy.h
new file mode 100644
index 00000000000..4c9bc15c61c
--- /dev/null
+++ b/drivers/net/ethernet/intel/e1000/e1000_oem_phy.h
@@ -0,0 +1,225 @@
+/*******************************************************************************
+
+GPL LICENSE SUMMARY
+
+ Copyright(c) 2007,2008,2009 Intel Corporation. All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of version 2 of the GNU General Public License as
+ published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ The full GNU General Public License is included in this distribution
+ in the file called LICENSE.GPL.
+
+ Contact Information:
+ Intel Corporation
+
+ version: Embedded.Release.Patch.L.1.0.7-5
+
+ Contact Information:
+
+ Intel Corporation, 5000 W Chandler Blvd, Chandler, AZ 85226
+
+*******************************************************************************/
+#ifndef _E1000_OEM_PHY_H_
+#define _E1000_OEM_PHY_H_
+
+#include <linux/types.h>
+
+#define E1000_CTRL_AUX 0x000E0 /* Aux Control -RW */
+#define E1000_82542_CTRL_AUX E1000_CTRL_AUX
+
+/* Bit definitions for valid PHY IDs. */
+/* I = Integrated
+ * E = External
+ */
+#define M88E1000_E_PHY_ID 0x01410C50
+#define M88E1000_I_PHY_ID 0x01410C30
+#define M88E1011_I_PHY_ID 0x01410C20
+#define IGP01E1000_I_PHY_ID 0x02A80380
+#define M88E1000_12_PHY_ID M88E1000_E_PHY_ID
+#define M88E1000_14_PHY_ID M88E1000_E_PHY_ID
+#define M88E1011_I_REV_4 0x04
+#define M88E1141_E_PHY_ID 0x01410CD0
+#define L1LXT971A_PHY_ID 0x001378E0
+#define VSC8211_E_PHY_ID 0x000FC4B1
+#define VSC8601_E_PHY_ID 0x00070420
+
+/* RGMII TX and RX Timing Control*/
+#define M88E1000_EPSCR_TX_TIME_CTRL 0x0002 /* Add Delay */
+#define M88E1000_EPSCR_RX_TIME_CTRL 0x0080 /* Add Delay */
+
+/* M88E1000 Specific Registers */
+#define M88E1000_PHY_SPEC_CTRL 0x10 /* PHY Specific Control Register */
+#define M88E1000_PHY_SPEC_STATUS 0x11 /* PHY Specific Status Register */
+#define M88E1000_INT_ENABLE 0x12 /* Interrupt Enable Register */
+#define M88E1000_INT_STATUS 0x13 /* Interrupt Status Register */
+#define M88E1000_EXT_PHY_SPEC_CTRL 0x14 /* Extended PHY Specific Control */
+#define M88E1000_RX_ERR_CNTR 0x15 /* Receive Error Counter */
+
+#define M88E1000_PHY_EXT_CTRL 0x1A /* PHY extend control register */
+#define M88E1000_PHY_PAGE_SELECT 0x1D /* Reg 29 for page number setting */
+#define M88E1000_PHY_GEN_CONTROL 0x1E /* Its meaning depends on reg 29 */
+#define M88E1000_PHY_VCO_REG_BIT8 0x100 /* Bits 8 & 11 are adjusted for */
+#define M88E1000_PHY_VCO_REG_BIT11 0x800 /* improved BER performance */
+
+#define IGP01E1000_IEEE_REGS_PAGE 0x0000
+#define IGP01E1000_IEEE_RESTART_AUTONEG 0x3300
+#define IGP01E1000_IEEE_FORCE_GIGA 0x0140
+
+/* IGP01E1000 Specific Registers */
+#define IGP01E1000_PHY_PORT_CONFIG 0x10 /* PHY Specific Port Config Register */
+#define IGP01E1000_PHY_PORT_STATUS 0x11 /* PHY Specific Status Register */
+#define IGP01E1000_PHY_PORT_CTRL 0x12 /* PHY Specific Control Register */
+#define IGP01E1000_PHY_LINK_HEALTH 0x13 /* PHY Link Health Register */
+#define IGP01E1000_GMII_FIFO 0x14 /* GMII FIFO Register */
+#define IGP01E1000_PHY_CHANNEL_QUALITY 0x15 /* PHY Channel Quality Register */
+#define IGP02E1000_PHY_POWER_MGMT 0x19
+#define IGP01E1000_PHY_PAGE_SELECT 0x1F /* PHY Page Select Core Register */
+
+/* VSC8211 Specific Registers */
+#define VSC8211_BYPASS_CTRL 0x12
+#define VSC8211_PHY_CTRL_1 0x17
+#define VSC8211_AUX_CTRL_STS 0x1C
+#define VSC8211_EXT_PAGE_ACCESS 0x1F
+
+/* VSC8601 Specific Registers */
+#define VSC8601_BYPASS_CTRL 0x12
+#define VSC8601_PHY_CTRL_1 0x17
+#define VSC8601_AUX_CTRL_STS 0x1C
+
+/* VSC8211 BYPASS Control Register */
+#define VSC8211_BYPASS_POLAR_INVERS_DISABLE 0x0010
+#define VSC8211_BYPASS_AUTO_MDI_DISABLE 0x0020
+
+/* VSC8211 Auxiliary Control & Status Register */
+#define VSC8211_AUX_SPEED_MASK 0x0018
+#define VSC8211_AUX_SPEED_IS_1000 0x0010
+#define VSC8211_AUX_SPEED_IS_100 0x0008
+#define VSC8211_AUX_SPEED_IS_10 0x0000
+
+#define VSC8211_AUX_FDX_MASK 0x0020
+#define VSC8211_AUX_FDX_IS_FULL 0x0020
+#define VSC8211_AUX_FDX_IS_HALF 0x0000
+
+/* VSC8211 PHY Control Register #1 */
+#define VSC8211_PHY_CTRL1_INTF_MODE1_RGMII 0x1000
+#define VSC8211_PHY_CTRL1_INTF_MODE1_GMII 0x3000
+
+#define VSC8211_PHY_CTRL1_TXC_SKEW_2NS 0x0800
+#define VSC8211_PHY_CTRL1_RXC_SKEW_2NS 0x0200
+
+#define VSC8211_PHY_CTRL1_RX_IDLE_CLK_ENABLE 0x0020
+#define VSC8211_PHY_CTRL1_RX_IDLE_CLK_DISABLE 0x0000
+
+#define VSC8211_PHY_CTRL1_INTF_MODE2_CAT5 0x0004
+#define VSC8211_PHY_CTRL1_INTF_MODE2_FIBER 0x0002
+
+/* VSC8601 BYPASS Control Register */
+#define VSC8601_BYPASS_POLAR_INVERS_DISABLE 0x0010
+#define VSC8601_BYPASS_AUTO_MDI_DISABLE 0x0020
+
+/* VSC8601 Auxiliary Control & Status Register */
+#define VSC8601_AUX_SPEED_MASK 0x0018
+#define VSC8601_AUX_SPEED_IS_1000 0x0010
+#define VSC8601_AUX_SPEED_IS_100 0x0008
+#define VSC8601_AUX_SPEED_IS_10 0x0000
+
+#define VSC8601_AUX_FDX_MASK 0x0020
+#define VSC8601_AUX_FDX_IS_FULL 0x0020
+#define VSC8601_AUX_FDX_IS_HALF 0x0000
+
+/*
+ * ICP GbE devices are not assigned Intel part numbers yet so just
+ * identify them via their device id's
+ */
+#define E1000_DEV_ID_ICP_5040 0x5040
+#define E1000_DEV_ID_ICP_5041 0x5041
+#define E1000_DEV_ID_ICP_5042 0x5042
+#define E1000_DEV_ID_ICP_5043 0x5043
+#define E1000_DEV_ID_ICP_5044 0x5044
+#define E1000_DEV_ID_ICP_5045 0x5045
+#define E1000_DEV_ID_ICP_5046 0x5046
+#define E1000_DEV_ID_ICP_5047 0x5047
+#define E1000_DEV_ID_ICP_5048 0x5048
+#define E1000_DEV_ID_ICP_5049 0x5049
+#define E1000_DEV_ID_ICP_504A 0x504A
+#define E1000_DEV_ID_ICP_504B 0x504B
+
+struct e1000_hw;
+struct e1000_adapter;
+struct ifreq;
+struct e1000_phy_info;
+
+int32_t e1000_oem_setup_link(struct e1000_hw *hw);
+int32_t e1000_oem_set_trans_gasket(struct e1000_hw *hw);
+
+uint32_t e1000_oem_get_tipg(struct e1000_hw *hw);
+int e1000_oem_phy_is_copper(struct e1000_hw *hw);
+uint32_t e1000_oem_get_phy_dev_number(struct e1000_hw *hw);
+int e1000_oem_mii_ioctl(struct e1000_adapter *adapter, unsigned long flags,
+ struct ifreq *ifr, int cmd);
+void e1000_oem_get_phy_regs(struct e1000_adapter *adapter, uint32_t *data,
+ uint32_t data_length);
+int e1000_oem_phy_loopback(struct e1000_adapter *adapter);
+void e1000_oem_loopback_cleanup(struct e1000_adapter *adapter);
+uint32_t e1000_oem_phy_speed_downgraded(struct e1000_hw *hw,
+ uint16_t *isDowngraded);
+int32_t e1000_oem_check_polarity(struct e1000_hw *hw, uint16_t *polarity);
+
+int32_t e1000_oem_phy_is_full_duplex(struct e1000_hw *hw, int *isFD);
+int32_t e1000_oem_phy_is_speed_1000(struct e1000_hw *hw, int *is1000);
+int32_t e1000_oem_phy_is_speed_100(struct e1000_hw *hw, int *is100);
+
+int32_t e1000_oem_force_mdi(struct e1000_hw *hw, int *resetPhy);
+int32_t e1000_oem_phy_reset_dsp(struct e1000_hw *hw);
+int32_t e1000_oem_cleanup_after_phy_reset(struct e1000_hw *hw);
+
+int32_t e1000_oem_phy_get_info(struct e1000_hw *hw,
+ struct e1000_phy_info *phy_info);
+
+int32_t e1000_oem_phy_hw_reset(struct e1000_hw *hw);
+void e1000_oem_phy_init_script(struct e1000_hw *hw);
+
+int32_t e1000_oem_read_phy_reg_ex(struct e1000_hw *hw,
+ uint32_t reg_addr, uint16_t *phy_data);
+int32_t e1000_oem_write_phy_reg_ex(struct e1000_hw *hw,
+ uint32_t reg_addr, uint16_t phy_data);
+
+int e1000_oem_phy_needs_reset_with_mac(struct e1000_hw *hw);
+
+int32_t e1000_oem_config_dsp_after_link_change(struct e1000_hw *hw,
+ int link_up);
+
+int32_t e1000_oem_get_cable_length(struct e1000_hw *hw,
+ uint16_t *min_length,
+ uint16_t *max_length);
+
+int32_t e1000_oem_phy_is_link_up(struct e1000_hw *hw, int *isUp);
+
+/* Default Register Macros */
+
+#define ICP_XXXX_MAC_0 0 /* PCI Device numbers associated with MACs on */
+#define ICP_XXXX_MAC_1 1 /* ICP_XXXX family of controllers */
+#define ICP_XXXX_MAC_2 2
+
+#define DEFAULT_ICP_XXXX_TIPG_IPGT 8 /* Inter Packet Gap Transmit Time */
+#define ICP_XXXX_TIPG_IPGT_MASK 0x000003FFUL
+
+/* Miscellaneous defines */
+#ifdef IEGBE_10_100_ONLY
+ #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x0F
+#else
+ #define ICP_XXXX_AUTONEG_ADV_DEFAULT 0x2F
+#endif
+
+#endif /* ifndef _IEGBE_OEM_PHY_H_ */
+
diff --git a/drivers/net/ethernet/intel/e1000/e1000_osdep.h b/drivers/net/ethernet/intel/e1000/e1000_osdep.h
index 33e7c45a4fe..69538aff9f8 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_osdep.h
+++ b/drivers/net/ethernet/intel/e1000/e1000_osdep.h
@@ -59,10 +59,20 @@
(writel((value), (hw->hw_addr + ((hw->mac_type >= e1000_82543) \
? E1000_##reg : E1000_82542_##reg))))
+#define E1000_WRITE_REG(a, reg, value) ( \
+ writel((value), ((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : \
+ E1000_82542_##reg))))
+
+#define E1000_READ_REG(a, reg) ( \
+ readl((a)->hw_addr + \
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : \
+ E1000_82542_##reg)))
+
#define E1000_WRITE_REG_ARRAY(a, reg, offset, value) ( \
writel((value), ((a)->hw_addr + \
- (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
- ((offset) << 2))))
+ (((a)->mac_type >= e1000_82543) ? E1000_##reg : E1000_82542_##reg) + \
+ ((offset) << 2))))
#define E1000_READ_REG_ARRAY(a, reg, offset) ( \
readl((a)->hw_addr + \
diff --git a/drivers/net/ethernet/intel/e1000/e1000_param.c b/drivers/net/ethernet/intel/e1000/e1000_param.c
index 1301eba8b57..a1a6e57d421 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_param.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_param.c
@@ -27,6 +27,7 @@
*******************************************************************************/
#include "e1000.h"
+#include "e1000_oem_phy.h"
/* This is the only thing that needs to be changed to adjust the
* maximum number of ports that the driver can manage.
@@ -522,6 +523,12 @@ void __devinit e1000_check_options(struct e1000_adapter *adapter)
case e1000_media_type_copper:
e1000_check_copper_options(adapter);
break;
+ case e1000_media_type_oem:
+ if (e1000_oem_phy_is_copper(&adapter->hw))
+ e1000_check_copper_options(adapter);
+ else
+ e1000_check_fiber_options(adapter);
+ break;
default:
BUG();
}