📄 e1000_phy.c
字号:
/******************************************************************************* Intel PRO/1000 Linux driver Copyright(c) 1999 - 2008 Intel Corporation. This program is free software; you can redistribute it and/or modify it under the terms and conditions of the GNU General Public License, version 2, as published by the Free Software Foundation. This program is distributed in the hope 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 "COPYING". Contact Information: Linux NICS <linux.nics@intel.com> e1000-devel Mailing List <e1000-devel@lists.sourceforge.net> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************/#include "e1000_api.h"#include "e1000_phy.h"static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw);static void e1000_release_phy(struct e1000_hw *hw);static s32 e1000_acquire_phy(struct e1000_hw *hw);/* Cable length tables */static const u16 e1000_m88_cable_length_table[] = { 0, 50, 80, 110, 140, 140, E1000_CABLE_LENGTH_UNDEFINED };#define M88E1000_CABLE_LENGTH_TABLE_SIZE \ (sizeof(e1000_m88_cable_length_table) / \ sizeof(e1000_m88_cable_length_table[0]))static const u16 e1000_igp_2_cable_length_table[] = { 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11, 13, 16, 18, 21, 0, 0, 0, 3, 6, 10, 13, 16, 19, 23, 26, 29, 32, 35, 38, 41, 6, 10, 14, 18, 22, 26, 30, 33, 37, 41, 44, 48, 51, 54, 58, 61, 21, 26, 31, 35, 40, 44, 49, 53, 57, 61, 65, 68, 72, 75, 79, 82, 40, 45, 51, 56, 61, 66, 70, 75, 79, 83, 87, 91, 94, 98, 101, 104, 60, 66, 72, 77, 82, 87, 92, 96, 100, 104, 108, 111, 114, 117, 119, 121, 83, 89, 95, 100, 105, 109, 113, 116, 119, 122, 124, 104, 109, 114, 118, 121, 124};#define IGP02E1000_CABLE_LENGTH_TABLE_SIZE \ (sizeof(e1000_igp_2_cable_length_table) / \ sizeof(e1000_igp_2_cable_length_table[0]))/** * e1000_check_reset_block_generic - Check if PHY reset is blocked * @hw: pointer to the HW structure * * Read the PHY management control register and check whether a PHY reset * is blocked. If a reset is not blocked return E1000_SUCCESS, otherwise * return E1000_BLK_PHY_RESET (12). **/s32 e1000_check_reset_block_generic(struct e1000_hw *hw){ u32 manc; DEBUGFUNC("e1000_check_reset_block"); manc = E1000_READ_REG(hw, E1000_MANC); return (manc & E1000_MANC_BLK_PHY_RST_ON_IDE) ? E1000_BLK_PHY_RESET : E1000_SUCCESS;}/** * e1000_get_phy_id - Retrieve the PHY ID and revision * @hw: pointer to the HW structure * * Reads the PHY registers and stores the PHY ID and possibly the PHY * revision in the hardware structure. **/s32 e1000_get_phy_id(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val = E1000_SUCCESS; u16 phy_id; DEBUGFUNC("e1000_get_phy_id"); ret_val = e1000_read_phy_reg(hw, PHY_ID1, &phy_id); if (ret_val) goto out; phy->id = (u32)(phy_id << 16); usec_delay(20); ret_val = e1000_read_phy_reg(hw, PHY_ID2, &phy_id); if (ret_val) goto out; phy->id |= (u32)(phy_id & PHY_REVISION_MASK); phy->revision = (u32)(phy_id & ~PHY_REVISION_MASK);out: return ret_val;}/** * e1000_phy_reset_dsp_generic - Reset PHY DSP * @hw: pointer to the HW structure * * Reset the digital signal processor. **/s32 e1000_phy_reset_dsp_generic(struct e1000_hw *hw){ s32 ret_val; DEBUGFUNC("e1000_phy_reset_dsp_generic"); ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0xC1); if (ret_val) goto out; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_GEN_CONTROL, 0);out: return ret_val;}/** * e1000_read_phy_reg_mdic - Read MDI control register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data * * Reads the MDI control regsiter in the PHY at offset and stores the * information read to data. **/s32 e1000_read_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 *data){ struct e1000_phy_info *phy = &hw->phy; u32 i, mdic = 0; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_read_phy_reg_mdic"); if (offset > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", offset); ret_val = -E1000_ERR_PARAM; goto out; } /* * Set up Op-code, Phy Address, and register offset in the MDI * Control register. The MAC will take care of interfacing with the * PHY to retrieve the desired data. */ mdic = ((offset << E1000_MDIC_REG_SHIFT) | (phy->addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_READ)); E1000_WRITE_REG(hw, E1000_MDIC, mdic); /* * Poll the ready bit to see if the MDI read completed * Increasing the time out as testing showed failures with * the lower time out */ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { usec_delay(50); mdic = E1000_READ_REG(hw, E1000_MDIC); if (mdic & E1000_MDIC_READY) break; } if (!(mdic & E1000_MDIC_READY)) { DEBUGOUT("MDI Read did not complete\n"); ret_val = -E1000_ERR_PHY; goto out; } if (mdic & E1000_MDIC_ERROR) { DEBUGOUT("MDI Error\n"); ret_val = -E1000_ERR_PHY; goto out; } *data = (u16) mdic;out: return ret_val;}/** * e1000_write_phy_reg_mdic - Write MDI control register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write to register at offset * * Writes data to MDI control register in the PHY at offset. **/s32 e1000_write_phy_reg_mdic(struct e1000_hw *hw, u32 offset, u16 data){ struct e1000_phy_info *phy = &hw->phy; u32 i, mdic = 0; s32 ret_val = E1000_SUCCESS; DEBUGFUNC("e1000_write_phy_reg_mdic"); if (offset > MAX_PHY_REG_ADDRESS) { DEBUGOUT1("PHY Address %d is out of range\n", offset); ret_val = -E1000_ERR_PARAM; goto out; } /* * Set up Op-code, Phy Address, and register offset in the MDI * Control register. The MAC will take care of interfacing with the * PHY to retrieve the desired data. */ mdic = (((u32)data) | (offset << E1000_MDIC_REG_SHIFT) | (phy->addr << E1000_MDIC_PHY_SHIFT) | (E1000_MDIC_OP_WRITE)); E1000_WRITE_REG(hw, E1000_MDIC, mdic); /* * Poll the ready bit to see if the MDI read completed * Increasing the time out as testing showed failures with * the lower time out */ for (i = 0; i < (E1000_GEN_POLL_TIMEOUT * 3); i++) { usec_delay(50); mdic = E1000_READ_REG(hw, E1000_MDIC); if (mdic & E1000_MDIC_READY) break; } if (!(mdic & E1000_MDIC_READY)) { DEBUGOUT("MDI Write did not complete\n"); ret_val = -E1000_ERR_PHY; goto out; } if (mdic & E1000_MDIC_ERROR) { DEBUGOUT("MDI Error\n"); ret_val = -E1000_ERR_PHY; goto out; }out: return ret_val;}/** * e1000_read_phy_reg_m88 - Read m88 PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data * * Acquires semaphore, if necessary, then reads the PHY register at offset * and storing the retrieved information in data. Release any acquired * semaphores before exiting. **/s32 e1000_read_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 *data){ s32 ret_val; DEBUGFUNC("e1000_read_phy_reg_m88"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); e1000_release_phy(hw);out: return ret_val;}/** * e1000_write_phy_reg_m88 - Write m88 PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. **/s32 e1000_write_phy_reg_m88(struct e1000_hw *hw, u32 offset, u16 data){ s32 ret_val; DEBUGFUNC("e1000_write_phy_reg_m88"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); e1000_release_phy(hw);out: return ret_val;}/** * e1000_read_phy_reg_igp - Read igp PHY register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data * * Acquires semaphore, if necessary, then reads the PHY register at offset * and storing the retrieved information in data. Release any acquired * semaphores before exiting. **/s32 e1000_read_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 *data){ s32 ret_val; DEBUGFUNC("e1000_read_phy_reg_igp"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, (u16)offset); if (ret_val) { e1000_release_phy(hw); goto out; } } ret_val = e1000_read_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); e1000_release_phy(hw);out: return ret_val;}/** * e1000_write_phy_reg_igp - Write igp PHY register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset * * Acquires semaphore, if necessary, then writes the data to PHY register * at the offset. Release any acquired semaphores before exiting. **/s32 e1000_write_phy_reg_igp(struct e1000_hw *hw, u32 offset, u16 data){ s32 ret_val; DEBUGFUNC("e1000_write_phy_reg_igp"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; if (offset > MAX_PHY_MULTI_PAGE_REG) { ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, (u16)offset); if (ret_val) { e1000_release_phy(hw); goto out; } } ret_val = e1000_write_phy_reg_mdic(hw, MAX_PHY_REG_ADDRESS & offset, data); e1000_release_phy(hw);out: return ret_val;}/** * e1000_read_kmrn_reg_generic - Read kumeran register * @hw: pointer to the HW structure * @offset: register offset to be read * @data: pointer to the read data * * Acquires semaphore, if necessary. Then reads the PHY register at offset * using the kumeran interface. The information retrieved is stored in data. * Release any acquired semaphores before exiting. **/s32 e1000_read_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 *data){ u32 kmrnctrlsta; s32 ret_val; DEBUGFUNC("e1000_read_kmrn_reg_generic"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); usec_delay(2); kmrnctrlsta = E1000_READ_REG(hw, E1000_KMRNCTRLSTA); *data = (u16)kmrnctrlsta; e1000_release_phy(hw);out: return ret_val;}/** * e1000_write_kmrn_reg_generic - Write kumeran register * @hw: pointer to the HW structure * @offset: register offset to write to * @data: data to write at register offset * * Acquires semaphore, if necessary. Then write the data to PHY register * at the offset using the kumeran interface. Release any acquired semaphores * before exiting. **/s32 e1000_write_kmrn_reg_generic(struct e1000_hw *hw, u32 offset, u16 data){ u32 kmrnctrlsta; s32 ret_val; DEBUGFUNC("e1000_write_kmrn_reg_generic"); ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & E1000_KMRNCTRLSTA_OFFSET) | data; E1000_WRITE_REG(hw, E1000_KMRNCTRLSTA, kmrnctrlsta); usec_delay(2); e1000_release_phy(hw);out: return ret_val;}/** * e1000_copper_link_setup_m88 - Setup m88 PHY's for copper link * @hw: pointer to the HW structure * * Sets up MDI/MDI-X and polarity for m88 PHY's. If necessary, transmit clock * and downshift values are set also. **/s32 e1000_copper_link_setup_m88(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 phy_data; DEBUGFUNC("e1000_copper_link_setup_m88"); if (phy->reset_disable) { ret_val = E1000_SUCCESS; goto out; } /* Enable CRS on TX. This must be set for half-duplex operation. */ ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) goto out; 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 (phy->mdix) { case 1: phy_data |= M88E1000_PSCR_MDI_MANUAL_MODE; break; case 2: phy_data |= M88E1000_PSCR_MDIX_MANUAL_MODE; break; case 3: 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 (phy->disable_polarity_correction == 1) phy_data |= M88E1000_PSCR_POLARITY_REVERSAL; ret_val = e1000_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, phy_data); if (ret_val) goto out; if (phy->revision < E1000_REVISION_4) { /* * Force TX_CLK in the Extended PHY Specific Control Register
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -