e1000/base: i210 PLL workaround

Signed-off-by: Jijiang Liu <jijiang.liu@intel.com>
Acked-by: Helin Zhang <helin.zhang@intel.com>
Tested-by: Waterman Cao <waterman.cao@intel.com>
[Thomas: split code drop]
This commit is contained in:
Jijiang Liu 2014-06-18 12:28:10 +02:00 committed by Thomas Monjalon
parent a304e6ed52
commit 95fe5e10ee
5 changed files with 103 additions and 2 deletions

View File

@ -55,7 +55,6 @@ STATIC s32 e1000_check_for_link_media_swap(struct e1000_hw *hw);
STATIC s32 e1000_get_cfg_done_82575(struct e1000_hw *hw);
STATIC s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
u16 *duplex);
STATIC s32 e1000_init_hw_82575(struct e1000_hw *hw);
STATIC s32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
STATIC s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
u16 *data);
@ -449,6 +448,9 @@ STATIC s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
else
mac->ops.reset_hw = e1000_reset_hw_82575;
/* hw initialization */
if ((mac->type == e1000_i210) || (mac->type == e1000_i211))
mac->ops.init_hw = e1000_init_hw_i210;
else
mac->ops.init_hw = e1000_init_hw_82575;
/* link setup */
mac->ops.setup_link = e1000_setup_link_generic;
@ -1460,7 +1462,7 @@ STATIC s32 e1000_reset_hw_82575(struct e1000_hw *hw)
*
* This inits the hardware readying it for operation.
**/
STATIC s32 e1000_init_hw_82575(struct e1000_hw *hw)
s32 e1000_init_hw_82575(struct e1000_hw *hw)
{
struct e1000_mac_info *mac = &hw->mac;
s32 ret_val;

View File

@ -479,6 +479,7 @@ void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable);
void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf);
void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable);
s32 e1000_init_nvm_params_82575(struct e1000_hw *hw);
s32 e1000_init_hw_82575(struct e1000_hw *hw);
enum e1000_promisc_type {
e1000_promisc_disabled = 0, /* all promisc modes disabled */

View File

@ -76,6 +76,7 @@ POSSIBILITY OF SUCH DAMAGE.
#define E1000_CTRL_EXT_EE_RST 0x00002000 /* Reinitialize from EEPROM */
/* Physical Func Reset Done Indication */
#define E1000_CTRL_EXT_PFRSTD 0x00004000
#define E1000_CTRL_EXT_SDLPE 0X00040000 /* SerDes Low Power Enable */
#define E1000_CTRL_EXT_SPD_BYPS 0x00008000 /* Speed Select Bypass */
#define E1000_CTRL_EXT_RO_DIS 0x00020000 /* Relaxed Ordering disable */
#define E1000_CTRL_EXT_DMA_DYN_CLK_EN 0x00080000 /* DMA Dynamic Clk Gating */

View File

@ -914,3 +914,87 @@ s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr, u16 data)
return __e1000_access_xmdio_reg(hw, addr, dev_addr, &data, false);
}
/**
* e1000_pll_workaround_i210
* @hw: pointer to the HW structure
*
* Works around an errata in the PLL circuit where it occasionally
* provides the wrong clock frequency after power up.
**/
STATIC s32 e1000_pll_workaround_i210(struct e1000_hw *hw)
{
s32 ret_val;
u32 wuc, mdicnfg, ctrl_ext, reg_val;
u16 nvm_word, phy_word, pci_word, tmp_nvm;
int i;
/* Get and set needed register values */
wuc = E1000_READ_REG(hw, E1000_WUC);
mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
reg_val = mdicnfg & ~E1000_MDICNFG_EXT_MDIO;
E1000_WRITE_REG(hw, E1000_MDICNFG, reg_val);
/* Get data from NVM, or set default */
ret_val = e1000_read_invm_word_i210(hw, E1000_INVM_AUTOLOAD,
&nvm_word);
if (ret_val != E1000_SUCCESS)
nvm_word = E1000_INVM_DEFAULT_AL;
tmp_nvm = nvm_word | E1000_INVM_PLL_WO_VAL;
for (i = 0; i < E1000_MAX_PLL_TRIES; i++) {
/* check current state */
hw->phy.ops.read_reg(hw, (E1000_PHY_PLL_FREQ_PAGE |
E1000_PHY_PLL_FREQ_REG), &phy_word);
if ((phy_word & E1000_PHY_PLL_UNCONF)
!= E1000_PHY_PLL_UNCONF) {
ret_val = E1000_SUCCESS;
break;
} else {
ret_val = -E1000_ERR_PHY;
}
hw->phy.ops.reset(hw);
ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
ctrl_ext |= (E1000_CTRL_EXT_PHYPDEN | E1000_CTRL_EXT_SDLPE);
E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
E1000_WRITE_REG(hw, E1000_WUC, 0);
reg_val = (E1000_INVM_AUTOLOAD << 4) | (tmp_nvm << 16);
E1000_WRITE_REG(hw, E1000_EEARBC, reg_val);
e1000_read_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
pci_word |= E1000_PCI_PMCSR_D3;
e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
msec_delay(1);
pci_word &= ~E1000_PCI_PMCSR_D3;
e1000_write_pci_cfg(hw, E1000_PCI_PMCSR, &pci_word);
reg_val = (E1000_INVM_AUTOLOAD << 4) | (nvm_word << 16);
E1000_WRITE_REG(hw, E1000_EEARBC, reg_val);
/* restore WUC register */
E1000_WRITE_REG(hw, E1000_WUC, wuc);
}
/* restore MDICNFG setting */
E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
return ret_val;
}
/**
* e1000_init_hw_i210 - Init hw for I210/I211
* @hw: pointer to the HW structure
*
* Called to initialize hw for i210 hw family.
**/
s32 e1000_init_hw_i210(struct e1000_hw *hw)
{
s32 ret_val;
DEBUGFUNC("e1000_init_hw_i210");
if ((hw->mac.type >= e1000_i210) &&
!(e1000_get_flash_presence_i210(hw))) {
ret_val = e1000_pll_workaround_i210(hw);
if (ret_val != E1000_SUCCESS)
return ret_val;
}
ret_val = e1000_init_hw_82575(hw);
return ret_val;
}

View File

@ -50,6 +50,7 @@ s32 e1000_read_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
u16 *data);
s32 e1000_write_xmdio_reg(struct e1000_hw *hw, u16 addr, u8 dev_addr,
u16 data);
s32 e1000_init_hw_i210(struct e1000_hw *hw);
#define E1000_STM_OPCODE 0xDB00
#define E1000_EEPROM_FLASH_SIZE_WORD 0x11
@ -94,4 +95,16 @@ enum E1000_INVM_STRUCTURE_TYPE {
#define NVM_INIT_CTRL_4_DEFAULT_I211 0x00C1
#define NVM_LED_1_CFG_DEFAULT_I211 0x0184
#define NVM_LED_0_2_CFG_DEFAULT_I211 0x200C
/* PLL Defines */
#define E1000_PCI_PMCSR 0x44
#define E1000_PCI_PMCSR_D3 0x03
#define E1000_MAX_PLL_TRIES 5
#define E1000_PHY_PLL_UNCONF 0xFF
#define E1000_PHY_PLL_FREQ_PAGE 0xFC0000
#define E1000_PHY_PLL_FREQ_REG 0x000E
#define E1000_INVM_DEFAULT_AL 0x202F
#define E1000_INVM_AUTOLOAD 0x0A
#define E1000_INVM_PLL_WO_VAL 0x0010
#endif