📄 e1000_phy.c
字号:
* cable. By reading the AGC registers, which reperesent the * cobination of course and fine gain value, the value can be put * into a lookup table to obtain the approximate cable length * for each channel. **/s32 e1000_get_cable_length_igp_2(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val = E1000_SUCCESS; u16 phy_data, i, agc_value = 0; u16 cur_agc_index, max_agc_index = 0; u16 min_agc_index = IGP02E1000_CABLE_LENGTH_TABLE_SIZE - 1; u16 agc_reg_array[IGP02E1000_PHY_CHANNEL_NUM] = {IGP02E1000_PHY_AGC_A, IGP02E1000_PHY_AGC_B, IGP02E1000_PHY_AGC_C, IGP02E1000_PHY_AGC_D}; DEBUGFUNC("e1000_get_cable_length_igp_2"); /* Read the AGC registers for all channels */ for (i = 0; i < IGP02E1000_PHY_CHANNEL_NUM; i++) { ret_val = e1000_read_phy_reg(hw, agc_reg_array[i], &phy_data); if (ret_val) goto out; /* * Getting bits 15:9, which represent the combination of * course and fine gain values. The result is a number * that can be put into the lookup table to obtain the * approximate cable length. */ cur_agc_index = (phy_data >> IGP02E1000_AGC_LENGTH_SHIFT) & IGP02E1000_AGC_LENGTH_MASK; /* Array index bound check. */ if ((cur_agc_index >= IGP02E1000_CABLE_LENGTH_TABLE_SIZE) || (cur_agc_index == 0)) { ret_val = -E1000_ERR_PHY; goto out; } /* Remove min & max AGC values from calculation. */ if (e1000_igp_2_cable_length_table[min_agc_index] > e1000_igp_2_cable_length_table[cur_agc_index]) min_agc_index = cur_agc_index; if (e1000_igp_2_cable_length_table[max_agc_index] < e1000_igp_2_cable_length_table[cur_agc_index]) max_agc_index = cur_agc_index; agc_value += e1000_igp_2_cable_length_table[cur_agc_index]; } agc_value -= (e1000_igp_2_cable_length_table[min_agc_index] + e1000_igp_2_cable_length_table[max_agc_index]); agc_value /= (IGP02E1000_PHY_CHANNEL_NUM - 2); /* Calculate cable length with the error range of +/- 10 meters. */ phy->min_cable_length = ((agc_value - IGP02E1000_AGC_RANGE) > 0) ? (agc_value - IGP02E1000_AGC_RANGE) : 0; phy->max_cable_length = agc_value + IGP02E1000_AGC_RANGE; phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;out: return ret_val;}/** * e1000_get_phy_info_m88 - Retrieve PHY information * @hw: pointer to the HW structure * * Valid for only copper links. Read the PHY status register (sticky read) * to verify that link is up. Read the PHY special control register to * determine the polarity and 10base-T extended distance. Read the PHY * special status register to determine MDI/MDIx and current speed. If * speed is 1000, then determine cable length, local and remote receiver. **/s32 e1000_get_phy_info_m88(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 phy_data; bool link; DEBUGFUNC("e1000_get_phy_info_m88"); if (hw->phy.media_type != e1000_media_type_copper) { DEBUGOUT("Phy info is only valid for copper media\n"); ret_val = -E1000_ERR_CONFIG; goto out; } ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); if (ret_val) goto out; if (!link) { DEBUGOUT("Phy info is only valid if link is up\n"); ret_val = -E1000_ERR_CONFIG; goto out; } ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, &phy_data); if (ret_val) goto out; phy->polarity_correction = (phy_data & M88E1000_PSCR_POLARITY_REVERSAL) ? TRUE : FALSE; ret_val = e1000_check_polarity_m88(hw); if (ret_val) goto out; ret_val = e1000_read_phy_reg(hw, M88E1000_PHY_SPEC_STATUS, &phy_data); if (ret_val) goto out; phy->is_mdix = (phy_data & M88E1000_PSSR_MDIX) ? TRUE : FALSE; if ((phy_data & M88E1000_PSSR_SPEED) == M88E1000_PSSR_1000MBS) { ret_val = e1000_get_cable_length(hw); if (ret_val) goto out; ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &phy_data); if (ret_val) goto out; phy->local_rx = (phy_data & SR_1000T_LOCAL_RX_STATUS) ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; phy->remote_rx = (phy_data & SR_1000T_REMOTE_RX_STATUS) ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; } else { /* Set values to "undefined" */ phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; phy->local_rx = e1000_1000t_rx_status_undefined; phy->remote_rx = e1000_1000t_rx_status_undefined; }out: return ret_val;}/** * e1000_get_phy_info_igp - Retrieve igp PHY information * @hw: pointer to the HW structure * * Read PHY status to determine if link is up. If link is up, then * set/determine 10base-T extended distance and polarity correction. Read * PHY port status to determine MDI/MDIx and speed. Based on the speed, * determine on the cable length, local and remote receiver. **/s32 e1000_get_phy_info_igp(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u16 data; bool link; DEBUGFUNC("e1000_get_phy_info_igp"); ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link); if (ret_val) goto out; if (!link) { DEBUGOUT("Phy info is only valid if link is up\n"); ret_val = -E1000_ERR_CONFIG; goto out; } phy->polarity_correction = TRUE; ret_val = e1000_check_polarity_igp(hw); if (ret_val) goto out; ret_val = e1000_read_phy_reg(hw, IGP01E1000_PHY_PORT_STATUS, &data); if (ret_val) goto out; phy->is_mdix = (data & IGP01E1000_PSSR_MDIX) ? TRUE : FALSE; if ((data & IGP01E1000_PSSR_SPEED_MASK) == IGP01E1000_PSSR_SPEED_1000MBPS) { ret_val = e1000_get_cable_length(hw); if (ret_val) goto out; ret_val = e1000_read_phy_reg(hw, PHY_1000T_STATUS, &data); if (ret_val) goto out; phy->local_rx = (data & SR_1000T_LOCAL_RX_STATUS) ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; phy->remote_rx = (data & SR_1000T_REMOTE_RX_STATUS) ? e1000_1000t_rx_status_ok : e1000_1000t_rx_status_not_ok; } else { phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED; phy->local_rx = e1000_1000t_rx_status_undefined; phy->remote_rx = e1000_1000t_rx_status_undefined; }out: return ret_val;}/** * e1000_phy_sw_reset_generic - PHY software reset * @hw: pointer to the HW structure * * Does a software reset of the PHY by reading the PHY control register and * setting/write the control register reset bit to the PHY. **/s32 e1000_phy_sw_reset_generic(struct e1000_hw *hw){ s32 ret_val; u16 phy_ctrl; DEBUGFUNC("e1000_phy_sw_reset_generic"); ret_val = e1000_read_phy_reg(hw, PHY_CONTROL, &phy_ctrl); if (ret_val) goto out; phy_ctrl |= MII_CR_RESET; ret_val = e1000_write_phy_reg(hw, PHY_CONTROL, phy_ctrl); if (ret_val) goto out; usec_delay(1);out: return ret_val;}/** * e1000_phy_hw_reset_generic - PHY hardware reset * @hw: pointer to the HW structure * * Verify the reset block is not blocking us from resetting. Acquire * semaphore (if necessary) and read/set/write the device control reset * bit in the PHY. Wait the appropriate delay time for the device to * reset and relase the semaphore (if necessary). **/s32 e1000_phy_hw_reset_generic(struct e1000_hw *hw){ struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u32 ctrl; DEBUGFUNC("e1000_phy_hw_reset_generic"); ret_val = e1000_check_reset_block(hw); if (ret_val) { ret_val = E1000_SUCCESS; goto out; } ret_val = e1000_acquire_phy(hw); if (ret_val) goto out; ctrl = E1000_READ_REG(hw, E1000_CTRL); E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_PHY_RST); E1000_WRITE_FLUSH(hw); usec_delay(phy->reset_delay_us); E1000_WRITE_REG(hw, E1000_CTRL, ctrl); E1000_WRITE_FLUSH(hw); usec_delay(150); e1000_release_phy(hw); ret_val = e1000_get_phy_cfg_done(hw);out: return ret_val;}/** * e1000_get_cfg_done_generic - Generic configuration done * @hw: pointer to the HW structure * * Generic function to wait 10 milli-seconds for configuration to complete * and return success. **/s32 e1000_get_cfg_done_generic(struct e1000_hw *hw){ DEBUGFUNC("e1000_get_cfg_done_generic"); msec_delay_irq(10); return E1000_SUCCESS;}/* Internal function pointers *//** * e1000_get_phy_cfg_done - Generic PHY configuration done * @hw: pointer to the HW structure * * Return success if silicon family did not implement a family specific * get_cfg_done function. **/static s32 e1000_get_phy_cfg_done(struct e1000_hw *hw){ if (hw->func.get_cfg_done) return hw->func.get_cfg_done(hw); return E1000_SUCCESS;}/** * e1000_release_phy - Generic release PHY * @hw: pointer to the HW structure * * Return if silicon family does not require a semaphore when accessing the * PHY. **/static void e1000_release_phy(struct e1000_hw *hw){ if (hw->func.release_phy) hw->func.release_phy(hw);}/** * e1000_acquire_phy - Generic acquire PHY * @hw: pointer to the HW structure * * Return success if silicon family does not require a semaphore when * accessing the PHY. **/static s32 e1000_acquire_phy(struct e1000_hw *hw){ if (hw->func.acquire_phy) return hw->func.acquire_phy(hw); return E1000_SUCCESS;}/** * e1000_phy_force_speed_duplex - Generic force PHY speed/duplex * @hw: pointer to the HW structure * * When the silicon family has not implemented a forced speed/duplex * function for the PHY, simply return E1000_SUCCESS. **/s32 e1000_phy_force_speed_duplex(struct e1000_hw *hw){ if (hw->func.force_speed_duplex) return hw->func.force_speed_duplex(hw); return E1000_SUCCESS;}/** * e1000_phy_init_script_igp3 - Inits the IGP3 PHY * @hw: pointer to the HW structure * * Initializes a Intel Gigabit PHY3 when an EEPROM is not present. **/s32 e1000_phy_init_script_igp3(struct e1000_hw *hw){ DEBUGOUT("Running IGP 3 PHY init script\n"); /* PHY init IGP 3 */ /* Enable rise/fall, 10-mode work in class-A */ e1000_write_phy_reg(hw, 0x2F5B, 0x9018); /* Remove all caps from Replica path filter */ e1000_write_phy_reg(hw, 0x2F52, 0x0000); /* Bias trimming for ADC, AFE and Driver (Default) */ e1000_write_phy_reg(hw, 0x2FB1, 0x8B24); /* Increase Hybrid poly bias */ e1000_write_phy_reg(hw, 0x2FB2, 0xF8F0); /* Add 4% to Tx amplitude in Giga mode */ e1000_write_phy_reg(hw, 0x2010, 0x10B0); /* Disable trimming (TTT) */ e1000_write_phy_reg(hw, 0x2011, 0x0000); /* Poly DC correction to 94.6% + 2% for all channels */ e1000_write_phy_reg(hw, 0x20DD, 0x249A); /* ABS DC correction to 95.9% */ e1000_write_phy_reg(hw, 0x20DE, 0x00D3); /* BG temp curve trim */ e1000_write_phy_reg(hw, 0x28B4, 0x04CE); /* Increasing ADC OPAMP stage 1 currents to max */ e1000_write_phy_reg(hw, 0x2F70, 0x29E4); /* Force 1000 ( required for enabling PHY regs configuration) */ e1000_write_phy_reg(hw, 0x0000, 0x0140); /* Set upd_freq to 6 */ e1000_write_phy_reg(hw, 0x1F30, 0x1606); /* Disable NPDFE */ e1000_write_phy_reg(hw, 0x1F31, 0xB814); /* Disable adaptive fixed FFE (Default) */ e1000_write_phy_reg(hw, 0x1F35, 0x002A); /* Enable FFE hysteresis */ e1000_write_phy_reg(hw, 0x1F3E, 0x0067); /* Fixed FFE for short cable lengths */ e1000_write_phy_reg(hw, 0x1F54, 0x0065); /* Fixed FFE for medium cable lengths */ e1000_write_phy_reg(hw, 0x1F55, 0x002A); /* Fixed FFE for long cable lengths */ e1000_write_phy_reg(hw, 0x1F56, 0x002A); /* Enable Adaptive Clip Threshold */ e1000_write_phy_reg(hw, 0x1F72, 0x3FB0); /* AHT reset limit to 1 */ e1000_write_phy_reg(hw, 0x1F76, 0xC0FF); /* Set AHT master delay to 127 msec */ e1000_write_phy_reg(hw, 0x1F77, 0x1DEC); /* Set scan bits for AHT */ e1000_write_phy_reg(hw, 0x1F78, 0xF9EF); /* Set AHT Preset bits */ e1000_write_phy_reg(hw, 0x1F79, 0x0210); /* Change integ_factor of channel A to 3 */ e1000_write_phy_reg(hw, 0x1895, 0x0003); /* Change prop_factor of channels BCD to 8 */ e1000_write_phy_reg(hw, 0x1796, 0x0008); /* Change cg_icount + enable integbp for channels BCD */ e1000_write_phy_reg(hw, 0x1798, 0xD008); /* * Change cg_icount + enable integbp + change prop_factor_master * to 8 for channel A */ e1000_write_phy_reg(hw, 0x1898, 0xD918); /* Disable AHT in Slave mode on channel A */ e1000_write_phy_reg(hw, 0x187A, 0x0800); /* * Enable LPLU and disable AN to 1000 in non-D0a states, * Enable SPD+B2B */ e1000_write_phy_reg(hw, 0x0019, 0x008D); /* Enable restart AN on an1000_dis change */ e1000_write_phy_reg(hw, 0x001B, 0x2080); /* Enable wh_fifo read clock in 10/100 modes */ e1000_write_phy_reg(hw, 0x0014, 0x0045); /* Restart AN, Speed selection is 1000 */ e1000_write_phy_reg(hw, 0x0000, 0x1340); return E1000_SUCCESS;}/** * e1000_get_phy_type_from_id - Get PHY type from id * @phy_id: phy_id read from the phy * * Returns the phy type from the id. **/e1000_phy_type e1000_get_phy_type_from_id(u32 phy_id){ e1000_phy_type phy_type = e1000_phy_unknown; switch (phy_id) { case M88E1000_I_PHY_ID: case M88E1000_E_PHY_ID: case M88E1111_I_PHY_ID: case M88E1011_I_PHY_ID: phy_type = e1000_phy_m88; break; case IGP01E1000_I_PHY_ID: /* IGP 1 & 2 share this */ phy_type = e1000_phy_igp_2; break; case GG82563_E_PHY_ID: phy_type = e1000_phy_gg82563; break; case IGP03E1000_E_PHY_ID: phy_type = e1000_phy_igp_3; break; case IFE_E_PHY_ID: case IFE_PLUS_E_PHY_ID: case IFE_C_E_PHY_ID: phy_type = e1000_phy_ife; break; default: phy_type = e1000_phy_unknown; break; } return phy_type;}/** * e1000_power_up_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_up_phy_copper(struct e1000_hw *hw){ u16 mii_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ e1000_read_phy_reg(hw, PHY_CONTROL, &mii_reg); mii_reg &= ~MII_CR_POWER_DOWN; e1000_write_phy_reg(hw, PHY_CONTROL, mii_reg);}/** * e1000_power_down_phy_copper - Restore copper link in case of PHY power down * @hw: pointer to the HW structure * * In the case of a PHY power down to save power, or to turn off link during a * driver unload, or wake on lan is not enabled, restore the link to previous * settings. **/void e1000_power_down_phy_copper(struct e1000_hw *hw){ u16 mii_reg = 0; /* The PHY will retain its settings across a power down/up cycle */ e1000_read_phy_reg(hw, PHY_CONTROL, &mii_reg); mii_reg |= MII_CR_POWER_DOWN; e1000_write_phy_reg(hw, PHY_CONTROL, mii_reg); msec_delay(1);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -