xref: /freebsd/sys/dev/e1000/e1000_82541.c (revision 8cfa0ad2)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
38cfa0ad2SJack F Vogel   Copyright (c) 2001-2008, Intel Corporation
48cfa0ad2SJack F Vogel   All rights reserved.
58cfa0ad2SJack F Vogel 
68cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
78cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
88cfa0ad2SJack F Vogel 
98cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
108cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
118cfa0ad2SJack F Vogel 
128cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
138cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
148cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
158cfa0ad2SJack F Vogel 
168cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
178cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
188cfa0ad2SJack F Vogel       this software without specific prior written permission.
198cfa0ad2SJack F Vogel 
208cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
318cfa0ad2SJack F Vogel 
328cfa0ad2SJack F Vogel ******************************************************************************/
338cfa0ad2SJack F Vogel /*$FreeBSD$*/
348cfa0ad2SJack F Vogel 
358cfa0ad2SJack F Vogel /* e1000_82541
368cfa0ad2SJack F Vogel  * e1000_82547
378cfa0ad2SJack F Vogel  * e1000_82541_rev_2
388cfa0ad2SJack F Vogel  * e1000_82547_rev_2
398cfa0ad2SJack F Vogel  */
408cfa0ad2SJack F Vogel 
418cfa0ad2SJack F Vogel #include "e1000_api.h"
428cfa0ad2SJack F Vogel 
438cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_82541(struct e1000_hw *hw);
448cfa0ad2SJack F Vogel static s32  e1000_init_nvm_params_82541(struct e1000_hw *hw);
458cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_82541(struct e1000_hw *hw);
468cfa0ad2SJack F Vogel static s32  e1000_reset_hw_82541(struct e1000_hw *hw);
478cfa0ad2SJack F Vogel static s32  e1000_init_hw_82541(struct e1000_hw *hw);
488cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
498cfa0ad2SJack F Vogel                                          u16 *duplex);
508cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_82541(struct e1000_hw *hw);
518cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_82541(struct e1000_hw *hw);
528cfa0ad2SJack F Vogel static s32  e1000_check_for_link_82541(struct e1000_hw *hw);
538cfa0ad2SJack F Vogel static s32  e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
548cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
558cfa0ad2SJack F Vogel                                           bool active);
568cfa0ad2SJack F Vogel static s32  e1000_setup_led_82541(struct e1000_hw *hw);
578cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_82541(struct e1000_hw *hw);
588cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
598cfa0ad2SJack F Vogel static s32  e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
608cfa0ad2SJack F Vogel                                                      bool link_up);
618cfa0ad2SJack F Vogel static s32  e1000_phy_init_script_82541(struct e1000_hw *hw);
628cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
638cfa0ad2SJack F Vogel 
648cfa0ad2SJack F Vogel static const u16 e1000_igp_cable_length_table[] =
658cfa0ad2SJack F Vogel     { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
668cfa0ad2SJack F Vogel       5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
678cfa0ad2SJack F Vogel       25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
688cfa0ad2SJack F Vogel       40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
698cfa0ad2SJack F Vogel       60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
708cfa0ad2SJack F Vogel       90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
718cfa0ad2SJack F Vogel       100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
728cfa0ad2SJack F Vogel       110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
738cfa0ad2SJack F Vogel #define IGP01E1000_AGC_LENGTH_TABLE_SIZE \
748cfa0ad2SJack F Vogel                 (sizeof(e1000_igp_cable_length_table) / \
758cfa0ad2SJack F Vogel                  sizeof(e1000_igp_cable_length_table[0]))
768cfa0ad2SJack F Vogel 
778cfa0ad2SJack F Vogel struct e1000_dev_spec_82541 {
788cfa0ad2SJack F Vogel 	enum e1000_dsp_config dsp_config;
798cfa0ad2SJack F Vogel 	enum e1000_ffe_config ffe_config;
808cfa0ad2SJack F Vogel 	u16 spd_default;
818cfa0ad2SJack F Vogel 	bool phy_init_script;
828cfa0ad2SJack F Vogel };
838cfa0ad2SJack F Vogel 
848cfa0ad2SJack F Vogel /**
858cfa0ad2SJack F Vogel  *  e1000_init_phy_params_82541 - Init PHY func ptrs.
868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
878cfa0ad2SJack F Vogel  *
888cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by the api module.
898cfa0ad2SJack F Vogel  **/
908cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_82541(struct e1000_hw *hw)
918cfa0ad2SJack F Vogel {
928cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
938cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
948cfa0ad2SJack F Vogel 
958cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_82541");
968cfa0ad2SJack F Vogel 
978cfa0ad2SJack F Vogel 	phy->addr                      = 1;
988cfa0ad2SJack F Vogel 	phy->autoneg_mask              = AUTONEG_ADVERTISE_SPEED_DEFAULT;
998cfa0ad2SJack F Vogel 	phy->reset_delay_us            = 10000;
1008cfa0ad2SJack F Vogel 	phy->type                      = e1000_phy_igp;
1018cfa0ad2SJack F Vogel 
1028cfa0ad2SJack F Vogel 	/* Function Pointers */
1038cfa0ad2SJack F Vogel 	phy->ops.check_polarity        = e1000_check_polarity_igp;
1048cfa0ad2SJack F Vogel 	phy->ops.force_speed_duplex    = e1000_phy_force_speed_duplex_igp;
1058cfa0ad2SJack F Vogel 	phy->ops.get_cable_length      = e1000_get_cable_length_igp_82541;
1068cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done          = e1000_get_cfg_done_generic;
1078cfa0ad2SJack F Vogel 	phy->ops.get_info              = e1000_get_phy_info_igp;
1088cfa0ad2SJack F Vogel 	phy->ops.read_reg              = e1000_read_phy_reg_igp;
1098cfa0ad2SJack F Vogel 	phy->ops.reset                 = e1000_phy_hw_reset_82541;
1108cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state     = e1000_set_d3_lplu_state_82541;
1118cfa0ad2SJack F Vogel 	phy->ops.write_reg             = e1000_write_phy_reg_igp;
1128cfa0ad2SJack F Vogel 	phy->ops.power_up              = e1000_power_up_phy_copper;
1138cfa0ad2SJack F Vogel 	phy->ops.power_down            = e1000_power_down_phy_copper_82541;
1148cfa0ad2SJack F Vogel 
1158cfa0ad2SJack F Vogel 	ret_val = e1000_get_phy_id(hw);
1168cfa0ad2SJack F Vogel 	if (ret_val)
1178cfa0ad2SJack F Vogel 		goto out;
1188cfa0ad2SJack F Vogel 
1198cfa0ad2SJack F Vogel 	/* Verify phy id */
1208cfa0ad2SJack F Vogel 	if (phy->id != IGP01E1000_I_PHY_ID) {
1218cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
1228cfa0ad2SJack F Vogel 		goto out;
1238cfa0ad2SJack F Vogel 	}
1248cfa0ad2SJack F Vogel 
1258cfa0ad2SJack F Vogel out:
1268cfa0ad2SJack F Vogel 	return ret_val;
1278cfa0ad2SJack F Vogel }
1288cfa0ad2SJack F Vogel 
1298cfa0ad2SJack F Vogel /**
1308cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_82541 - Init NVM func ptrs.
1318cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
1328cfa0ad2SJack F Vogel  *
1338cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by the api module.
1348cfa0ad2SJack F Vogel  **/
1358cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw)
1368cfa0ad2SJack F Vogel {
1378cfa0ad2SJack F Vogel 	struct   e1000_nvm_info *nvm = &hw->nvm;
1388cfa0ad2SJack F Vogel 	s32  ret_val = E1000_SUCCESS;
1398cfa0ad2SJack F Vogel 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1408cfa0ad2SJack F Vogel 	u16 size;
1418cfa0ad2SJack F Vogel 
1428cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_82541");
1438cfa0ad2SJack F Vogel 
1448cfa0ad2SJack F Vogel 	switch (nvm->override) {
1458cfa0ad2SJack F Vogel 	case e1000_nvm_override_spi_large:
1468cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_spi;
1478cfa0ad2SJack F Vogel 		eecd |= E1000_EECD_ADDR_BITS;
1488cfa0ad2SJack F Vogel 		break;
1498cfa0ad2SJack F Vogel 	case e1000_nvm_override_spi_small:
1508cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_spi;
1518cfa0ad2SJack F Vogel 		eecd &= ~E1000_EECD_ADDR_BITS;
1528cfa0ad2SJack F Vogel 		break;
1538cfa0ad2SJack F Vogel 	case e1000_nvm_override_microwire_large:
1548cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_microwire;
1558cfa0ad2SJack F Vogel 		eecd |= E1000_EECD_SIZE;
1568cfa0ad2SJack F Vogel 		break;
1578cfa0ad2SJack F Vogel 	case e1000_nvm_override_microwire_small:
1588cfa0ad2SJack F Vogel 		nvm->type = e1000_nvm_eeprom_microwire;
1598cfa0ad2SJack F Vogel 		eecd &= ~E1000_EECD_SIZE;
1608cfa0ad2SJack F Vogel 		break;
1618cfa0ad2SJack F Vogel 	default:
1628cfa0ad2SJack F Vogel 		nvm->type = eecd & E1000_EECD_TYPE
1638cfa0ad2SJack F Vogel 		            ? e1000_nvm_eeprom_spi
1648cfa0ad2SJack F Vogel 		            : e1000_nvm_eeprom_microwire;
1658cfa0ad2SJack F Vogel 		break;
1668cfa0ad2SJack F Vogel 	}
1678cfa0ad2SJack F Vogel 
1688cfa0ad2SJack F Vogel 	if (nvm->type == e1000_nvm_eeprom_spi) {
1698cfa0ad2SJack F Vogel 		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
1708cfa0ad2SJack F Vogel 		                          ? 16 : 8;
1718cfa0ad2SJack F Vogel 		nvm->delay_usec         = 1;
1728cfa0ad2SJack F Vogel 		nvm->opcode_bits        = 8;
1738cfa0ad2SJack F Vogel 		nvm->page_size          = (eecd & E1000_EECD_ADDR_BITS)
1748cfa0ad2SJack F Vogel 		                          ? 32 : 8;
1758cfa0ad2SJack F Vogel 
1768cfa0ad2SJack F Vogel 		/* Function Pointers */
1778cfa0ad2SJack F Vogel 		nvm->ops.acquire        = e1000_acquire_nvm_generic;
1788cfa0ad2SJack F Vogel 		nvm->ops.read           = e1000_read_nvm_spi;
1798cfa0ad2SJack F Vogel 		nvm->ops.release        = e1000_release_nvm_generic;
1808cfa0ad2SJack F Vogel 		nvm->ops.update         = e1000_update_nvm_checksum_generic;
1818cfa0ad2SJack F Vogel 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1828cfa0ad2SJack F Vogel 		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
1838cfa0ad2SJack F Vogel 		nvm->ops.write          = e1000_write_nvm_spi;
1848cfa0ad2SJack F Vogel 
1858cfa0ad2SJack F Vogel 		/*
1868cfa0ad2SJack F Vogel 		 * nvm->word_size must be discovered after the pointers
1878cfa0ad2SJack F Vogel 		 * are set so we can verify the size from the nvm image
1888cfa0ad2SJack F Vogel 		 * itself.  Temporarily set it to a dummy value so the
1898cfa0ad2SJack F Vogel 		 * read will work.
1908cfa0ad2SJack F Vogel 		 */
1918cfa0ad2SJack F Vogel 		nvm->word_size = 64;
1928cfa0ad2SJack F Vogel 		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
1938cfa0ad2SJack F Vogel 		if (ret_val)
1948cfa0ad2SJack F Vogel 			goto out;
1958cfa0ad2SJack F Vogel 		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
1968cfa0ad2SJack F Vogel 		/*
1978cfa0ad2SJack F Vogel 		 * if size != 0, it can be added to a constant and become
1988cfa0ad2SJack F Vogel 		 * the left-shift value to set the word_size.  Otherwise,
1998cfa0ad2SJack F Vogel 		 * word_size stays at 64.
2008cfa0ad2SJack F Vogel 		 */
2018cfa0ad2SJack F Vogel 		if (size) {
2028cfa0ad2SJack F Vogel 			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
2038cfa0ad2SJack F Vogel 			nvm->word_size = 1 << size;
2048cfa0ad2SJack F Vogel 		}
2058cfa0ad2SJack F Vogel 	} else {
2068cfa0ad2SJack F Vogel 		nvm->address_bits       = (eecd & E1000_EECD_ADDR_BITS)
2078cfa0ad2SJack F Vogel 		                          ? 8 : 6;
2088cfa0ad2SJack F Vogel 		nvm->delay_usec         = 50;
2098cfa0ad2SJack F Vogel 		nvm->opcode_bits        = 3;
2108cfa0ad2SJack F Vogel 		nvm->word_size          = (eecd & E1000_EECD_ADDR_BITS)
2118cfa0ad2SJack F Vogel 		                          ? 256 : 64;
2128cfa0ad2SJack F Vogel 
2138cfa0ad2SJack F Vogel 		/* Function Pointers */
2148cfa0ad2SJack F Vogel 		nvm->ops.acquire        = e1000_acquire_nvm_generic;
2158cfa0ad2SJack F Vogel 		nvm->ops.read           = e1000_read_nvm_microwire;
2168cfa0ad2SJack F Vogel 		nvm->ops.release        = e1000_release_nvm_generic;
2178cfa0ad2SJack F Vogel 		nvm->ops.update         = e1000_update_nvm_checksum_generic;
2188cfa0ad2SJack F Vogel 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
2198cfa0ad2SJack F Vogel 		nvm->ops.validate       = e1000_validate_nvm_checksum_generic;
2208cfa0ad2SJack F Vogel 		nvm->ops.write          = e1000_write_nvm_microwire;
2218cfa0ad2SJack F Vogel 	}
2228cfa0ad2SJack F Vogel 
2238cfa0ad2SJack F Vogel out:
2248cfa0ad2SJack F Vogel 	return ret_val;
2258cfa0ad2SJack F Vogel }
2268cfa0ad2SJack F Vogel 
2278cfa0ad2SJack F Vogel /**
2288cfa0ad2SJack F Vogel  *  e1000_init_mac_params_82541 - Init MAC func ptrs.
2298cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2308cfa0ad2SJack F Vogel  *
2318cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by the api module.
2328cfa0ad2SJack F Vogel  **/
2338cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_82541(struct e1000_hw *hw)
2348cfa0ad2SJack F Vogel {
2358cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
2368cfa0ad2SJack F Vogel 	s32 ret_val;
2378cfa0ad2SJack F Vogel 
2388cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_82541");
2398cfa0ad2SJack F Vogel 
2408cfa0ad2SJack F Vogel 	/* Set media type */
2418cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
2428cfa0ad2SJack F Vogel 	/* Set mta register count */
2438cfa0ad2SJack F Vogel 	mac->mta_reg_count = 128;
2448cfa0ad2SJack F Vogel 	/* Set rar entry count */
2458cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_RAR_ENTRIES;
2468cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
2478cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
2488cfa0ad2SJack F Vogel 
2498cfa0ad2SJack F Vogel 	/* Function Pointers */
2508cfa0ad2SJack F Vogel 
2518cfa0ad2SJack F Vogel 	/* bus type/speed/width */
2528cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
2538cfa0ad2SJack F Vogel 	/* reset */
2548cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_82541;
2558cfa0ad2SJack F Vogel 	/* hw initialization */
2568cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_82541;
2578cfa0ad2SJack F Vogel 	/* link setup */
2588cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_generic;
2598cfa0ad2SJack F Vogel 	/* physical interface link setup */
2608cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
2618cfa0ad2SJack F Vogel 	/* check for link */
2628cfa0ad2SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_link_82541;
2638cfa0ad2SJack F Vogel 	/* link info */
2648cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
2658cfa0ad2SJack F Vogel 	/* multicast address update */
2668cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2678cfa0ad2SJack F Vogel 	/* writing VFTA */
2688cfa0ad2SJack F Vogel 	mac->ops.write_vfta = e1000_write_vfta_generic;
2698cfa0ad2SJack F Vogel 	/* clearing VFTA */
2708cfa0ad2SJack F Vogel 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
2718cfa0ad2SJack F Vogel 	/* setting MTA */
2728cfa0ad2SJack F Vogel 	mac->ops.mta_set = e1000_mta_set_generic;
2738cfa0ad2SJack F Vogel 	/* setup LED */
2748cfa0ad2SJack F Vogel 	mac->ops.setup_led = e1000_setup_led_82541;
2758cfa0ad2SJack F Vogel 	/* cleanup LED */
2768cfa0ad2SJack F Vogel 	mac->ops.cleanup_led = e1000_cleanup_led_82541;
2778cfa0ad2SJack F Vogel 	/* turn on/off LED */
2788cfa0ad2SJack F Vogel 	mac->ops.led_on = e1000_led_on_generic;
2798cfa0ad2SJack F Vogel 	mac->ops.led_off = e1000_led_off_generic;
2808cfa0ad2SJack F Vogel 	/* remove device */
2818cfa0ad2SJack F Vogel 	mac->ops.remove_device = e1000_remove_device_generic;
2828cfa0ad2SJack F Vogel 	/* clear hardware counters */
2838cfa0ad2SJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
2848cfa0ad2SJack F Vogel 
2858cfa0ad2SJack F Vogel 	hw->dev_spec_size = sizeof(struct e1000_dev_spec_82541);
2868cfa0ad2SJack F Vogel 
2878cfa0ad2SJack F Vogel 	/* Device-specific structure allocation */
2888cfa0ad2SJack F Vogel 	ret_val = e1000_alloc_zeroed_dev_spec_struct(hw, hw->dev_spec_size);
2898cfa0ad2SJack F Vogel 
2908cfa0ad2SJack F Vogel 	return ret_val;
2918cfa0ad2SJack F Vogel }
2928cfa0ad2SJack F Vogel 
2938cfa0ad2SJack F Vogel /**
2948cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_82541 - Init func ptrs.
2958cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2968cfa0ad2SJack F Vogel  *
2978cfa0ad2SJack F Vogel  *  The only function explicitly called by the api module to initialize
2988cfa0ad2SJack F Vogel  *  all function pointers and parameters.
2998cfa0ad2SJack F Vogel  **/
3008cfa0ad2SJack F Vogel void e1000_init_function_pointers_82541(struct e1000_hw *hw)
3018cfa0ad2SJack F Vogel {
3028cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_82541");
3038cfa0ad2SJack F Vogel 
3048cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_82541;
3058cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
3068cfa0ad2SJack F Vogel 	hw->phy.ops.init_params = e1000_init_phy_params_82541;
3078cfa0ad2SJack F Vogel }
3088cfa0ad2SJack F Vogel 
3098cfa0ad2SJack F Vogel /**
3108cfa0ad2SJack F Vogel  *  e1000_reset_hw_82541 - Reset hardware
3118cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3128cfa0ad2SJack F Vogel  *
3138cfa0ad2SJack F Vogel  *  This resets the hardware into a known state.  This is a
3148cfa0ad2SJack F Vogel  *  function pointer entry point called by the api module.
3158cfa0ad2SJack F Vogel  **/
3168cfa0ad2SJack F Vogel static s32 e1000_reset_hw_82541(struct e1000_hw *hw)
3178cfa0ad2SJack F Vogel {
3188cfa0ad2SJack F Vogel 	u32 ledctl, ctrl, icr, manc;
3198cfa0ad2SJack F Vogel 
3208cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_82541");
3218cfa0ad2SJack F Vogel 
3228cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
3238cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3248cfa0ad2SJack F Vogel 
3258cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
3268cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
3278cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
3288cfa0ad2SJack F Vogel 
3298cfa0ad2SJack F Vogel 	/*
3308cfa0ad2SJack F Vogel 	 * Delay to allow any outstanding PCI transactions to complete
3318cfa0ad2SJack F Vogel 	 * before resetting the device.
3328cfa0ad2SJack F Vogel 	 */
3338cfa0ad2SJack F Vogel 	msec_delay(10);
3348cfa0ad2SJack F Vogel 
3358cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
3368cfa0ad2SJack F Vogel 
3378cfa0ad2SJack F Vogel 	/* Must reset the Phy before resetting the MAC */
3388cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3398cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
3408cfa0ad2SJack F Vogel 		msec_delay(5);
3418cfa0ad2SJack F Vogel 	}
3428cfa0ad2SJack F Vogel 
3438cfa0ad2SJack F Vogel 	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
3448cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
3458cfa0ad2SJack F Vogel 	case e1000_82541:
3468cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
3478cfa0ad2SJack F Vogel 		/*
3488cfa0ad2SJack F Vogel 		 * These controllers can't ack the 64-bit write when
3498cfa0ad2SJack F Vogel 		 * issuing the reset, so we use IO-mapping as a
3508cfa0ad2SJack F Vogel 		 * workaround to issue the reset.
3518cfa0ad2SJack F Vogel 		 */
3528cfa0ad2SJack F Vogel 		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3538cfa0ad2SJack F Vogel 		break;
3548cfa0ad2SJack F Vogel 	default:
3558cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3568cfa0ad2SJack F Vogel 		break;
3578cfa0ad2SJack F Vogel 	}
3588cfa0ad2SJack F Vogel 
3598cfa0ad2SJack F Vogel 	/* Wait for NVM reload */
3608cfa0ad2SJack F Vogel 	msec_delay(20);
3618cfa0ad2SJack F Vogel 
3628cfa0ad2SJack F Vogel 	/* Disable HW ARPs on ASF enabled adapters */
3638cfa0ad2SJack F Vogel 	manc = E1000_READ_REG(hw, E1000_MANC);
3648cfa0ad2SJack F Vogel 	manc &= ~E1000_MANC_ARP_EN;
3658cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_MANC, manc);
3668cfa0ad2SJack F Vogel 
3678cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3688cfa0ad2SJack F Vogel 		e1000_phy_init_script_82541(hw);
3698cfa0ad2SJack F Vogel 
3708cfa0ad2SJack F Vogel 		/* Configure activity LED after Phy reset */
3718cfa0ad2SJack F Vogel 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
3728cfa0ad2SJack F Vogel 		ledctl &= IGP_ACTIVITY_LED_MASK;
3738cfa0ad2SJack F Vogel 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
3748cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
3758cfa0ad2SJack F Vogel 	}
3768cfa0ad2SJack F Vogel 
3778cfa0ad2SJack F Vogel 	/* Once again, mask the interrupts */
3788cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
3798cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3808cfa0ad2SJack F Vogel 
3818cfa0ad2SJack F Vogel 	/* Clear any pending interrupt events. */
3828cfa0ad2SJack F Vogel 	icr = E1000_READ_REG(hw, E1000_ICR);
3838cfa0ad2SJack F Vogel 
3848cfa0ad2SJack F Vogel 	return E1000_SUCCESS;
3858cfa0ad2SJack F Vogel }
3868cfa0ad2SJack F Vogel 
3878cfa0ad2SJack F Vogel /**
3888cfa0ad2SJack F Vogel  *  e1000_init_hw_82541 - Initialize hardware
3898cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3908cfa0ad2SJack F Vogel  *
3918cfa0ad2SJack F Vogel  *  This inits the hardware readying it for operation.  This is a
3928cfa0ad2SJack F Vogel  *  function pointer entry point called by the api module.
3938cfa0ad2SJack F Vogel  **/
3948cfa0ad2SJack F Vogel static s32 e1000_init_hw_82541(struct e1000_hw *hw)
3958cfa0ad2SJack F Vogel {
3968cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
3978cfa0ad2SJack F Vogel 	u32 i, txdctl;
3988cfa0ad2SJack F Vogel 	s32 ret_val;
3998cfa0ad2SJack F Vogel 
4008cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_82541");
4018cfa0ad2SJack F Vogel 
4028cfa0ad2SJack F Vogel 	/* Initialize identification LED */
4038cfa0ad2SJack F Vogel 	ret_val = e1000_id_led_init_generic(hw);
4048cfa0ad2SJack F Vogel 	if (ret_val) {
4058cfa0ad2SJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
4068cfa0ad2SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
4078cfa0ad2SJack F Vogel 	}
4088cfa0ad2SJack F Vogel 
4098cfa0ad2SJack F Vogel 	/* Disabling VLAN filtering */
4108cfa0ad2SJack F Vogel 	DEBUGOUT("Initializing the IEEE VLAN\n");
4118cfa0ad2SJack F Vogel 	mac->ops.clear_vfta(hw);
4128cfa0ad2SJack F Vogel 
4138cfa0ad2SJack F Vogel 	/* Setup the receive address. */
4148cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
4158cfa0ad2SJack F Vogel 
4168cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
4178cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
4188cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++) {
4198cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
4208cfa0ad2SJack F Vogel 		/*
4218cfa0ad2SJack F Vogel 		 * Avoid back to back register writes by adding the register
4228cfa0ad2SJack F Vogel 		 * read (flush).  This is to protect against some strange
4238cfa0ad2SJack F Vogel 		 * bridge configurations that may issue Memory Write Block
4248cfa0ad2SJack F Vogel 		 * (MWB) to our register space.
4258cfa0ad2SJack F Vogel 		 */
4268cfa0ad2SJack F Vogel 		E1000_WRITE_FLUSH(hw);
4278cfa0ad2SJack F Vogel 	}
4288cfa0ad2SJack F Vogel 
4298cfa0ad2SJack F Vogel 	/* Setup link and flow control */
4308cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
4318cfa0ad2SJack F Vogel 
4328cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
4338cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
4348cfa0ad2SJack F Vogel 	         E1000_TXDCTL_FULL_TX_DESC_WB;
4358cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
4368cfa0ad2SJack F Vogel 
4378cfa0ad2SJack F Vogel 	/*
4388cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
4398cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
4408cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
4418cfa0ad2SJack F Vogel 	 * is no link.
4428cfa0ad2SJack F Vogel 	 */
4438cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_82541(hw);
4448cfa0ad2SJack F Vogel 
4458cfa0ad2SJack F Vogel 	return ret_val;
4468cfa0ad2SJack F Vogel }
4478cfa0ad2SJack F Vogel 
4488cfa0ad2SJack F Vogel /**
4498cfa0ad2SJack F Vogel  * e1000_get_link_up_info_82541 - Report speed and duplex
4508cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
4518cfa0ad2SJack F Vogel  * @speed: pointer to speed buffer
4528cfa0ad2SJack F Vogel  * @duplex: pointer to duplex buffer
4538cfa0ad2SJack F Vogel  *
4548cfa0ad2SJack F Vogel  * Retrieve the current speed and duplex configuration.
4558cfa0ad2SJack F Vogel  * This is a function pointer entry point called by the api module.
4568cfa0ad2SJack F Vogel  **/
4578cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
4588cfa0ad2SJack F Vogel                                         u16 *duplex)
4598cfa0ad2SJack F Vogel {
4608cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
4618cfa0ad2SJack F Vogel 	s32 ret_val;
4628cfa0ad2SJack F Vogel 	u16 data;
4638cfa0ad2SJack F Vogel 
4648cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_82541");
4658cfa0ad2SJack F Vogel 
4668cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
4678cfa0ad2SJack F Vogel 	if (ret_val)
4688cfa0ad2SJack F Vogel 		goto out;
4698cfa0ad2SJack F Vogel 
4708cfa0ad2SJack F Vogel 	if (!phy->speed_downgraded)
4718cfa0ad2SJack F Vogel 		goto out;
4728cfa0ad2SJack F Vogel 
4738cfa0ad2SJack F Vogel 	/*
4748cfa0ad2SJack F Vogel 	 * IGP01 PHY may advertise full duplex operation after speed
4758cfa0ad2SJack F Vogel 	 * downgrade even if it is operating at half duplex.
4768cfa0ad2SJack F Vogel 	 * Here we set the duplex settings to match the duplex in the
4778cfa0ad2SJack F Vogel 	 * link partner's capabilities.
4788cfa0ad2SJack F Vogel 	 */
4798cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
4808cfa0ad2SJack F Vogel 	if (ret_val)
4818cfa0ad2SJack F Vogel 		goto out;
4828cfa0ad2SJack F Vogel 
4838cfa0ad2SJack F Vogel 	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
4848cfa0ad2SJack F Vogel 		*duplex = HALF_DUPLEX;
4858cfa0ad2SJack F Vogel 	} else {
4868cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
4878cfa0ad2SJack F Vogel 		if (ret_val)
4888cfa0ad2SJack F Vogel 			goto out;
4898cfa0ad2SJack F Vogel 
4908cfa0ad2SJack F Vogel 		if (*speed == SPEED_100) {
4918cfa0ad2SJack F Vogel 			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
4928cfa0ad2SJack F Vogel 				*duplex = HALF_DUPLEX;
4938cfa0ad2SJack F Vogel 		} else if (*speed == SPEED_10) {
4948cfa0ad2SJack F Vogel 			if (!(data & NWAY_LPAR_10T_FD_CAPS))
4958cfa0ad2SJack F Vogel 				*duplex = HALF_DUPLEX;
4968cfa0ad2SJack F Vogel 		}
4978cfa0ad2SJack F Vogel 	}
4988cfa0ad2SJack F Vogel 
4998cfa0ad2SJack F Vogel out:
5008cfa0ad2SJack F Vogel 	return ret_val;
5018cfa0ad2SJack F Vogel }
5028cfa0ad2SJack F Vogel 
5038cfa0ad2SJack F Vogel /**
5048cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_82541 - PHY hardware reset
5058cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5068cfa0ad2SJack F Vogel  *
5078cfa0ad2SJack F Vogel  *  Verify the reset block is not blocking us from resetting.  Acquire
5088cfa0ad2SJack F Vogel  *  semaphore (if necessary) and read/set/write the device control reset
5098cfa0ad2SJack F Vogel  *  bit in the PHY.  Wait the appropriate delay time for the device to
5108cfa0ad2SJack F Vogel  *  reset and release the semaphore (if necessary).
5118cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by the api module.
5128cfa0ad2SJack F Vogel  **/
5138cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
5148cfa0ad2SJack F Vogel {
5158cfa0ad2SJack F Vogel 	s32 ret_val;
5168cfa0ad2SJack F Vogel 	u32 ledctl;
5178cfa0ad2SJack F Vogel 
5188cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_82541");
5198cfa0ad2SJack F Vogel 
5208cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
5218cfa0ad2SJack F Vogel 	if (ret_val)
5228cfa0ad2SJack F Vogel 		goto out;
5238cfa0ad2SJack F Vogel 
5248cfa0ad2SJack F Vogel 	e1000_phy_init_script_82541(hw);
5258cfa0ad2SJack F Vogel 
5268cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
5278cfa0ad2SJack F Vogel 		/* Configure activity LED after PHY reset */
5288cfa0ad2SJack F Vogel 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5298cfa0ad2SJack F Vogel 		ledctl &= IGP_ACTIVITY_LED_MASK;
5308cfa0ad2SJack F Vogel 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5318cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5328cfa0ad2SJack F Vogel 	}
5338cfa0ad2SJack F Vogel 
5348cfa0ad2SJack F Vogel out:
5358cfa0ad2SJack F Vogel 	return ret_val;
5368cfa0ad2SJack F Vogel }
5378cfa0ad2SJack F Vogel 
5388cfa0ad2SJack F Vogel /**
5398cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_82541 - Configure copper link settings
5408cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5418cfa0ad2SJack F Vogel  *
5428cfa0ad2SJack F Vogel  *  Calls the appropriate function to configure the link for auto-neg or forced
5438cfa0ad2SJack F Vogel  *  speed and duplex.  Then we check for link, once link is established calls
5448cfa0ad2SJack F Vogel  *  to configure collision distance and flow control are called.  If link is
5458cfa0ad2SJack F Vogel  *  not established, we return -E1000_ERR_PHY (-2).  This is a function
5468cfa0ad2SJack F Vogel  *  pointer entry point called by the api module.
5478cfa0ad2SJack F Vogel  **/
5488cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw)
5498cfa0ad2SJack F Vogel {
5508cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
5518cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
5528cfa0ad2SJack F Vogel 	s32  ret_val;
5538cfa0ad2SJack F Vogel 	u32 ctrl, ledctl;
5548cfa0ad2SJack F Vogel 
5558cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_82541");
5568cfa0ad2SJack F Vogel 
5578cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
5588cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
5598cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
5608cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
5618cfa0ad2SJack F Vogel 
5628cfa0ad2SJack F Vogel 	hw->phy.reset_disable = FALSE;
5638cfa0ad2SJack F Vogel 
5648cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
5658cfa0ad2SJack F Vogel 
5668cfa0ad2SJack F Vogel 	/* Earlier revs of the IGP phy require us to force MDI. */
5678cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
5688cfa0ad2SJack F Vogel 		dev_spec->dsp_config = e1000_dsp_config_disabled;
5698cfa0ad2SJack F Vogel 		phy->mdix = 1;
5708cfa0ad2SJack F Vogel 	} else {
5718cfa0ad2SJack F Vogel 		dev_spec->dsp_config = e1000_dsp_config_enabled;
5728cfa0ad2SJack F Vogel 	}
5738cfa0ad2SJack F Vogel 
5748cfa0ad2SJack F Vogel 	ret_val = e1000_copper_link_setup_igp(hw);
5758cfa0ad2SJack F Vogel 	if (ret_val)
5768cfa0ad2SJack F Vogel 		goto out;
5778cfa0ad2SJack F Vogel 
5788cfa0ad2SJack F Vogel 	if (hw->mac.autoneg) {
5798cfa0ad2SJack F Vogel 		if (dev_spec->ffe_config == e1000_ffe_config_active)
5808cfa0ad2SJack F Vogel 			dev_spec->ffe_config = e1000_ffe_config_enabled;
5818cfa0ad2SJack F Vogel 	}
5828cfa0ad2SJack F Vogel 
5838cfa0ad2SJack F Vogel 	/* Configure activity LED after Phy reset */
5848cfa0ad2SJack F Vogel 	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5858cfa0ad2SJack F Vogel 	ledctl &= IGP_ACTIVITY_LED_MASK;
5868cfa0ad2SJack F Vogel 	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5878cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5888cfa0ad2SJack F Vogel 
5898cfa0ad2SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
5908cfa0ad2SJack F Vogel 
5918cfa0ad2SJack F Vogel out:
5928cfa0ad2SJack F Vogel 	return ret_val;
5938cfa0ad2SJack F Vogel }
5948cfa0ad2SJack F Vogel 
5958cfa0ad2SJack F Vogel /**
5968cfa0ad2SJack F Vogel  *  e1000_check_for_link_82541 - Check/Store link connection
5978cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5988cfa0ad2SJack F Vogel  *
5998cfa0ad2SJack F Vogel  *  This checks the link condition of the adapter and stores the
6008cfa0ad2SJack F Vogel  *  results in the hw->mac structure. This is a function pointer entry
6018cfa0ad2SJack F Vogel  *  point called by the api module.
6028cfa0ad2SJack F Vogel  **/
6038cfa0ad2SJack F Vogel static s32 e1000_check_for_link_82541(struct e1000_hw *hw)
6048cfa0ad2SJack F Vogel {
6058cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
6068cfa0ad2SJack F Vogel 	s32 ret_val;
6078cfa0ad2SJack F Vogel 	bool link;
6088cfa0ad2SJack F Vogel 
6098cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_for_link_82541");
6108cfa0ad2SJack F Vogel 
6118cfa0ad2SJack F Vogel 	/*
6128cfa0ad2SJack F Vogel 	 * We only want to go out to the PHY registers to see if Auto-Neg
6138cfa0ad2SJack F Vogel 	 * has completed and/or if our link status has changed.  The
6148cfa0ad2SJack F Vogel 	 * get_link_status flag is set upon receiving a Link Status
6158cfa0ad2SJack F Vogel 	 * Change or Rx Sequence Error interrupt.
6168cfa0ad2SJack F Vogel 	 */
6178cfa0ad2SJack F Vogel 	if (!mac->get_link_status) {
6188cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
6198cfa0ad2SJack F Vogel 		goto out;
6208cfa0ad2SJack F Vogel 	}
6218cfa0ad2SJack F Vogel 
6228cfa0ad2SJack F Vogel 	/*
6238cfa0ad2SJack F Vogel 	 * First we want to see if the MII Status Register reports
6248cfa0ad2SJack F Vogel 	 * link.  If so, then we want to get the current speed/duplex
6258cfa0ad2SJack F Vogel 	 * of the PHY.
6268cfa0ad2SJack F Vogel 	 */
6278cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
6288cfa0ad2SJack F Vogel 	if (ret_val)
6298cfa0ad2SJack F Vogel 		goto out;
6308cfa0ad2SJack F Vogel 
6318cfa0ad2SJack F Vogel 	if (!link) {
6328cfa0ad2SJack F Vogel 		ret_val = e1000_config_dsp_after_link_change_82541(hw, FALSE);
6338cfa0ad2SJack F Vogel 		goto out; /* No link detected */
6348cfa0ad2SJack F Vogel 	}
6358cfa0ad2SJack F Vogel 
6368cfa0ad2SJack F Vogel 	mac->get_link_status = FALSE;
6378cfa0ad2SJack F Vogel 
6388cfa0ad2SJack F Vogel 	/*
6398cfa0ad2SJack F Vogel 	 * Check if there was DownShift, must be checked
6408cfa0ad2SJack F Vogel 	 * immediately after link-up
6418cfa0ad2SJack F Vogel 	 */
6428cfa0ad2SJack F Vogel 	e1000_check_downshift_generic(hw);
6438cfa0ad2SJack F Vogel 
6448cfa0ad2SJack F Vogel 	/*
6458cfa0ad2SJack F Vogel 	 * If we are forcing speed/duplex, then we simply return since
6468cfa0ad2SJack F Vogel 	 * we have already determined whether we have link or not.
6478cfa0ad2SJack F Vogel 	 */
6488cfa0ad2SJack F Vogel 	if (!mac->autoneg) {
6498cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
6508cfa0ad2SJack F Vogel 		goto out;
6518cfa0ad2SJack F Vogel 	}
6528cfa0ad2SJack F Vogel 
6538cfa0ad2SJack F Vogel 	ret_val = e1000_config_dsp_after_link_change_82541(hw, TRUE);
6548cfa0ad2SJack F Vogel 
6558cfa0ad2SJack F Vogel 	/*
6568cfa0ad2SJack F Vogel 	 * Auto-Neg is enabled.  Auto Speed Detection takes care
6578cfa0ad2SJack F Vogel 	 * of MAC speed/duplex configuration.  So we only need to
6588cfa0ad2SJack F Vogel 	 * configure Collision Distance in the MAC.
6598cfa0ad2SJack F Vogel 	 */
6608cfa0ad2SJack F Vogel 	e1000_config_collision_dist_generic(hw);
6618cfa0ad2SJack F Vogel 
6628cfa0ad2SJack F Vogel 	/*
6638cfa0ad2SJack F Vogel 	 * Configure Flow Control now that Auto-Neg has completed.
6648cfa0ad2SJack F Vogel 	 * First, we need to restore the desired flow control
6658cfa0ad2SJack F Vogel 	 * settings because we may have had to re-autoneg with a
6668cfa0ad2SJack F Vogel 	 * different link partner.
6678cfa0ad2SJack F Vogel 	 */
6688cfa0ad2SJack F Vogel 	ret_val = e1000_config_fc_after_link_up_generic(hw);
6698cfa0ad2SJack F Vogel 	if (ret_val) {
6708cfa0ad2SJack F Vogel 		DEBUGOUT("Error configuring flow control\n");
6718cfa0ad2SJack F Vogel 	}
6728cfa0ad2SJack F Vogel 
6738cfa0ad2SJack F Vogel out:
6748cfa0ad2SJack F Vogel 	return ret_val;
6758cfa0ad2SJack F Vogel }
6768cfa0ad2SJack F Vogel 
6778cfa0ad2SJack F Vogel /**
6788cfa0ad2SJack F Vogel  *  e1000_config_dsp_after_link_change_82541 - Config DSP after link
6798cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6808cfa0ad2SJack F Vogel  *  @link_up: boolean flag for link up status
6818cfa0ad2SJack F Vogel  *
6828cfa0ad2SJack F Vogel  *  Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
6838cfa0ad2SJack F Vogel  *  at any other case.
6848cfa0ad2SJack F Vogel  *
6858cfa0ad2SJack F Vogel  *  82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
6868cfa0ad2SJack F Vogel  *  gigabit link is achieved to improve link quality.
6878cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by the api module.
6888cfa0ad2SJack F Vogel  **/
6898cfa0ad2SJack F Vogel static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
6908cfa0ad2SJack F Vogel                                                     bool link_up)
6918cfa0ad2SJack F Vogel {
6928cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
6938cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
6948cfa0ad2SJack F Vogel 	s32 ret_val;
6958cfa0ad2SJack F Vogel 	u32 idle_errs = 0;
6968cfa0ad2SJack F Vogel 	u16 phy_data, phy_saved_data, speed, duplex, i;
6978cfa0ad2SJack F Vogel 	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
6988cfa0ad2SJack F Vogel 	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
6998cfa0ad2SJack F Vogel 	                                           {IGP01E1000_PHY_AGC_PARAM_A,
7008cfa0ad2SJack F Vogel 	                                            IGP01E1000_PHY_AGC_PARAM_B,
7018cfa0ad2SJack F Vogel 	                                            IGP01E1000_PHY_AGC_PARAM_C,
7028cfa0ad2SJack F Vogel 	                                            IGP01E1000_PHY_AGC_PARAM_D};
7038cfa0ad2SJack F Vogel 
7048cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
7058cfa0ad2SJack F Vogel 
7068cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
7078cfa0ad2SJack F Vogel 
7088cfa0ad2SJack F Vogel 	if (link_up) {
7098cfa0ad2SJack F Vogel 		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
7108cfa0ad2SJack F Vogel 		if (ret_val) {
7118cfa0ad2SJack F Vogel 			DEBUGOUT("Error getting link speed and duplex\n");
7128cfa0ad2SJack F Vogel 			goto out;
7138cfa0ad2SJack F Vogel 		}
7148cfa0ad2SJack F Vogel 
7158cfa0ad2SJack F Vogel 		if (speed != SPEED_1000) {
7168cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
7178cfa0ad2SJack F Vogel 			goto out;
7188cfa0ad2SJack F Vogel 		}
7198cfa0ad2SJack F Vogel 
7208cfa0ad2SJack F Vogel 		ret_val = phy->ops.get_cable_length(hw);
7218cfa0ad2SJack F Vogel 		if (ret_val)
7228cfa0ad2SJack F Vogel 			goto out;
7238cfa0ad2SJack F Vogel 
7248cfa0ad2SJack F Vogel 		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
7258cfa0ad2SJack F Vogel 		    phy->min_cable_length >= 50) {
7268cfa0ad2SJack F Vogel 
7278cfa0ad2SJack F Vogel 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
7288cfa0ad2SJack F Vogel 				ret_val = phy->ops.read_reg(hw,
7298cfa0ad2SJack F Vogel 				                            dsp_reg_array[i],
7308cfa0ad2SJack F Vogel 				                            &phy_data);
7318cfa0ad2SJack F Vogel 				if (ret_val)
7328cfa0ad2SJack F Vogel 					goto out;
7338cfa0ad2SJack F Vogel 
7348cfa0ad2SJack F Vogel 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
7358cfa0ad2SJack F Vogel 
7368cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
7378cfa0ad2SJack F Vogel 				                             dsp_reg_array[i],
7388cfa0ad2SJack F Vogel 				                             phy_data);
7398cfa0ad2SJack F Vogel 				if (ret_val)
7408cfa0ad2SJack F Vogel 					goto out;
7418cfa0ad2SJack F Vogel 			}
7428cfa0ad2SJack F Vogel 			dev_spec->dsp_config = e1000_dsp_config_activated;
7438cfa0ad2SJack F Vogel 		}
7448cfa0ad2SJack F Vogel 
7458cfa0ad2SJack F Vogel 		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
7468cfa0ad2SJack F Vogel 		    (phy->min_cable_length >= 50)) {
7478cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
7488cfa0ad2SJack F Vogel 			goto out;
7498cfa0ad2SJack F Vogel 		}
7508cfa0ad2SJack F Vogel 
7518cfa0ad2SJack F Vogel 		/* clear previous idle error counts */
7528cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
7538cfa0ad2SJack F Vogel 		if (ret_val)
7548cfa0ad2SJack F Vogel 			goto out;
7558cfa0ad2SJack F Vogel 
7568cfa0ad2SJack F Vogel 		for (i = 0; i < ffe_idle_err_timeout; i++) {
7578cfa0ad2SJack F Vogel 			usec_delay(1000);
7588cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
7598cfa0ad2SJack F Vogel 			                            PHY_1000T_STATUS,
7608cfa0ad2SJack F Vogel 			                            &phy_data);
7618cfa0ad2SJack F Vogel 			if (ret_val)
7628cfa0ad2SJack F Vogel 				goto out;
7638cfa0ad2SJack F Vogel 
7648cfa0ad2SJack F Vogel 			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
7658cfa0ad2SJack F Vogel 			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
7668cfa0ad2SJack F Vogel 				dev_spec->ffe_config = e1000_ffe_config_active;
7678cfa0ad2SJack F Vogel 
7688cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
7698cfa0ad2SJack F Vogel 				                  IGP01E1000_PHY_DSP_FFE,
7708cfa0ad2SJack F Vogel 				                  IGP01E1000_PHY_DSP_FFE_CM_CP);
7718cfa0ad2SJack F Vogel 				if (ret_val)
7728cfa0ad2SJack F Vogel 					goto out;
7738cfa0ad2SJack F Vogel 				break;
7748cfa0ad2SJack F Vogel 			}
7758cfa0ad2SJack F Vogel 
7768cfa0ad2SJack F Vogel 			if (idle_errs)
7778cfa0ad2SJack F Vogel 				ffe_idle_err_timeout =
7788cfa0ad2SJack F Vogel 				                 FFE_IDLE_ERR_COUNT_TIMEOUT_100;
7798cfa0ad2SJack F Vogel 		}
7808cfa0ad2SJack F Vogel 	} else {
7818cfa0ad2SJack F Vogel 		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
7828cfa0ad2SJack F Vogel 			/*
7838cfa0ad2SJack F Vogel 			 * Save off the current value of register 0x2F5B
7848cfa0ad2SJack F Vogel 			 * to be restored at the end of the routines.
7858cfa0ad2SJack F Vogel 			 */
7868cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
7878cfa0ad2SJack F Vogel 			                            0x2F5B,
7888cfa0ad2SJack F Vogel 			                            &phy_saved_data);
7898cfa0ad2SJack F Vogel 			if (ret_val)
7908cfa0ad2SJack F Vogel 				goto out;
7918cfa0ad2SJack F Vogel 
7928cfa0ad2SJack F Vogel 			/* Disable the PHY transmitter */
7938cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
7948cfa0ad2SJack F Vogel 			if (ret_val)
7958cfa0ad2SJack F Vogel 				goto out;
7968cfa0ad2SJack F Vogel 
7978cfa0ad2SJack F Vogel 			msec_delay_irq(20);
7988cfa0ad2SJack F Vogel 
7998cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
8008cfa0ad2SJack F Vogel 			                             0x0000,
8018cfa0ad2SJack F Vogel 			                             IGP01E1000_IEEE_FORCE_GIG);
8028cfa0ad2SJack F Vogel 			if (ret_val)
8038cfa0ad2SJack F Vogel 				goto out;
8048cfa0ad2SJack F Vogel 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
8058cfa0ad2SJack F Vogel 				ret_val = phy->ops.read_reg(hw,
8068cfa0ad2SJack F Vogel 				                            dsp_reg_array[i],
8078cfa0ad2SJack F Vogel 				                            &phy_data);
8088cfa0ad2SJack F Vogel 				if (ret_val)
8098cfa0ad2SJack F Vogel 					goto out;
8108cfa0ad2SJack F Vogel 
8118cfa0ad2SJack F Vogel 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
8128cfa0ad2SJack F Vogel 				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
8138cfa0ad2SJack F Vogel 
8148cfa0ad2SJack F Vogel 				ret_val = phy->ops.write_reg(hw,
8158cfa0ad2SJack F Vogel 				                             dsp_reg_array[i],
8168cfa0ad2SJack F Vogel 				                             phy_data);
8178cfa0ad2SJack F Vogel 				if (ret_val)
8188cfa0ad2SJack F Vogel 					goto out;
8198cfa0ad2SJack F Vogel 			}
8208cfa0ad2SJack F Vogel 
8218cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
8228cfa0ad2SJack F Vogel 			                       0x0000,
8238cfa0ad2SJack F Vogel 			                       IGP01E1000_IEEE_RESTART_AUTONEG);
8248cfa0ad2SJack F Vogel 			if (ret_val)
8258cfa0ad2SJack F Vogel 				goto out;
8268cfa0ad2SJack F Vogel 
8278cfa0ad2SJack F Vogel 			msec_delay_irq(20);
8288cfa0ad2SJack F Vogel 
8298cfa0ad2SJack F Vogel 			/* Now enable the transmitter */
8308cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
8318cfa0ad2SJack F Vogel 			                             0x2F5B,
8328cfa0ad2SJack F Vogel 			                             phy_saved_data);
8338cfa0ad2SJack F Vogel 			if (ret_val)
8348cfa0ad2SJack F Vogel 				goto out;
8358cfa0ad2SJack F Vogel 
8368cfa0ad2SJack F Vogel 			dev_spec->dsp_config = e1000_dsp_config_enabled;
8378cfa0ad2SJack F Vogel 		}
8388cfa0ad2SJack F Vogel 
8398cfa0ad2SJack F Vogel 		if (dev_spec->ffe_config != e1000_ffe_config_active) {
8408cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
8418cfa0ad2SJack F Vogel 			goto out;
8428cfa0ad2SJack F Vogel 		}
8438cfa0ad2SJack F Vogel 
8448cfa0ad2SJack F Vogel 		/*
8458cfa0ad2SJack F Vogel 		 * Save off the current value of register 0x2F5B
8468cfa0ad2SJack F Vogel 		 * to be restored at the end of the routines.
8478cfa0ad2SJack F Vogel 		 */
8488cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
8498cfa0ad2SJack F Vogel 		if (ret_val)
8508cfa0ad2SJack F Vogel 			goto out;
8518cfa0ad2SJack F Vogel 
8528cfa0ad2SJack F Vogel 		/* Disable the PHY transmitter */
8538cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
8548cfa0ad2SJack F Vogel 		if (ret_val)
8558cfa0ad2SJack F Vogel 			goto out;
8568cfa0ad2SJack F Vogel 
8578cfa0ad2SJack F Vogel 		msec_delay_irq(20);
8588cfa0ad2SJack F Vogel 
8598cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
8608cfa0ad2SJack F Vogel 		                             0x0000,
8618cfa0ad2SJack F Vogel 		                             IGP01E1000_IEEE_FORCE_GIG);
8628cfa0ad2SJack F Vogel 		if (ret_val)
8638cfa0ad2SJack F Vogel 			goto out;
8648cfa0ad2SJack F Vogel 
8658cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
8668cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_DSP_FFE,
8678cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_DSP_FFE_DEFAULT);
8688cfa0ad2SJack F Vogel 		if (ret_val)
8698cfa0ad2SJack F Vogel 			goto out;
8708cfa0ad2SJack F Vogel 
8718cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
8728cfa0ad2SJack F Vogel 		                             0x0000,
8738cfa0ad2SJack F Vogel 		                             IGP01E1000_IEEE_RESTART_AUTONEG);
8748cfa0ad2SJack F Vogel 		if (ret_val)
8758cfa0ad2SJack F Vogel 			goto out;
8768cfa0ad2SJack F Vogel 
8778cfa0ad2SJack F Vogel 		msec_delay_irq(20);
8788cfa0ad2SJack F Vogel 
8798cfa0ad2SJack F Vogel 		/* Now enable the transmitter */
8808cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
8818cfa0ad2SJack F Vogel 
8828cfa0ad2SJack F Vogel 		if (ret_val)
8838cfa0ad2SJack F Vogel 			goto out;
8848cfa0ad2SJack F Vogel 
8858cfa0ad2SJack F Vogel 		dev_spec->ffe_config = e1000_ffe_config_enabled;
8868cfa0ad2SJack F Vogel 	}
8878cfa0ad2SJack F Vogel 
8888cfa0ad2SJack F Vogel out:
8898cfa0ad2SJack F Vogel 	return ret_val;
8908cfa0ad2SJack F Vogel }
8918cfa0ad2SJack F Vogel 
8928cfa0ad2SJack F Vogel /**
8938cfa0ad2SJack F Vogel  *  e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
8948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8958cfa0ad2SJack F Vogel  *
8968cfa0ad2SJack F Vogel  *  The automatic gain control (agc) normalizes the amplitude of the
8978cfa0ad2SJack F Vogel  *  received signal, adjusting for the attenuation produced by the
8988cfa0ad2SJack F Vogel  *  cable.  By reading the AGC registers, which represent the
8998cfa0ad2SJack F Vogel  *  combination of coarse and fine gain value, the value can be put
9008cfa0ad2SJack F Vogel  *  into a lookup table to obtain the approximate cable length
9018cfa0ad2SJack F Vogel  *  for each channel.  This is a function pointer entry point called by the
9028cfa0ad2SJack F Vogel  *  api module.
9038cfa0ad2SJack F Vogel  **/
9048cfa0ad2SJack F Vogel static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
9058cfa0ad2SJack F Vogel {
9068cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
9078cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
9088cfa0ad2SJack F Vogel 	u16 i, data;
9098cfa0ad2SJack F Vogel 	u16 cur_agc_value, agc_value = 0;
9108cfa0ad2SJack F Vogel 	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
9118cfa0ad2SJack F Vogel 	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
9128cfa0ad2SJack F Vogel 	                                                 {IGP01E1000_PHY_AGC_A,
9138cfa0ad2SJack F Vogel 	                                                  IGP01E1000_PHY_AGC_B,
9148cfa0ad2SJack F Vogel 	                                                  IGP01E1000_PHY_AGC_C,
9158cfa0ad2SJack F Vogel 	                                                  IGP01E1000_PHY_AGC_D};
9168cfa0ad2SJack F Vogel 
9178cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_cable_length_igp_82541");
9188cfa0ad2SJack F Vogel 
9198cfa0ad2SJack F Vogel 	/* Read the AGC registers for all channels */
9208cfa0ad2SJack F Vogel 	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
9218cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
9228cfa0ad2SJack F Vogel 		if (ret_val)
9238cfa0ad2SJack F Vogel 			goto out;
9248cfa0ad2SJack F Vogel 
9258cfa0ad2SJack F Vogel 		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
9268cfa0ad2SJack F Vogel 
9278cfa0ad2SJack F Vogel 		/* Bounds checking */
9288cfa0ad2SJack F Vogel 		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
9298cfa0ad2SJack F Vogel 		    (cur_agc_value == 0)) {
9308cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_PHY;
9318cfa0ad2SJack F Vogel 			goto out;
9328cfa0ad2SJack F Vogel 		}
9338cfa0ad2SJack F Vogel 
9348cfa0ad2SJack F Vogel 		agc_value += cur_agc_value;
9358cfa0ad2SJack F Vogel 
9368cfa0ad2SJack F Vogel 		if (min_agc_value > cur_agc_value)
9378cfa0ad2SJack F Vogel 			min_agc_value = cur_agc_value;
9388cfa0ad2SJack F Vogel 	}
9398cfa0ad2SJack F Vogel 
9408cfa0ad2SJack F Vogel 	/* Remove the minimal AGC result for length < 50m */
9418cfa0ad2SJack F Vogel 	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
9428cfa0ad2SJack F Vogel 		agc_value -= min_agc_value;
9438cfa0ad2SJack F Vogel 		/* Average the three remaining channels for the length. */
9448cfa0ad2SJack F Vogel 		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
9458cfa0ad2SJack F Vogel 	} else {
9468cfa0ad2SJack F Vogel 		/* Average the channels for the length. */
9478cfa0ad2SJack F Vogel 		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
9488cfa0ad2SJack F Vogel 	}
9498cfa0ad2SJack F Vogel 
9508cfa0ad2SJack F Vogel 	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
9518cfa0ad2SJack F Vogel 	                         IGP01E1000_AGC_RANGE)
9528cfa0ad2SJack F Vogel 	                        ? (e1000_igp_cable_length_table[agc_value] -
9538cfa0ad2SJack F Vogel 	                           IGP01E1000_AGC_RANGE)
9548cfa0ad2SJack F Vogel 	                        : 0;
9558cfa0ad2SJack F Vogel 	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
9568cfa0ad2SJack F Vogel 	                        IGP01E1000_AGC_RANGE;
9578cfa0ad2SJack F Vogel 
9588cfa0ad2SJack F Vogel 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
9598cfa0ad2SJack F Vogel 
9608cfa0ad2SJack F Vogel out:
9618cfa0ad2SJack F Vogel 	return ret_val;
9628cfa0ad2SJack F Vogel }
9638cfa0ad2SJack F Vogel 
9648cfa0ad2SJack F Vogel /**
9658cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
9668cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
9678cfa0ad2SJack F Vogel  *  @active: boolean used to enable/disable lplu
9688cfa0ad2SJack F Vogel  *
9698cfa0ad2SJack F Vogel  *  Success returns 0, Failure returns 1
9708cfa0ad2SJack F Vogel  *
9718cfa0ad2SJack F Vogel  *  The low power link up (lplu) state is set to the power management level D3
9728cfa0ad2SJack F Vogel  *  and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
9738cfa0ad2SJack F Vogel  *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
9748cfa0ad2SJack F Vogel  *  is used during Dx states where the power conservation is most important.
9758cfa0ad2SJack F Vogel  *  During driver activity, SmartSpeed should be enabled so performance is
9768cfa0ad2SJack F Vogel  *  maintained.  This is a function pointer entry point called by the
9778cfa0ad2SJack F Vogel  *  api module.
9788cfa0ad2SJack F Vogel  **/
9798cfa0ad2SJack F Vogel static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
9808cfa0ad2SJack F Vogel {
9818cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
9828cfa0ad2SJack F Vogel 	s32 ret_val;
9838cfa0ad2SJack F Vogel 	u16 data;
9848cfa0ad2SJack F Vogel 
9858cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_82541");
9868cfa0ad2SJack F Vogel 
9878cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
9888cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
9898cfa0ad2SJack F Vogel 	case e1000_82547_rev_2:
9908cfa0ad2SJack F Vogel 		break;
9918cfa0ad2SJack F Vogel 	default:
9928cfa0ad2SJack F Vogel 		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
9938cfa0ad2SJack F Vogel 		goto out;
9948cfa0ad2SJack F Vogel 		break;
9958cfa0ad2SJack F Vogel 	}
9968cfa0ad2SJack F Vogel 
9978cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
9988cfa0ad2SJack F Vogel 	if (ret_val)
9998cfa0ad2SJack F Vogel 		goto out;
10008cfa0ad2SJack F Vogel 
10018cfa0ad2SJack F Vogel 	if (!active) {
10028cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_GMII_FLEX_SPD;
10038cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10048cfa0ad2SJack F Vogel 		if (ret_val)
10058cfa0ad2SJack F Vogel 			goto out;
10068cfa0ad2SJack F Vogel 
10078cfa0ad2SJack F Vogel 		/*
10088cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
10098cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
10108cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
10118cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
10128cfa0ad2SJack F Vogel 		 */
10138cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
10148cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
10158cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
10168cfa0ad2SJack F Vogel 			                            &data);
10178cfa0ad2SJack F Vogel 			if (ret_val)
10188cfa0ad2SJack F Vogel 				goto out;
10198cfa0ad2SJack F Vogel 
10208cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
10218cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10228cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
10238cfa0ad2SJack F Vogel 			                             data);
10248cfa0ad2SJack F Vogel 			if (ret_val)
10258cfa0ad2SJack F Vogel 				goto out;
10268cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
10278cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
10288cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
10298cfa0ad2SJack F Vogel 			                            &data);
10308cfa0ad2SJack F Vogel 			if (ret_val)
10318cfa0ad2SJack F Vogel 				goto out;
10328cfa0ad2SJack F Vogel 
10338cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10348cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10358cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
10368cfa0ad2SJack F Vogel 			                             data);
10378cfa0ad2SJack F Vogel 			if (ret_val)
10388cfa0ad2SJack F Vogel 				goto out;
10398cfa0ad2SJack F Vogel 		}
10408cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
10418cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
10428cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
10438cfa0ad2SJack F Vogel 		data |= IGP01E1000_GMII_FLEX_SPD;
10448cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10458cfa0ad2SJack F Vogel 		if (ret_val)
10468cfa0ad2SJack F Vogel 			goto out;
10478cfa0ad2SJack F Vogel 
10488cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
10498cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
10508cfa0ad2SJack F Vogel 		                            IGP01E1000_PHY_PORT_CONFIG,
10518cfa0ad2SJack F Vogel 		                            &data);
10528cfa0ad2SJack F Vogel 		if (ret_val)
10538cfa0ad2SJack F Vogel 			goto out;
10548cfa0ad2SJack F Vogel 
10558cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10568cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
10578cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_PORT_CONFIG,
10588cfa0ad2SJack F Vogel 		                             data);
10598cfa0ad2SJack F Vogel 	}
10608cfa0ad2SJack F Vogel 
10618cfa0ad2SJack F Vogel out:
10628cfa0ad2SJack F Vogel 	return ret_val;
10638cfa0ad2SJack F Vogel }
10648cfa0ad2SJack F Vogel 
10658cfa0ad2SJack F Vogel /**
10668cfa0ad2SJack F Vogel  *  e1000_setup_led_82541 - Configures SW controllable LED
10678cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10688cfa0ad2SJack F Vogel  *
10698cfa0ad2SJack F Vogel  *  This prepares the SW controllable LED for use and saves the current state
10708cfa0ad2SJack F Vogel  *  of the LED so it can be later restored.  This is a function pointer entry
10718cfa0ad2SJack F Vogel  *  point called by the api module.
10728cfa0ad2SJack F Vogel  **/
10738cfa0ad2SJack F Vogel static s32 e1000_setup_led_82541(struct e1000_hw *hw)
10748cfa0ad2SJack F Vogel {
10758cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
10768cfa0ad2SJack F Vogel 	s32 ret_val;
10778cfa0ad2SJack F Vogel 
10788cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_led_82541");
10798cfa0ad2SJack F Vogel 
10808cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
10818cfa0ad2SJack F Vogel 
10828cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw,
10838cfa0ad2SJack F Vogel 	                               IGP01E1000_GMII_FIFO,
10848cfa0ad2SJack F Vogel 	                               &dev_spec->spd_default);
10858cfa0ad2SJack F Vogel 	if (ret_val)
10868cfa0ad2SJack F Vogel 		goto out;
10878cfa0ad2SJack F Vogel 
10888cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw,
10898cfa0ad2SJack F Vogel 	                                IGP01E1000_GMII_FIFO,
10908cfa0ad2SJack F Vogel 	                                (u16)(dev_spec->spd_default &
10918cfa0ad2SJack F Vogel 	                                        ~IGP01E1000_GMII_SPD));
10928cfa0ad2SJack F Vogel 	if (ret_val)
10938cfa0ad2SJack F Vogel 		goto out;
10948cfa0ad2SJack F Vogel 
10958cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
10968cfa0ad2SJack F Vogel 
10978cfa0ad2SJack F Vogel out:
10988cfa0ad2SJack F Vogel 	return ret_val;
10998cfa0ad2SJack F Vogel }
11008cfa0ad2SJack F Vogel 
11018cfa0ad2SJack F Vogel /**
11028cfa0ad2SJack F Vogel  *  e1000_cleanup_led_82541 - Set LED config to default operation
11038cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
11048cfa0ad2SJack F Vogel  *
11058cfa0ad2SJack F Vogel  *  Remove the current LED configuration and set the LED configuration
11068cfa0ad2SJack F Vogel  *  to the default value, saved from the EEPROM.  This is a function pointer
11078cfa0ad2SJack F Vogel  *  entry point called by the api module.
11088cfa0ad2SJack F Vogel  **/
11098cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_82541(struct e1000_hw *hw)
11108cfa0ad2SJack F Vogel {
11118cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
11128cfa0ad2SJack F Vogel 	s32 ret_val;
11138cfa0ad2SJack F Vogel 
11148cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_82541");
11158cfa0ad2SJack F Vogel 
11168cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
11178cfa0ad2SJack F Vogel 
11188cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw,
11198cfa0ad2SJack F Vogel 	                                IGP01E1000_GMII_FIFO,
11208cfa0ad2SJack F Vogel 	                                dev_spec->spd_default);
11218cfa0ad2SJack F Vogel 	if (ret_val)
11228cfa0ad2SJack F Vogel 		goto out;
11238cfa0ad2SJack F Vogel 
11248cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
11258cfa0ad2SJack F Vogel 
11268cfa0ad2SJack F Vogel out:
11278cfa0ad2SJack F Vogel 	return ret_val;
11288cfa0ad2SJack F Vogel }
11298cfa0ad2SJack F Vogel 
11308cfa0ad2SJack F Vogel /**
11318cfa0ad2SJack F Vogel  *  e1000_phy_init_script_82541 - Initialize GbE PHY
11328cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
11338cfa0ad2SJack F Vogel  *
11348cfa0ad2SJack F Vogel  *  Initializes the IGP PHY.
11358cfa0ad2SJack F Vogel  **/
11368cfa0ad2SJack F Vogel static s32 e1000_phy_init_script_82541(struct e1000_hw *hw)
11378cfa0ad2SJack F Vogel {
11388cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
11398cfa0ad2SJack F Vogel 	u32 ret_val;
11408cfa0ad2SJack F Vogel 	u16 phy_saved_data;
11418cfa0ad2SJack F Vogel 
11428cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_init_script_82541");
11438cfa0ad2SJack F Vogel 
11448cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
11458cfa0ad2SJack F Vogel 
11468cfa0ad2SJack F Vogel 	if (!dev_spec->phy_init_script) {
11478cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
11488cfa0ad2SJack F Vogel 		goto out;
11498cfa0ad2SJack F Vogel 	}
11508cfa0ad2SJack F Vogel 
11518cfa0ad2SJack F Vogel 	/* Delay after phy reset to enable NVM configuration to load */
11528cfa0ad2SJack F Vogel 	msec_delay(20);
11538cfa0ad2SJack F Vogel 
11548cfa0ad2SJack F Vogel 	/*
11558cfa0ad2SJack F Vogel 	 * Save off the current value of register 0x2F5B to be restored at
11568cfa0ad2SJack F Vogel 	 * the end of this routine.
11578cfa0ad2SJack F Vogel 	 */
11588cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
11598cfa0ad2SJack F Vogel 
11608cfa0ad2SJack F Vogel 	/* Disabled the PHY transmitter */
11618cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
11628cfa0ad2SJack F Vogel 
11638cfa0ad2SJack F Vogel 	msec_delay(20);
11648cfa0ad2SJack F Vogel 
11658cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
11668cfa0ad2SJack F Vogel 
11678cfa0ad2SJack F Vogel 	msec_delay(5);
11688cfa0ad2SJack F Vogel 
11698cfa0ad2SJack F Vogel 	switch (hw->mac.type) {
11708cfa0ad2SJack F Vogel 	case e1000_82541:
11718cfa0ad2SJack F Vogel 	case e1000_82547:
11728cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
11738cfa0ad2SJack F Vogel 
11748cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
11758cfa0ad2SJack F Vogel 
11768cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
11778cfa0ad2SJack F Vogel 
11788cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
11798cfa0ad2SJack F Vogel 
11808cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
11818cfa0ad2SJack F Vogel 
11828cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
11838cfa0ad2SJack F Vogel 
11848cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
11858cfa0ad2SJack F Vogel 
11868cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
11878cfa0ad2SJack F Vogel 
11888cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
11898cfa0ad2SJack F Vogel 		break;
11908cfa0ad2SJack F Vogel 	case e1000_82541_rev_2:
11918cfa0ad2SJack F Vogel 	case e1000_82547_rev_2:
11928cfa0ad2SJack F Vogel 		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
11938cfa0ad2SJack F Vogel 		break;
11948cfa0ad2SJack F Vogel 	default:
11958cfa0ad2SJack F Vogel 		break;
11968cfa0ad2SJack F Vogel 	}
11978cfa0ad2SJack F Vogel 
11988cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
11998cfa0ad2SJack F Vogel 
12008cfa0ad2SJack F Vogel 	msec_delay(20);
12018cfa0ad2SJack F Vogel 
12028cfa0ad2SJack F Vogel 	/* Now enable the transmitter */
12038cfa0ad2SJack F Vogel 	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
12048cfa0ad2SJack F Vogel 
12058cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_82547) {
12068cfa0ad2SJack F Vogel 		u16 fused, fine, coarse;
12078cfa0ad2SJack F Vogel 
12088cfa0ad2SJack F Vogel 		/* Move to analog registers page */
12098cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw,
12108cfa0ad2SJack F Vogel 		                  IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
12118cfa0ad2SJack F Vogel 		                  &fused);
12128cfa0ad2SJack F Vogel 
12138cfa0ad2SJack F Vogel 		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
12148cfa0ad2SJack F Vogel 			hw->phy.ops.read_reg(hw,
12158cfa0ad2SJack F Vogel 			                  IGP01E1000_ANALOG_FUSE_STATUS,
12168cfa0ad2SJack F Vogel 			                  &fused);
12178cfa0ad2SJack F Vogel 
12188cfa0ad2SJack F Vogel 			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
12198cfa0ad2SJack F Vogel 			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
12208cfa0ad2SJack F Vogel 
12218cfa0ad2SJack F Vogel 			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
12228cfa0ad2SJack F Vogel 				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
12238cfa0ad2SJack F Vogel 				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
12248cfa0ad2SJack F Vogel 			} else if (coarse ==
12258cfa0ad2SJack F Vogel 			           IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
12268cfa0ad2SJack F Vogel 				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
12278cfa0ad2SJack F Vogel 
12288cfa0ad2SJack F Vogel 			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
12298cfa0ad2SJack F Vogel 			        (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
12308cfa0ad2SJack F Vogel 			        (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
12318cfa0ad2SJack F Vogel 
12328cfa0ad2SJack F Vogel 			hw->phy.ops.write_reg(hw,
12338cfa0ad2SJack F Vogel 			                   IGP01E1000_ANALOG_FUSE_CONTROL,
12348cfa0ad2SJack F Vogel 			                   fused);
12358cfa0ad2SJack F Vogel 			hw->phy.ops.write_reg(hw,
12368cfa0ad2SJack F Vogel 			              IGP01E1000_ANALOG_FUSE_BYPASS,
12378cfa0ad2SJack F Vogel 			              IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
12388cfa0ad2SJack F Vogel 		}
12398cfa0ad2SJack F Vogel 	}
12408cfa0ad2SJack F Vogel 
12418cfa0ad2SJack F Vogel out:
12428cfa0ad2SJack F Vogel 	return ret_val;
12438cfa0ad2SJack F Vogel }
12448cfa0ad2SJack F Vogel 
12458cfa0ad2SJack F Vogel /**
12468cfa0ad2SJack F Vogel  *  e1000_init_script_state_82541 - Enable/Disable PHY init script
12478cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12488cfa0ad2SJack F Vogel  *  @state: boolean value used to enable/disable PHY init script
12498cfa0ad2SJack F Vogel  *
12508cfa0ad2SJack F Vogel  *  Allows the driver to enable/disable the PHY init script, if the PHY is an
12518cfa0ad2SJack F Vogel  *  IGP PHY.  This is a function pointer entry point called by the api module.
12528cfa0ad2SJack F Vogel  **/
12538cfa0ad2SJack F Vogel void e1000_init_script_state_82541(struct e1000_hw *hw, bool state)
12548cfa0ad2SJack F Vogel {
12558cfa0ad2SJack F Vogel 	struct e1000_dev_spec_82541 *dev_spec;
12568cfa0ad2SJack F Vogel 
12578cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_script_state_82541");
12588cfa0ad2SJack F Vogel 
12598cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp) {
12608cfa0ad2SJack F Vogel 		DEBUGOUT("Initialization script not necessary.\n");
12618cfa0ad2SJack F Vogel 		goto out;
12628cfa0ad2SJack F Vogel 	}
12638cfa0ad2SJack F Vogel 
12648cfa0ad2SJack F Vogel 	dev_spec = (struct e1000_dev_spec_82541 *)hw->dev_spec;
12658cfa0ad2SJack F Vogel 
12668cfa0ad2SJack F Vogel 	if (!dev_spec) {
12678cfa0ad2SJack F Vogel 		DEBUGOUT("dev_spec pointer is set to NULL.\n");
12688cfa0ad2SJack F Vogel 		goto out;
12698cfa0ad2SJack F Vogel 	}
12708cfa0ad2SJack F Vogel 
12718cfa0ad2SJack F Vogel 	dev_spec->phy_init_script = state;
12728cfa0ad2SJack F Vogel 
12738cfa0ad2SJack F Vogel out:
12748cfa0ad2SJack F Vogel 	return;
12758cfa0ad2SJack F Vogel }
12768cfa0ad2SJack F Vogel 
12778cfa0ad2SJack F Vogel /**
12788cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
12798cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
12808cfa0ad2SJack F Vogel  *
12818cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
12828cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
12838cfa0ad2SJack F Vogel  **/
12848cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
12858cfa0ad2SJack F Vogel {
12868cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
12878cfa0ad2SJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
12888cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
12898cfa0ad2SJack F Vogel 
12908cfa0ad2SJack F Vogel 	return;
12918cfa0ad2SJack F Vogel }
12928cfa0ad2SJack F Vogel 
12938cfa0ad2SJack F Vogel /**
12948cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
12958cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12968cfa0ad2SJack F Vogel  *
12978cfa0ad2SJack F Vogel  *  Clears the hardware counters by reading the counter registers.
12988cfa0ad2SJack F Vogel  **/
12998cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
13008cfa0ad2SJack F Vogel {
13018cfa0ad2SJack F Vogel 	volatile u32 temp;
13028cfa0ad2SJack F Vogel 
13038cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_82541");
13048cfa0ad2SJack F Vogel 
13058cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
13068cfa0ad2SJack F Vogel 
13078cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC64);
13088cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC127);
13098cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC255);
13108cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC511);
13118cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC1023);
13128cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PRC1522);
13138cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC64);
13148cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC127);
13158cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC255);
13168cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC511);
13178cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC1023);
13188cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_PTC1522);
13198cfa0ad2SJack F Vogel 
13208cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_ALGNERRC);
13218cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_RXERRC);
13228cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_TNCRS);
13238cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_CEXTERR);
13248cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_TSCTC);
13258cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_TSCTFC);
13268cfa0ad2SJack F Vogel 
13278cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_MGTPRC);
13288cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_MGTPDC);
13298cfa0ad2SJack F Vogel 	temp = E1000_READ_REG(hw, E1000_MGTPTC);
13308cfa0ad2SJack F Vogel }
1331