From 6418ecc68e1d9416451b6f78ebb2c0b077e0abf2 Mon Sep 17 00:00:00 2001 From: Jeff Kirsher Date: Thu, 2 Mar 2006 18:21:10 -0800 Subject: e1000: Add support for new hardware (ESB2) Signed-off-by: Jeff Kirsher Signed-off-by: Jesse Brandeburg Signed-off-by: John Ronciak --- drivers/net/e1000/e1000_hw.c | 685 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 669 insertions(+), 16 deletions(-) (limited to 'drivers/net/e1000/e1000_hw.c') diff --git a/drivers/net/e1000/e1000_hw.c b/drivers/net/e1000/e1000_hw.c index 5ee42c7..63e2370 100644 --- a/drivers/net/e1000/e1000_hw.c +++ b/drivers/net/e1000/e1000_hw.c @@ -100,6 +100,8 @@ static void e1000_write_reg_io(struct e1000_hw *hw, uint32_t offset, #define E1000_WRITE_REG_IO(a, reg, val) \ e1000_write_reg_io((a), E1000_##reg, val) +static int32_t e1000_configure_kmrn_for_10_100(struct e1000_hw *hw); +static int32_t e1000_configure_kmrn_for_1000(struct e1000_hw *hw); /* IGP cable length table */ static const @@ -153,6 +155,11 @@ e1000_set_phy_type(struct e1000_hw *hw) hw->phy_type = e1000_phy_igp; break; } + case GG82563_E_PHY_ID: + if (hw->mac_type == e1000_80003es2lan) { + hw->phy_type = e1000_phy_gg82563; + break; + } /* Fall Through */ default: /* Should never have loaded on this device */ @@ -353,12 +360,19 @@ e1000_set_mac_type(struct e1000_hw *hw) case E1000_DEV_ID_82573L: hw->mac_type = e1000_82573; break; + case E1000_DEV_ID_80003ES2LAN_COPPER_DPT: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: + hw->mac_type = e1000_80003es2lan; + break; default: /* Should never have loaded on this device */ return -E1000_ERR_MAC_TYPE; } switch(hw->mac_type) { + case e1000_80003es2lan: + hw->swfw_sync_present = TRUE; + /* fall through */ case e1000_82571: case e1000_82572: case e1000_82573: @@ -399,6 +413,7 @@ e1000_set_media_type(struct e1000_hw *hw) case E1000_DEV_ID_82546GB_SERDES: case E1000_DEV_ID_82571EB_SERDES: case E1000_DEV_ID_82572EI_SERDES: + case E1000_DEV_ID_80003ES2LAN_SERDES_DPT: hw->media_type = e1000_media_type_internal_serdes; break; default: @@ -575,6 +590,7 @@ e1000_reset_hw(struct e1000_hw *hw) /* fall through */ case e1000_82571: case e1000_82572: + case e1000_80003es2lan: ret_val = e1000_get_auto_rd_done(hw); if(ret_val) /* We don't want to continue accessing MAC registers. */ @@ -641,6 +657,7 @@ e1000_init_hw(struct e1000_hw *hw) uint16_t cmd_mmrbc; uint16_t stat_mmrbc; uint32_t mta_size; + uint32_t reg_data; uint32_t ctrl_ext; DEBUGFUNC("e1000_init_hw"); @@ -739,6 +756,7 @@ e1000_init_hw(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: ctrl |= E1000_TXDCTL_COUNT_DESC; break; } @@ -752,12 +770,34 @@ e1000_init_hw(struct e1000_hw *hw) switch (hw->mac_type) { default: break; + case e1000_80003es2lan: + /* Enable retransmit on late collisions */ + reg_data = E1000_READ_REG(hw, TCTL); + reg_data |= E1000_TCTL_RTLC; + E1000_WRITE_REG(hw, TCTL, reg_data); + + /* Configure Gigabit Carry Extend Padding */ + reg_data = E1000_READ_REG(hw, TCTL_EXT); + reg_data &= ~E1000_TCTL_EXT_GCEX_MASK; + reg_data |= DEFAULT_80003ES2LAN_TCTL_EXT_GCEX; + E1000_WRITE_REG(hw, TCTL_EXT, reg_data); + + /* Configure Transmit Inter-Packet Gap */ + reg_data = E1000_READ_REG(hw, TIPG); + reg_data &= ~E1000_TIPG_IPGT_MASK; + reg_data |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, reg_data); + + reg_data = E1000_READ_REG_ARRAY(hw, FFLT, 0x0001); + reg_data &= ~0x00100000; + E1000_WRITE_REG_ARRAY(hw, FFLT, 0x0001, reg_data); + /* Fall through */ case e1000_82571: case e1000_82572: ctrl = E1000_READ_REG(hw, TXDCTL1); - ctrl &= ~E1000_TXDCTL_WTHRESH; - ctrl |= E1000_TXDCTL_COUNT_DESC | E1000_TXDCTL_FULL_TX_DESC_WB; - ctrl |= (1 << 22); + ctrl = (ctrl & ~E1000_TXDCTL_WTHRESH) | E1000_TXDCTL_FULL_TX_DESC_WB; + if(hw->mac_type >= e1000_82571) + ctrl |= E1000_TXDCTL_COUNT_DESC; E1000_WRITE_REG(hw, TXDCTL1, ctrl); break; } @@ -1314,6 +1354,154 @@ e1000_copper_link_igp_setup(struct e1000_hw *hw) return E1000_SUCCESS; } +/******************************************************************** +* Copper link setup for e1000_phy_gg82563 series. +* +* hw - Struct containing variables accessed by shared code +*********************************************************************/ +static int32_t +e1000_copper_link_ggp_setup(struct e1000_hw *hw) +{ + int32_t ret_val; + uint16_t phy_data; + uint32_t reg_data; + + DEBUGFUNC("e1000_copper_link_ggp_setup"); + + if(!hw->phy_reset_disable) { + + /* Enable CRS on TX for half-duplex operation. */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + &phy_data); + if(ret_val) + return ret_val; + + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + /* Use 25MHz for both link down and 1000BASE-T for Tx clock */ + phy_data |= GG82563_MSCR_TX_CLK_1000MBPS_25MHZ; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, + phy_data); + if(ret_val) + 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) + */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL, &phy_data); + if(ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR_CROSSOVER_MODE_MASK; + + switch (hw->mdix) { + case 1: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDI; + break; + case 2: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_MDIX; + break; + case 0: + default: + phy_data |= GG82563_PSCR_CROSSOVER_MODE_AUTO; + break; + } + + /* Options: + * disable_polarity_correction = 0 (default) + * Automatic Correction for Reversed Cable Polarity + * 0 - Disabled + * 1 - Enabled + */ + phy_data &= ~GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + if(hw->disable_polarity_correction == 1) + phy_data |= GG82563_PSCR_POLARITY_REVERSAL_DISABLE; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL, phy_data); + + if(ret_val) + return ret_val; + + /* SW Reset the PHY so all changes take effect */ + ret_val = e1000_phy_reset(hw); + if (ret_val) { + DEBUGOUT("Error Resetting the PHY\n"); + return ret_val; + } + } /* phy_reset_disable */ + + if (hw->mac_type == e1000_80003es2lan) { + /* Bypass RX and TX FIFO's */ + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_FIFO_CTRL, + E1000_KUMCTRLSTA_FIFO_CTRL_RX_BYPASS | + E1000_KUMCTRLSTA_FIFO_CTRL_TX_BYPASS); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_PSCR2_REVERSE_AUTO_NEG; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_SPEC_CTRL_2, phy_data); + + if (ret_val) + return ret_val; + + reg_data = E1000_READ_REG(hw, CTRL_EXT); + reg_data &= ~(E1000_CTRL_EXT_LINK_MODE_MASK); + E1000_WRITE_REG(hw, CTRL_EXT, reg_data); + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* Do not init these registers when the HW is in IAMT mode, since the + * firmware will have already initialized them. We only initialize + * them if the HW is not in IAMT mode. + */ + if (e1000_check_mng_mode(hw) == FALSE) { + /* Enable Electrical Idle on the PHY */ + phy_data |= GG82563_PMCR_ENABLE_ELECTRICAL_IDLE; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_PWR_MGMT_CTRL, + phy_data); + if (ret_val) + return ret_val; + + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + &phy_data); + if (ret_val) + return ret_val; + + /* Enable Pass False Carrier on the PHY */ + phy_data |= GG82563_KMCR_PASS_FALSE_CARRIER; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_KMRN_MODE_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + /* Workaround: Disable padding in Kumeran interface in the MAC + * and in the PHY to avoid CRC errors. + */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + &phy_data); + if (ret_val) + return ret_val; + phy_data |= GG82563_ICR_DIS_PADDING; + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_INBAND_CTRL, + phy_data); + if (ret_val) + return ret_val; + } + + return E1000_SUCCESS; +} /******************************************************************** * Copper link setup for e1000_phy_m88 series. @@ -1524,6 +1712,7 @@ e1000_setup_copper_link(struct e1000_hw *hw) int32_t ret_val; uint16_t i; uint16_t phy_data; + uint16_t reg_data; DEBUGFUNC("e1000_setup_copper_link"); @@ -1532,6 +1721,22 @@ e1000_setup_copper_link(struct e1000_hw *hw) if(ret_val) return ret_val; + switch (hw->mac_type) { + case e1000_80003es2lan: + ret_val = e1000_read_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, + ®_data); + if (ret_val) + return ret_val; + reg_data |= E1000_KUMCTRLSTA_INB_CTRL_DIS_PADDING; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_INB_CTRL, + reg_data); + if (ret_val) + return ret_val; + break; + default: + break; + } + if (hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) { ret_val = e1000_copper_link_igp_setup(hw); @@ -1541,6 +1746,10 @@ e1000_setup_copper_link(struct e1000_hw *hw) ret_val = e1000_copper_link_mgp_setup(hw); if(ret_val) return ret_val; + } else if (hw->phy_type == e1000_phy_gg82563) { + ret_val = e1000_copper_link_ggp_setup(hw); + if(ret_val) + return ret_val; } if(hw->autoneg) { @@ -1588,6 +1797,59 @@ e1000_setup_copper_link(struct e1000_hw *hw) } /****************************************************************************** +* Configure the MAC-to-PHY interface for 10/100Mbps +* +* hw - Struct containing variables accessed by shared code +******************************************************************************/ +static int32_t +e1000_configure_kmrn_for_10_100(struct e1000_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint32_t tipg; + uint16_t reg_data; + + DEBUGFUNC("e1000_configure_kmrn_for_10_100"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_10_100_DEFAULT; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_10_100; + E1000_WRITE_REG(hw, TIPG, tipg); + + return ret_val; +} + +static int32_t +e1000_configure_kmrn_for_1000(struct e1000_hw *hw) +{ + int32_t ret_val = E1000_SUCCESS; + uint16_t reg_data; + uint32_t tipg; + + DEBUGFUNC("e1000_configure_kmrn_for_1000"); + + reg_data = E1000_KUMCTRLSTA_HD_CTRL_1000_DEFAULT; + ret_val = e1000_write_kmrn_reg(hw, E1000_KUMCTRLSTA_OFFSET_HD_CTRL, + reg_data); + if (ret_val) + return ret_val; + + /* Configure Transmit Inter-Packet Gap */ + tipg = E1000_READ_REG(hw, TIPG); + tipg &= ~E1000_TIPG_IPGT_MASK; + tipg |= DEFAULT_80003ES2LAN_TIPG_IPGT_1000; + E1000_WRITE_REG(hw, TIPG, tipg); + + return ret_val; +} + +/****************************************************************************** * Configures PHY autoneg and flow control advertisement settings * * hw - Struct containing variables accessed by shared code @@ -1808,7 +2070,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) /* Write the configured values back to the Device Control Reg. */ E1000_WRITE_REG(hw, CTRL, ctrl); - if (hw->phy_type == e1000_phy_m88) { + if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if(ret_val) return ret_val; @@ -1877,7 +2140,8 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) msec_delay(100); } if((i == 0) && - (hw->phy_type == e1000_phy_m88)) { + ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563))) { /* We didn't get link. Reset the DSP and wait again for link. */ ret_val = e1000_phy_reset_dsp(hw); if(ret_val) { @@ -1936,6 +2200,27 @@ e1000_phy_force_speed_duplex(struct e1000_hw *hw) if(ret_val) return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + /* The TX_CLK of the Extended PHY Specific Control Register defaults + * to 2.5MHz on a reset. We need to re-force it back to 25MHz, if + * we're not in a forced 10/duplex configuration. */ + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, &phy_data); + if (ret_val) + return ret_val; + + phy_data &= ~GG82563_MSCR_TX_CLK_MASK; + if ((hw->forced_speed_duplex == e1000_10_full) || + (hw->forced_speed_duplex == e1000_10_half)) + phy_data |= GG82563_MSCR_TX_CLK_10MBPS_2_5MHZ; + else + phy_data |= GG82563_MSCR_TX_CLK_100MBPS_25MHZ; + + /* Also due to the reset, we need to enable CRS on Tx. */ + phy_data |= GG82563_MSCR_ASSERT_CRS_ON_TX; + + ret_val = e1000_write_phy_reg(hw, GG82563_PHY_MAC_SPEC_CTRL, phy_data); + if (ret_val) + return ret_val; } return E1000_SUCCESS; } @@ -2598,6 +2883,16 @@ e1000_get_speed_and_duplex(struct e1000_hw *hw, } } + if ((hw->mac_type == e1000_80003es2lan) && + (hw->media_type == e1000_media_type_copper)) { + if (*speed == SPEED_1000) + ret_val = e1000_configure_kmrn_for_1000(hw); + else + ret_val = e1000_configure_kmrn_for_10_100(hw); + if (ret_val) + return ret_val; + } + return E1000_SUCCESS; } @@ -2773,6 +3068,72 @@ e1000_shift_in_mdi_bits(struct e1000_hw *hw) return data; } +int32_t +e1000_swfw_sync_acquire(struct e1000_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync = 0; + uint32_t swmask = mask; + uint32_t fwmask = mask << 16; + int32_t timeout = 200; + + DEBUGFUNC("e1000_swfw_sync_acquire"); + + if (!hw->swfw_sync_present) + return e1000_get_hw_eeprom_semaphore(hw); + + while(timeout) { + if (e1000_get_hw_eeprom_semaphore(hw)) + return -E1000_ERR_SWFW_SYNC; + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) { + break; + } + + /* firmware currently using resource (fwmask) */ + /* or other software thread currently using resource (swmask) */ + e1000_put_hw_eeprom_semaphore(hw); + msec_delay_irq(5); + timeout--; + } + + if (!timeout) { + DEBUGOUT("Driver can't access resource, SW_FW_SYNC timeout.\n"); + return -E1000_ERR_SWFW_SYNC; + } + + swfw_sync |= swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + e1000_put_hw_eeprom_semaphore(hw); + return E1000_SUCCESS; +} + +void +e1000_swfw_sync_release(struct e1000_hw *hw, uint16_t mask) +{ + uint32_t swfw_sync; + uint32_t swmask = mask; + + DEBUGFUNC("e1000_swfw_sync_release"); + + if (!hw->swfw_sync_present) { + e1000_put_hw_eeprom_semaphore(hw); + return; + } + + /* if (e1000_get_hw_eeprom_semaphore(hw)) + * return -E1000_ERR_SWFW_SYNC; */ + while (e1000_get_hw_eeprom_semaphore(hw) != E1000_SUCCESS); + /* empty */ + + swfw_sync = E1000_READ_REG(hw, SW_FW_SYNC); + swfw_sync &= ~swmask; + E1000_WRITE_REG(hw, SW_FW_SYNC, swfw_sync); + + e1000_put_hw_eeprom_semaphore(hw); +} + /***************************************************************************** * Reads the value from a PHY register, if the value is on a specific non zero * page, sets the page first. @@ -2785,22 +3146,55 @@ e1000_read_phy_reg(struct e1000_hw *hw, uint16_t *phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_read_phy_reg"); + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + if((hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); if(ret_val) { + e1000_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == e1000_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = e1000_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + e1000_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = e1000_read_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + e1000_swfw_sync_release(hw, swfw); return ret_val; } @@ -2891,22 +3285,55 @@ e1000_write_phy_reg(struct e1000_hw *hw, uint16_t phy_data) { uint32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_write_phy_reg"); + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + if((hw->phy_type == e1000_phy_igp || hw->phy_type == e1000_phy_igp_2) && (reg_addr > MAX_PHY_MULTI_PAGE_REG)) { ret_val = e1000_write_phy_reg_ex(hw, IGP01E1000_PHY_PAGE_SELECT, (uint16_t)reg_addr); if(ret_val) { + e1000_swfw_sync_release(hw, swfw); return ret_val; } + } else if (hw->phy_type == e1000_phy_gg82563) { + if (((reg_addr & MAX_PHY_REG_ADDRESS) > MAX_PHY_MULTI_PAGE_REG) || + (hw->mac_type == e1000_80003es2lan)) { + /* Select Configuration Page */ + if ((reg_addr & MAX_PHY_REG_ADDRESS) < GG82563_MIN_ALT_REG) { + ret_val = e1000_write_phy_reg_ex(hw, GG82563_PHY_PAGE_SELECT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } else { + /* Use Alternative Page Select register to access + * registers 30 and 31 + */ + ret_val = e1000_write_phy_reg_ex(hw, + GG82563_PHY_PAGE_SELECT_ALT, + (uint16_t)((uint16_t)reg_addr >> GG82563_PAGE_SHIFT)); + } + + if (ret_val) { + e1000_swfw_sync_release(hw, swfw); + return ret_val; + } + } } ret_val = e1000_write_phy_reg_ex(hw, MAX_PHY_REG_ADDRESS & reg_addr, phy_data); + e1000_swfw_sync_release(hw, swfw); return ret_val; } @@ -2973,6 +3400,65 @@ e1000_write_phy_reg_ex(struct e1000_hw *hw, return E1000_SUCCESS; } +int32_t +e1000_read_kmrn_reg(struct e1000_hw *hw, + uint32_t reg_addr, + uint16_t *data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("e1000_read_kmrn_reg"); + + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + /* Write register address */ + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | + E1000_KUMCTRLSTA_REN; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + udelay(2); + + /* Read the data returned */ + reg_val = E1000_READ_REG(hw, KUMCTRLSTA); + *data = (uint16_t)reg_val; + + e1000_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} + +int32_t +e1000_write_kmrn_reg(struct e1000_hw *hw, + uint32_t reg_addr, + uint16_t data) +{ + uint32_t reg_val; + uint16_t swfw; + DEBUGFUNC("e1000_write_kmrn_reg"); + + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) + return -E1000_ERR_SWFW_SYNC; + + reg_val = ((reg_addr << E1000_KUMCTRLSTA_OFFSET_SHIFT) & + E1000_KUMCTRLSTA_OFFSET) | data; + E1000_WRITE_REG(hw, KUMCTRLSTA, reg_val); + udelay(2); + + e1000_swfw_sync_release(hw, swfw); + return E1000_SUCCESS; +} /****************************************************************************** * Returns the PHY to the power-on reset state @@ -2985,6 +3471,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) uint32_t ctrl, ctrl_ext; uint32_t led_ctrl; int32_t ret_val; + uint16_t swfw; DEBUGFUNC("e1000_phy_hw_reset"); @@ -2997,6 +3484,16 @@ e1000_phy_hw_reset(struct e1000_hw *hw) DEBUGOUT("Resetting Phy...\n"); if(hw->mac_type > e1000_82543) { + if ((hw->mac_type == e1000_80003es2lan) && + (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1)) { + swfw = E1000_SWFW_PHY1_SM; + } else { + swfw = E1000_SWFW_PHY0_SM; + } + if (e1000_swfw_sync_acquire(hw, swfw)) { + e1000_release_software_semaphore(hw); + return -E1000_ERR_SWFW_SYNC; + } /* Read the device control register and assert the E1000_CTRL_PHY_RST * bit. Then, take it out of reset. * For pre-e1000_82571 hardware, we delay for 10ms between the assert @@ -3017,6 +3514,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) if (hw->mac_type >= e1000_82571) msec_delay(10); + e1000_swfw_sync_release(hw, swfw); } else { /* Read the Extended Device Control Register, assert the PHY_RESET_DIR * bit to put the PHY into reset. Then, take it out of reset. @@ -3043,6 +3541,7 @@ e1000_phy_hw_reset(struct e1000_hw *hw) /* Wait for FW to finish PHY configuration. */ ret_val = e1000_get_phy_cfg_done(hw); + e1000_release_software_semaphore(hw); return ret_val; } @@ -3120,6 +3619,15 @@ e1000_detect_gig_phy(struct e1000_hw *hw) return E1000_SUCCESS; } + /* ESB-2 PHY reads require e1000_phy_gg82563 to be set because of a work- + * around that forces PHY page 0 to be set or the reads fail. The rest of + * the code in this routine uses e1000_read_phy_reg to read the PHY ID. + * So for ESB-2 we need to have this set so our reads won't fail. If the + * attached PHY is not a e1000_phy_gg82563, the routines below will figure + * this out as well. */ + if (hw->mac_type == e1000_80003es2lan) + hw->phy_type = e1000_phy_gg82563; + /* Read the PHY ID Registers to identify which PHY is onboard. */ ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id_high); if(ret_val) @@ -3157,6 +3665,9 @@ e1000_detect_gig_phy(struct e1000_hw *hw) case e1000_82573: if(hw->phy_id == M88E1111_I_PHY_ID) match = TRUE; break; + case e1000_80003es2lan: + if (hw->phy_id == GG82563_E_PHY_ID) match = TRUE; + break; default: DEBUGOUT1("Invalid MAC type %d\n", hw->mac_type); return -E1000_ERR_CONFIG; @@ -3183,8 +3694,10 @@ e1000_phy_reset_dsp(struct e1000_hw *hw) DEBUGFUNC("e1000_phy_reset_dsp"); do { - ret_val = e1000_write_phy_reg(hw, 29, 0x001d); - if(ret_val) break; + if (hw->phy_type != e1000_phy_gg82563) { + ret_val = e1000_write_phy_reg(hw, 29, 0x001d); + if(ret_val) break; + } ret_val = e1000_write_phy_reg(hw, 30, 0x00c1); if(ret_val) break; ret_val = e1000_write_phy_reg(hw, 30, 0x0000); @@ -3316,8 +3829,17 @@ e1000_phy_m88_get_info(struct e1000_hw *hw, /* 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); + if (hw->phy_type != e1000_phy_gg82563) { + phy_info->cable_length = ((phy_data & M88E1000_PSSR_CABLE_LENGTH) >> + M88E1000_PSSR_CABLE_LENGTH_SHIFT); + } else { + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + + phy_info->cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + } ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); if(ret_val) @@ -3511,6 +4033,20 @@ e1000_init_eeprom_params(struct e1000_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); } break; + case e1000_80003es2lan: + eeprom->type = e1000_eeprom_spi; + eeprom->opcode_bits = 8; + eeprom->delay_usec = 1; + if (eecd & E1000_EECD_ADDR_BITS) { + eeprom->page_size = 32; + eeprom->address_bits = 16; + } else { + eeprom->page_size = 8; + eeprom->address_bits = 8; + } + eeprom->use_eerd = TRUE; + eeprom->use_eewr = FALSE; + break; default: break; } @@ -3691,9 +4227,8 @@ e1000_acquire_eeprom(struct e1000_hw *hw) DEBUGFUNC("e1000_acquire_eeprom"); - if(e1000_get_hw_eeprom_semaphore(hw)) - return -E1000_ERR_EEPROM; - + if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; eecd = E1000_READ_REG(hw, EECD); if (hw->mac_type != e1000_82573) { @@ -3712,7 +4247,7 @@ e1000_acquire_eeprom(struct e1000_hw *hw) eecd &= ~E1000_EECD_REQ; E1000_WRITE_REG(hw, EECD, eecd); DEBUGOUT("Could not acquire EEPROM grant\n"); - e1000_put_hw_eeprom_semaphore(hw); + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); return -E1000_ERR_EEPROM; } } @@ -3835,7 +4370,7 @@ e1000_release_eeprom(struct e1000_hw *hw) E1000_WRITE_REG(hw, EECD, eecd); } - e1000_put_hw_eeprom_semaphore(hw); + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); } /****************************************************************************** @@ -3914,6 +4449,8 @@ e1000_read_eeprom(struct e1000_hw *hw, if (e1000_is_onboard_nvm_eeprom(hw) == TRUE && hw->eeprom.use_eerd == FALSE) { switch (hw->mac_type) { + case e1000_80003es2lan: + break; default: /* Prepare the EEPROM for reading */ if (e1000_acquire_eeprom(hw) != E1000_SUCCESS) @@ -4031,6 +4568,9 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw, uint32_t i = 0; int32_t error = 0; + if (e1000_swfw_sync_acquire(hw, E1000_SWFW_EEP_SM)) + return -E1000_ERR_SWFW_SYNC; + for (i = 0; i < words; i++) { register_value = (data[i] << E1000_EEPROM_RW_REG_DATA) | ((offset+i) << E1000_EEPROM_RW_ADDR_SHIFT) | @@ -4050,6 +4590,7 @@ e1000_write_eeprom_eewr(struct e1000_hw *hw, } } + e1000_swfw_sync_release(hw, E1000_SWFW_EEP_SM); return error; } @@ -4091,6 +4632,8 @@ e1000_is_onboard_nvm_eeprom(struct e1000_hw *hw) { uint32_t eecd = 0; + DEBUGFUNC("e1000_is_onboard_nvm_eeprom"); + if(hw->mac_type == e1000_82573) { eecd = E1000_READ_REG(hw, EECD); @@ -4517,6 +5060,7 @@ e1000_read_mac_addr(struct e1000_hw * hw) case e1000_82546: case e1000_82546_rev_3: case e1000_82571: + case e1000_80003es2lan: if(E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) hw->perm_mac_addr[5] ^= 0x01; break; @@ -4778,6 +5322,7 @@ e1000_rar_set(struct e1000_hw *hw, switch (hw->mac_type) { case e1000_82571: case e1000_82572: + case e1000_80003es2lan: if (hw->leave_av_bit_off == TRUE) break; default: @@ -5364,6 +5909,7 @@ e1000_get_bus_info(struct e1000_hw *hw) hw->bus_width = e1000_bus_width_pciex_1; break; case e1000_82571: + case e1000_80003es2lan: hw->bus_type = e1000_bus_type_pci_express; hw->bus_speed = e1000_bus_speed_2500; hw->bus_width = e1000_bus_width_pciex_4; @@ -5509,6 +6055,34 @@ e1000_get_cable_length(struct e1000_hw *hw, return -E1000_ERR_PHY; break; } + } else if (hw->phy_type == e1000_phy_gg82563) { + ret_val = e1000_read_phy_reg(hw, GG82563_PHY_DSP_DISTANCE, + &phy_data); + if (ret_val) + return ret_val; + cable_length = phy_data & GG82563_DSPD_CABLE_LENGTH; + + switch (cable_length) { + case e1000_gg_cable_length_60: + *min_length = 0; + *max_length = e1000_igp_cable_length_60; + break; + case e1000_gg_cable_length_60_115: + *min_length = e1000_igp_cable_length_60; + *max_length = e1000_igp_cable_length_115; + break; + case e1000_gg_cable_length_115_150: + *min_length = e1000_igp_cable_length_115; + *max_length = e1000_igp_cable_length_150; + break; + case e1000_gg_cable_length_150: + *min_length = e1000_igp_cable_length_150; + *max_length = e1000_igp_cable_length_180; + break; + default: + return -E1000_ERR_PHY; + break; + } } else if(hw->phy_type == e1000_phy_igp) { /* For IGP PHY */ uint16_t agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] = {IGP01E1000_PHY_AGC_A, @@ -5618,7 +6192,8 @@ e1000_check_polarity(struct e1000_hw *hw, DEBUGFUNC("e1000_check_polarity"); - if(hw->phy_type == e1000_phy_m88) { + if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { /* return the Polarity bit in the Status register. */ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); @@ -5687,7 +6262,8 @@ e1000_check_downshift(struct e1000_hw *hw) return ret_val; hw->speed_downgraded = (phy_data & IGP01E1000_PLHR_SS_DOWNGRADE) ? 1 : 0; - } else if(hw->phy_type == e1000_phy_m88) { + } else if ((hw->phy_type == e1000_phy_m88) || + (hw->phy_type == e1000_phy_gg82563)) { ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if(ret_val) @@ -6720,6 +7296,7 @@ e1000_get_auto_rd_done(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: while(timeout) { if (E1000_READ_REG(hw, EECD) & E1000_EECD_AUTO_RD) break; else msec_delay(1); @@ -6763,6 +7340,11 @@ e1000_get_phy_cfg_done(struct e1000_hw *hw) default: msec_delay(10); break; + case e1000_80003es2lan: + /* Separate *_CFG_DONE_* bit for each port */ + if (E1000_READ_REG(hw, STATUS) & E1000_STATUS_FUNC_1) + cfg_mask = E1000_EEPROM_CFG_DONE_PORT_1; + /* Fall Through */ case e1000_82571: case e1000_82572: while (timeout) { @@ -6805,6 +7387,11 @@ e1000_get_hw_eeprom_semaphore(struct e1000_hw *hw) if(!hw->eeprom_semaphore_present) return E1000_SUCCESS; + if (hw->mac_type == e1000_80003es2lan) { + /* Get the SW semaphore. */ + if (e1000_get_software_semaphore(hw) != E1000_SUCCESS) + return -E1000_ERR_EEPROM; + } /* Get the FW semaphore. */ timeout = hw->eeprom.word_size + 1; @@ -6850,10 +7437,75 @@ e1000_put_hw_eeprom_semaphore(struct e1000_hw *hw) return; swsm = E1000_READ_REG(hw, SWSM); + if (hw->mac_type == e1000_80003es2lan) { + /* Release both semaphores. */ + swsm &= ~(E1000_SWSM_SMBI | E1000_SWSM_SWESMBI); + } else swsm &= ~(E1000_SWSM_SWESMBI); E1000_WRITE_REG(hw, SWSM, swsm); } +/*************************************************************************** + * + * Obtaining software semaphore bit (SMBI) before resetting PHY. + * + * hw: Struct containing variables accessed by shared code + * + * returns: - E1000_ERR_RESET if fail to obtain semaphore. + * E1000_SUCCESS at any other case. + * + ***************************************************************************/ +int32_t +e1000_get_software_semaphore(struct e1000_hw *hw) +{ + int32_t timeout = hw->eeprom.word_size + 1; + uint32_t swsm; + + DEBUGFUNC("e1000_get_software_semaphore"); + + if (hw->mac_type != e1000_80003es2lan) + return E1000_SUCCESS; + + while(timeout) { + swsm = E1000_READ_REG(hw, SWSM); + /* If SMBI bit cleared, it is now set and we hold the semaphore */ + if(!(swsm & E1000_SWSM_SMBI)) + break; + msec_delay_irq(1); + timeout--; + } + + if(!timeout) { + DEBUGOUT("Driver can't access device - SMBI bit is set.\n"); + return -E1000_ERR_RESET; + } + + return E1000_SUCCESS; +} + +/*************************************************************************** + * + * Release semaphore bit (SMBI). + * + * hw: Struct containing variables accessed by shared code + * + ***************************************************************************/ +void +e1000_release_software_semaphore(struct e1000_hw *hw) +{ + uint32_t swsm; + + DEBUGFUNC("e1000_release_software_semaphore"); + + if (hw->mac_type != e1000_80003es2lan) + return; + + swsm = E1000_READ_REG(hw, SWSM); + /* Release the SW semaphores.*/ + swsm &= ~E1000_SWSM_SMBI; + E1000_WRITE_REG(hw, SWSM, swsm); +} + /****************************************************************************** * Checks if PHY reset is blocked due to SOL/IDER session, for example. * Returning E1000_BLK_PHY_RESET isn't necessarily an error. But it's up to @@ -6890,6 +7542,7 @@ e1000_arc_subsystem_valid(struct e1000_hw *hw) case e1000_82571: case e1000_82572: case e1000_82573: + case e1000_80003es2lan: fwsm = E1000_READ_REG(hw, FWSM); if((fwsm & E1000_FWSM_MODE_MASK) != 0) return TRUE; -- cgit v1.1