xref: /freebsd/sys/dev/e1000/e1000_82575.c (revision 5b426b3e8cbd5abdb3a57ff49cd27c36cac03427)
18cfa0ad2SJack F Vogel /******************************************************************************
27282444bSPedro F. Giffuni   SPDX-License-Identifier: BSD-3-Clause
38cfa0ad2SJack F Vogel 
4702cac6cSKevin Bowling   Copyright (c) 2001-2020, Intel Corporation
58cfa0ad2SJack F Vogel   All rights reserved.
68cfa0ad2SJack F Vogel 
78cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
88cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
98cfa0ad2SJack F Vogel 
108cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
118cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
128cfa0ad2SJack F Vogel 
138cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
148cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
158cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
168cfa0ad2SJack F Vogel 
178cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
188cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
198cfa0ad2SJack F Vogel       this software without specific prior written permission.
208cfa0ad2SJack F Vogel 
218cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
228cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
258cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
268cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
278cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
288cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
298cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
308cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
318cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
328cfa0ad2SJack F Vogel 
338cfa0ad2SJack F Vogel ******************************************************************************/
348cfa0ad2SJack F Vogel /*$FreeBSD$*/
358cfa0ad2SJack F Vogel 
36daf9197cSJack F Vogel /*
37daf9197cSJack F Vogel  * 82575EB Gigabit Network Connection
38daf9197cSJack F Vogel  * 82575EB Gigabit Backplane Connection
39daf9197cSJack F Vogel  * 82575GB Gigabit Network Connection
40daf9197cSJack F Vogel  * 82576 Gigabit Network Connection
419d81738fSJack F Vogel  * 82576 Quad Port Gigabit Mezzanine Adapter
42ab5d0362SJack F Vogel  * 82580 Gigabit Network Connection
43ab5d0362SJack F Vogel  * I350 Gigabit Network Connection
448cfa0ad2SJack F Vogel  */
458cfa0ad2SJack F Vogel 
468cfa0ad2SJack F Vogel #include "e1000_api.h"
47ab5d0362SJack F Vogel #include "e1000_i210.h"
488cfa0ad2SJack F Vogel 
498cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_82575(struct e1000_hw *hw);
508cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_82575(struct e1000_hw *hw);
518cfa0ad2SJack F Vogel static s32  e1000_acquire_phy_82575(struct e1000_hw *hw);
528cfa0ad2SJack F Vogel static void e1000_release_phy_82575(struct e1000_hw *hw);
538cfa0ad2SJack F Vogel static s32  e1000_acquire_nvm_82575(struct e1000_hw *hw);
548cfa0ad2SJack F Vogel static void e1000_release_nvm_82575(struct e1000_hw *hw);
558cfa0ad2SJack F Vogel static s32  e1000_check_for_link_82575(struct e1000_hw *hw);
567609433eSJack F Vogel static s32  e1000_check_for_link_media_swap(struct e1000_hw *hw);
578cfa0ad2SJack F Vogel static s32  e1000_get_cfg_done_82575(struct e1000_hw *hw);
588cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
598cfa0ad2SJack F Vogel 					 u16 *duplex);
608cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw);
618cfa0ad2SJack F Vogel static s32  e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
628cfa0ad2SJack F Vogel 					   u16 *data);
638cfa0ad2SJack F Vogel static s32  e1000_reset_hw_82575(struct e1000_hw *hw);
644edd8523SJack F Vogel static s32  e1000_reset_hw_82580(struct e1000_hw *hw);
654edd8523SJack F Vogel static s32  e1000_read_phy_reg_82580(struct e1000_hw *hw,
664edd8523SJack F Vogel 				     u32 offset, u16 *data);
674edd8523SJack F Vogel static s32  e1000_write_phy_reg_82580(struct e1000_hw *hw,
684edd8523SJack F Vogel 				      u32 offset, u16 data);
69f0ecc46dSJack F Vogel static s32  e1000_set_d0_lplu_state_82580(struct e1000_hw *hw,
70f0ecc46dSJack F Vogel 					  bool active);
71f0ecc46dSJack F Vogel static s32  e1000_set_d3_lplu_state_82580(struct e1000_hw *hw,
72f0ecc46dSJack F Vogel 					  bool active);
738cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_82575(struct e1000_hw *hw,
748cfa0ad2SJack F Vogel 					  bool active);
758cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_82575(struct e1000_hw *hw);
764edd8523SJack F Vogel static s32  e1000_setup_serdes_link_82575(struct e1000_hw *hw);
774dab5c37SJack F Vogel static s32  e1000_get_media_type_82575(struct e1000_hw *hw);
784dab5c37SJack F Vogel static s32  e1000_set_sfp_media_type_82575(struct e1000_hw *hw);
798cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data);
808cfa0ad2SJack F Vogel static s32  e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw,
818cfa0ad2SJack F Vogel 					    u32 offset, u16 data);
828cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw);
838cfa0ad2SJack F Vogel static s32  e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
848cfa0ad2SJack F Vogel 						 u16 *speed, u16 *duplex);
858cfa0ad2SJack F Vogel static s32  e1000_get_phy_id_82575(struct e1000_hw *hw);
868cfa0ad2SJack F Vogel static bool e1000_sgmii_active_82575(struct e1000_hw *hw);
878cfa0ad2SJack F Vogel static s32  e1000_reset_init_script_82575(struct e1000_hw *hw);
888cfa0ad2SJack F Vogel static s32  e1000_read_mac_addr_82575(struct e1000_hw *hw);
89a69ed8dfSJack F Vogel static void e1000_config_collision_dist_82575(struct e1000_hw *hw);
908cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw);
914edd8523SJack F Vogel static void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw);
92a69ed8dfSJack F Vogel static void e1000_power_up_serdes_link_82575(struct e1000_hw *hw);
939d81738fSJack F Vogel static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw);
947d9119bdSJack F Vogel static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw);
95f0ecc46dSJack F Vogel static s32 e1000_validate_nvm_checksum_82580(struct e1000_hw *hw);
96f0ecc46dSJack F Vogel static s32 e1000_update_nvm_checksum_82580(struct e1000_hw *hw);
97f0ecc46dSJack F Vogel static s32 e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw,
98f0ecc46dSJack F Vogel 						 u16 offset);
99f0ecc46dSJack F Vogel static s32 e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw,
100f0ecc46dSJack F Vogel 						   u16 offset);
101f0ecc46dSJack F Vogel static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw);
102f0ecc46dSJack F Vogel static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw);
1034dab5c37SJack F Vogel static void e1000_clear_vfta_i350(struct e1000_hw *hw);
1048cfa0ad2SJack F Vogel 
1054dab5c37SJack F Vogel static void e1000_i2c_start(struct e1000_hw *hw);
1064dab5c37SJack F Vogel static void e1000_i2c_stop(struct e1000_hw *hw);
1074dab5c37SJack F Vogel static s32 e1000_clock_in_i2c_byte(struct e1000_hw *hw, u8 *data);
1084dab5c37SJack F Vogel static s32 e1000_clock_out_i2c_byte(struct e1000_hw *hw, u8 data);
1094dab5c37SJack F Vogel static s32 e1000_get_i2c_ack(struct e1000_hw *hw);
1104dab5c37SJack F Vogel static s32 e1000_clock_in_i2c_bit(struct e1000_hw *hw, bool *data);
1114dab5c37SJack F Vogel static s32 e1000_clock_out_i2c_bit(struct e1000_hw *hw, bool data);
1124dab5c37SJack F Vogel static void e1000_raise_i2c_clk(struct e1000_hw *hw, u32 *i2cctl);
1134dab5c37SJack F Vogel static void e1000_lower_i2c_clk(struct e1000_hw *hw, u32 *i2cctl);
1144dab5c37SJack F Vogel static s32 e1000_set_i2c_data(struct e1000_hw *hw, u32 *i2cctl, bool data);
1154dab5c37SJack F Vogel static bool e1000_get_i2c_data(u32 *i2cctl);
1164dab5c37SJack F Vogel 
1174dab5c37SJack F Vogel static const u16 e1000_82580_rxpbs_table[] = {
1184dab5c37SJack F Vogel 	36, 72, 144, 1, 2, 4, 8, 16, 35, 70, 140 };
1194edd8523SJack F Vogel #define E1000_82580_RXPBS_TABLE_SIZE \
1208cc64f1eSJack F Vogel 	(sizeof(e1000_82580_rxpbs_table) / \
1218cc64f1eSJack F Vogel 	 sizeof(e1000_82580_rxpbs_table[0]))
1224edd8523SJack F Vogel 
1237d9119bdSJack F Vogel 
1247d9119bdSJack F Vogel /**
1257d9119bdSJack F Vogel  *  e1000_sgmii_uses_mdio_82575 - Determine if I2C pins are for external MDIO
1267d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
1277d9119bdSJack F Vogel  *
1287d9119bdSJack F Vogel  *  Called to determine if the I2C pins are being used for I2C or as an
1297d9119bdSJack F Vogel  *  external MDIO interface since the two options are mutually exclusive.
1307d9119bdSJack F Vogel  **/
1317d9119bdSJack F Vogel static bool e1000_sgmii_uses_mdio_82575(struct e1000_hw *hw)
1327d9119bdSJack F Vogel {
1337d9119bdSJack F Vogel 	u32 reg = 0;
1347d9119bdSJack F Vogel 	bool ext_mdio = FALSE;
1357d9119bdSJack F Vogel 
1367d9119bdSJack F Vogel 	DEBUGFUNC("e1000_sgmii_uses_mdio_82575");
1377d9119bdSJack F Vogel 
1387d9119bdSJack F Vogel 	switch (hw->mac.type) {
1397d9119bdSJack F Vogel 	case e1000_82575:
1407d9119bdSJack F Vogel 	case e1000_82576:
1417d9119bdSJack F Vogel 		reg = E1000_READ_REG(hw, E1000_MDIC);
1427d9119bdSJack F Vogel 		ext_mdio = !!(reg & E1000_MDIC_DEST);
1437d9119bdSJack F Vogel 		break;
1447d9119bdSJack F Vogel 	case e1000_82580:
145f0ecc46dSJack F Vogel 	case e1000_i350:
1467609433eSJack F Vogel 	case e1000_i354:
1476ab6bfe3SJack F Vogel 	case e1000_i210:
1486ab6bfe3SJack F Vogel 	case e1000_i211:
1497d9119bdSJack F Vogel 		reg = E1000_READ_REG(hw, E1000_MDICNFG);
1507d9119bdSJack F Vogel 		ext_mdio = !!(reg & E1000_MDICNFG_EXT_MDIO);
1517d9119bdSJack F Vogel 		break;
1527d9119bdSJack F Vogel 	default:
1537d9119bdSJack F Vogel 		break;
1547d9119bdSJack F Vogel 	}
1557d9119bdSJack F Vogel 	return ext_mdio;
1567d9119bdSJack F Vogel }
1577d9119bdSJack F Vogel 
1588cfa0ad2SJack F Vogel /**
1598cfa0ad2SJack F Vogel  *  e1000_init_phy_params_82575 - Init PHY func ptrs.
1608cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
1618cfa0ad2SJack F Vogel  **/
1628cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_82575(struct e1000_hw *hw)
1638cfa0ad2SJack F Vogel {
1648cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
1658cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1667d9119bdSJack F Vogel 	u32 ctrl_ext;
1678cfa0ad2SJack F Vogel 
1688cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_82575");
1698cfa0ad2SJack F Vogel 
170ab5d0362SJack F Vogel 	phy->ops.read_i2c_byte = e1000_read_i2c_byte_generic;
171ab5d0362SJack F Vogel 	phy->ops.write_i2c_byte = e1000_write_i2c_byte_generic;
172ab5d0362SJack F Vogel 
1738cfa0ad2SJack F Vogel 	if (hw->phy.media_type != e1000_media_type_copper) {
1748cfa0ad2SJack F Vogel 		phy->type = e1000_phy_none;
1758cfa0ad2SJack F Vogel 		goto out;
1764edd8523SJack F Vogel 	}
1774edd8523SJack F Vogel 
1788cfa0ad2SJack F Vogel 	phy->ops.power_up   = e1000_power_up_phy_copper;
1798cfa0ad2SJack F Vogel 	phy->ops.power_down = e1000_power_down_phy_copper_82575;
1808cfa0ad2SJack F Vogel 
1818cfa0ad2SJack F Vogel 	phy->autoneg_mask	= AUTONEG_ADVERTISE_SPEED_DEFAULT;
1828cfa0ad2SJack F Vogel 	phy->reset_delay_us	= 100;
1838cfa0ad2SJack F Vogel 
1848cfa0ad2SJack F Vogel 	phy->ops.acquire	= e1000_acquire_phy_82575;
1858cfa0ad2SJack F Vogel 	phy->ops.check_reset_block = e1000_check_reset_block_generic;
1868cfa0ad2SJack F Vogel 	phy->ops.commit		= e1000_phy_sw_reset_generic;
1878cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done	= e1000_get_cfg_done_82575;
1888cfa0ad2SJack F Vogel 	phy->ops.release	= e1000_release_phy_82575;
1898cfa0ad2SJack F Vogel 
1907d9119bdSJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
1917d9119bdSJack F Vogel 
1928cfa0ad2SJack F Vogel 	if (e1000_sgmii_active_82575(hw)) {
1938cfa0ad2SJack F Vogel 		phy->ops.reset = e1000_phy_hw_reset_sgmii_82575;
1947d9119bdSJack F Vogel 		ctrl_ext |= E1000_CTRL_I2C_ENA;
1957d9119bdSJack F Vogel 	} else {
1967d9119bdSJack F Vogel 		phy->ops.reset = e1000_phy_hw_reset_generic;
1977d9119bdSJack F Vogel 		ctrl_ext &= ~E1000_CTRL_I2C_ENA;
1987d9119bdSJack F Vogel 	}
1997d9119bdSJack F Vogel 
2007d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
2017d9119bdSJack F Vogel 	e1000_reset_mdicnfg_82580(hw);
2027d9119bdSJack F Vogel 
2037d9119bdSJack F Vogel 	if (e1000_sgmii_active_82575(hw) && !e1000_sgmii_uses_mdio_82575(hw)) {
2048cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_sgmii_82575;
2058cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_sgmii_82575;
206ab5d0362SJack F Vogel 	} else {
207ab5d0362SJack F Vogel 		switch (hw->mac.type) {
208ab5d0362SJack F Vogel 		case e1000_82580:
209ab5d0362SJack F Vogel 		case e1000_i350:
2107609433eSJack F Vogel 		case e1000_i354:
2114edd8523SJack F Vogel 			phy->ops.read_reg = e1000_read_phy_reg_82580;
2124edd8523SJack F Vogel 			phy->ops.write_reg = e1000_write_phy_reg_82580;
213ab5d0362SJack F Vogel 			break;
214ab5d0362SJack F Vogel 		case e1000_i210:
215ab5d0362SJack F Vogel 		case e1000_i211:
216ab5d0362SJack F Vogel 			phy->ops.read_reg = e1000_read_phy_reg_gs40g;
217ab5d0362SJack F Vogel 			phy->ops.write_reg = e1000_write_phy_reg_gs40g;
218ab5d0362SJack F Vogel 			break;
219ab5d0362SJack F Vogel 		default:
2208cfa0ad2SJack F Vogel 			phy->ops.read_reg = e1000_read_phy_reg_igp;
2218cfa0ad2SJack F Vogel 			phy->ops.write_reg = e1000_write_phy_reg_igp;
2228cfa0ad2SJack F Vogel 		}
223ab5d0362SJack F Vogel 	}
2248cfa0ad2SJack F Vogel 
2258cfa0ad2SJack F Vogel 	/* Set phy->phy_addr and phy->id. */
2268cfa0ad2SJack F Vogel 	ret_val = e1000_get_phy_id_82575(hw);
2278cfa0ad2SJack F Vogel 
2288cfa0ad2SJack F Vogel 	/* Verify phy id and set remaining function pointers */
2298cfa0ad2SJack F Vogel 	switch (phy->id) {
2307609433eSJack F Vogel 	case M88E1543_E_PHY_ID:
2317609433eSJack F Vogel 	case M88E1512_E_PHY_ID:
232f0ecc46dSJack F Vogel 	case I347AT4_E_PHY_ID:
233f0ecc46dSJack F Vogel 	case M88E1112_E_PHY_ID:
2341fd3c44fSJack F Vogel 	case M88E1340M_E_PHY_ID:
2358cfa0ad2SJack F Vogel 	case M88E1111_I_PHY_ID:
2368cfa0ad2SJack F Vogel 		phy->type		= e1000_phy_m88;
2378cfa0ad2SJack F Vogel 		phy->ops.check_polarity	= e1000_check_polarity_m88;
2388cfa0ad2SJack F Vogel 		phy->ops.get_info	= e1000_get_phy_info_m88;
239f0ecc46dSJack F Vogel 		if (phy->id == I347AT4_E_PHY_ID ||
2401fd3c44fSJack F Vogel 		    phy->id == M88E1112_E_PHY_ID ||
2411fd3c44fSJack F Vogel 		    phy->id == M88E1340M_E_PHY_ID)
2424dab5c37SJack F Vogel 			phy->ops.get_cable_length =
2434dab5c37SJack F Vogel 					 e1000_get_cable_length_m88_gen2;
2447609433eSJack F Vogel 		else if (phy->id == M88E1543_E_PHY_ID ||
2457609433eSJack F Vogel 			 phy->id == M88E1512_E_PHY_ID)
2467609433eSJack F Vogel 			phy->ops.get_cable_length =
2477609433eSJack F Vogel 					 e1000_get_cable_length_m88_gen2;
248f0ecc46dSJack F Vogel 		else
2498cfa0ad2SJack F Vogel 			phy->ops.get_cable_length = e1000_get_cable_length_m88;
2508cfa0ad2SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
2517609433eSJack F Vogel 		/* Check if this PHY is confgured for media swap. */
2527609433eSJack F Vogel 		if (phy->id == M88E1112_E_PHY_ID) {
2537609433eSJack F Vogel 			u16 data;
2547609433eSJack F Vogel 
2557609433eSJack F Vogel 			ret_val = phy->ops.write_reg(hw,
2567609433eSJack F Vogel 						     E1000_M88E1112_PAGE_ADDR,
2577609433eSJack F Vogel 						     2);
2587609433eSJack F Vogel 			if (ret_val)
2597609433eSJack F Vogel 				goto out;
2607609433eSJack F Vogel 
2617609433eSJack F Vogel 			ret_val = phy->ops.read_reg(hw,
2627609433eSJack F Vogel 						    E1000_M88E1112_MAC_CTRL_1,
2637609433eSJack F Vogel 						    &data);
2647609433eSJack F Vogel 			if (ret_val)
2657609433eSJack F Vogel 				goto out;
2667609433eSJack F Vogel 
2677609433eSJack F Vogel 			data = (data & E1000_M88E1112_MAC_CTRL_1_MODE_MASK) >>
2687609433eSJack F Vogel 			       E1000_M88E1112_MAC_CTRL_1_MODE_SHIFT;
2697609433eSJack F Vogel 			if (data == E1000_M88E1112_AUTO_COPPER_SGMII ||
2707609433eSJack F Vogel 			    data == E1000_M88E1112_AUTO_COPPER_BASEX)
2717609433eSJack F Vogel 				hw->mac.ops.check_for_link =
2727609433eSJack F Vogel 						e1000_check_for_link_media_swap;
2737609433eSJack F Vogel 		}
2748cc64f1eSJack F Vogel 		if (phy->id == M88E1512_E_PHY_ID) {
2758cc64f1eSJack F Vogel 			ret_val = e1000_initialize_M88E1512_phy(hw);
2768cc64f1eSJack F Vogel 			if (ret_val)
2778cc64f1eSJack F Vogel 				goto out;
2788cc64f1eSJack F Vogel 		}
279c80429ceSEric Joyner 		if (phy->id == M88E1543_E_PHY_ID) {
280c80429ceSEric Joyner 			ret_val = e1000_initialize_M88E1543_phy(hw);
281c80429ceSEric Joyner 			if (ret_val)
282c80429ceSEric Joyner 				goto out;
283c80429ceSEric Joyner 		}
2848cfa0ad2SJack F Vogel 		break;
2858cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
2868cfa0ad2SJack F Vogel 	case IGP04E1000_E_PHY_ID:
2878cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
2888cfa0ad2SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_igp;
2898cfa0ad2SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_igp;
2908cfa0ad2SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
2918cfa0ad2SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
2928cfa0ad2SJack F Vogel 		phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82575;
2938cfa0ad2SJack F Vogel 		phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_generic;
2948cfa0ad2SJack F Vogel 		break;
2954edd8523SJack F Vogel 	case I82580_I_PHY_ID:
296f0ecc46dSJack F Vogel 	case I350_I_PHY_ID:
2974edd8523SJack F Vogel 		phy->type = e1000_phy_82580;
2984edd8523SJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
2994dab5c37SJack F Vogel 		phy->ops.force_speed_duplex =
3004dab5c37SJack F Vogel 					 e1000_phy_force_speed_duplex_82577;
3014edd8523SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_82577;
3024edd8523SJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
303f0ecc46dSJack F Vogel 		phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82580;
304f0ecc46dSJack F Vogel 		phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82580;
3054edd8523SJack F Vogel 		break;
306ab5d0362SJack F Vogel 	case I210_I_PHY_ID:
307ab5d0362SJack F Vogel 		phy->type		= e1000_phy_i210;
308ab5d0362SJack F Vogel 		phy->ops.check_polarity	= e1000_check_polarity_m88;
309ab5d0362SJack F Vogel 		phy->ops.get_info	= e1000_get_phy_info_m88;
310ab5d0362SJack F Vogel 		phy->ops.get_cable_length = e1000_get_cable_length_m88_gen2;
311ab5d0362SJack F Vogel 		phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_82580;
312ab5d0362SJack F Vogel 		phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82580;
313ab5d0362SJack F Vogel 		phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
314ab5d0362SJack F Vogel 		break;
3158cfa0ad2SJack F Vogel 	default:
3168cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
3178cfa0ad2SJack F Vogel 		goto out;
3188cfa0ad2SJack F Vogel 	}
3198cfa0ad2SJack F Vogel 
3208cfa0ad2SJack F Vogel out:
3218cfa0ad2SJack F Vogel 	return ret_val;
3228cfa0ad2SJack F Vogel }
3238cfa0ad2SJack F Vogel 
3248cfa0ad2SJack F Vogel /**
3258cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_82575 - Init NVM func ptrs.
3268cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3278cfa0ad2SJack F Vogel  **/
3281fd3c44fSJack F Vogel s32 e1000_init_nvm_params_82575(struct e1000_hw *hw)
3298cfa0ad2SJack F Vogel {
3308cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
3318cfa0ad2SJack F Vogel 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
3328cfa0ad2SJack F Vogel 	u16 size;
3338cfa0ad2SJack F Vogel 
3348cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_82575");
3358cfa0ad2SJack F Vogel 
336f0ecc46dSJack F Vogel 	size = (u16)((eecd & E1000_EECD_SIZE_EX_MASK) >>
337f0ecc46dSJack F Vogel 		     E1000_EECD_SIZE_EX_SHIFT);
338f0ecc46dSJack F Vogel 	/*
339f0ecc46dSJack F Vogel 	 * Added to a constant, "size" becomes the left-shift value
340f0ecc46dSJack F Vogel 	 * for setting word_size.
341f0ecc46dSJack F Vogel 	 */
342f0ecc46dSJack F Vogel 	size += NVM_WORD_SIZE_BASE_SHIFT;
343f0ecc46dSJack F Vogel 
3444dab5c37SJack F Vogel 	/* Just in case size is out of range, cap it to the largest
3454dab5c37SJack F Vogel 	 * EEPROM size supported
3464dab5c37SJack F Vogel 	 */
3474dab5c37SJack F Vogel 	if (size > 15)
3484dab5c37SJack F Vogel 		size = 15;
3494dab5c37SJack F Vogel 
350f0ecc46dSJack F Vogel 	nvm->word_size = 1 << size;
351ab5d0362SJack F Vogel 	if (hw->mac.type < e1000_i210) {
3528cfa0ad2SJack F Vogel 		nvm->opcode_bits = 8;
3538cfa0ad2SJack F Vogel 		nvm->delay_usec = 1;
354ab5d0362SJack F Vogel 
3558cfa0ad2SJack F Vogel 		switch (nvm->override) {
3568cfa0ad2SJack F Vogel 		case e1000_nvm_override_spi_large:
3578cfa0ad2SJack F Vogel 			nvm->page_size = 32;
3588cfa0ad2SJack F Vogel 			nvm->address_bits = 16;
3598cfa0ad2SJack F Vogel 			break;
3608cfa0ad2SJack F Vogel 		case e1000_nvm_override_spi_small:
3618cfa0ad2SJack F Vogel 			nvm->page_size = 8;
3628cfa0ad2SJack F Vogel 			nvm->address_bits = 8;
3638cfa0ad2SJack F Vogel 			break;
3648cfa0ad2SJack F Vogel 		default:
3658cfa0ad2SJack F Vogel 			nvm->page_size = eecd & E1000_EECD_ADDR_BITS ? 32 : 8;
366ab5d0362SJack F Vogel 			nvm->address_bits = eecd & E1000_EECD_ADDR_BITS ?
367ab5d0362SJack F Vogel 					    16 : 8;
3688cfa0ad2SJack F Vogel 			break;
3698cfa0ad2SJack F Vogel 		}
3701fd3c44fSJack F Vogel 		if (nvm->word_size == (1 << 15))
371f0ecc46dSJack F Vogel 			nvm->page_size = 128;
3728cfa0ad2SJack F Vogel 
373ab5d0362SJack F Vogel 		nvm->type = e1000_nvm_eeprom_spi;
374ab5d0362SJack F Vogel 	} else {
375ab5d0362SJack F Vogel 		nvm->type = e1000_nvm_flash_hw;
376ab5d0362SJack F Vogel 	}
3776ab6bfe3SJack F Vogel 
3788cfa0ad2SJack F Vogel 	/* Function Pointers */
3798cfa0ad2SJack F Vogel 	nvm->ops.acquire = e1000_acquire_nvm_82575;
3808cfa0ad2SJack F Vogel 	nvm->ops.release = e1000_release_nvm_82575;
3811fd3c44fSJack F Vogel 	if (nvm->word_size < (1 << 15))
3821fd3c44fSJack F Vogel 		nvm->ops.read = e1000_read_nvm_eerd;
3831fd3c44fSJack F Vogel 	else
3841fd3c44fSJack F Vogel 		nvm->ops.read = e1000_read_nvm_spi;
3851fd3c44fSJack F Vogel 
3861fd3c44fSJack F Vogel 	nvm->ops.write = e1000_write_nvm_spi;
3871fd3c44fSJack F Vogel 	nvm->ops.validate = e1000_validate_nvm_checksum_generic;
3881fd3c44fSJack F Vogel 	nvm->ops.update = e1000_update_nvm_checksum_generic;
3898cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_82575;
3901fd3c44fSJack F Vogel 
391ab5d0362SJack F Vogel 	/* override generic family function pointers for specific descendants */
392f0ecc46dSJack F Vogel 	switch (hw->mac.type) {
393f0ecc46dSJack F Vogel 	case e1000_82580:
394f0ecc46dSJack F Vogel 		nvm->ops.validate = e1000_validate_nvm_checksum_82580;
395f0ecc46dSJack F Vogel 		nvm->ops.update = e1000_update_nvm_checksum_82580;
396f0ecc46dSJack F Vogel 		break;
397f0ecc46dSJack F Vogel 	case e1000_i350:
3987609433eSJack F Vogel 	case e1000_i354:
399f0ecc46dSJack F Vogel 		nvm->ops.validate = e1000_validate_nvm_checksum_i350;
400f0ecc46dSJack F Vogel 		nvm->ops.update = e1000_update_nvm_checksum_i350;
401f0ecc46dSJack F Vogel 		break;
402f0ecc46dSJack F Vogel 	default:
4031fd3c44fSJack F Vogel 		break;
404f0ecc46dSJack F Vogel 	}
4058cfa0ad2SJack F Vogel 
4068cfa0ad2SJack F Vogel 	return E1000_SUCCESS;
4078cfa0ad2SJack F Vogel }
4088cfa0ad2SJack F Vogel 
4098cfa0ad2SJack F Vogel /**
4108cfa0ad2SJack F Vogel  *  e1000_init_mac_params_82575 - Init MAC func ptrs.
4118cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4128cfa0ad2SJack F Vogel  **/
4138cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_82575(struct e1000_hw *hw)
4148cfa0ad2SJack F Vogel {
4158cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
416daf9197cSJack F Vogel 	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
4178cfa0ad2SJack F Vogel 
4188cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_82575");
4198cfa0ad2SJack F Vogel 
4204dab5c37SJack F Vogel 	/* Derives media type */
4214dab5c37SJack F Vogel 	e1000_get_media_type_82575(hw);
4228cfa0ad2SJack F Vogel 	/* Set mta register count */
4238cfa0ad2SJack F Vogel 	mac->mta_reg_count = 128;
4244edd8523SJack F Vogel 	/* Set uta register count */
4254edd8523SJack F Vogel 	mac->uta_reg_count = (hw->mac.type == e1000_82575) ? 0 : 128;
4268cfa0ad2SJack F Vogel 	/* Set rar entry count */
4278cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_RAR_ENTRIES_82575;
4288cfa0ad2SJack F Vogel 	if (mac->type == e1000_82576)
4298cfa0ad2SJack F Vogel 		mac->rar_entry_count = E1000_RAR_ENTRIES_82576;
430a69ed8dfSJack F Vogel 	if (mac->type == e1000_82580)
4314edd8523SJack F Vogel 		mac->rar_entry_count = E1000_RAR_ENTRIES_82580;
4327609433eSJack F Vogel 	if (mac->type == e1000_i350 || mac->type == e1000_i354)
433f0ecc46dSJack F Vogel 		mac->rar_entry_count = E1000_RAR_ENTRIES_I350;
4346ab6bfe3SJack F Vogel 
4356ab6bfe3SJack F Vogel 	/* Enable EEE default settings for EEE supported devices */
4366ab6bfe3SJack F Vogel 	if (mac->type >= e1000_i350)
437f0ecc46dSJack F Vogel 		dev_spec->eee_disable = FALSE;
4386ab6bfe3SJack F Vogel 
4396ab6bfe3SJack F Vogel 	/* Allow a single clear of the SW semaphore on I210 and newer */
4406ab6bfe3SJack F Vogel 	if (mac->type >= e1000_i210)
4416ab6bfe3SJack F Vogel 		dev_spec->clear_semaphore_once = TRUE;
442f0ecc46dSJack F Vogel 
4438cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
4448cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
4458ec87fc5SJack F Vogel 	/* FWSM register */
4468ec87fc5SJack F Vogel 	mac->has_fwsm = TRUE;
4478ec87fc5SJack F Vogel 	/* ARC supported; valid only if manageability features are enabled. */
4488cfa0ad2SJack F Vogel 	mac->arc_subsystem_valid =
449ab5d0362SJack F Vogel 		!!(E1000_READ_REG(hw, E1000_FWSM) & E1000_FWSM_MODE_MASK);
4508cfa0ad2SJack F Vogel 
4518cfa0ad2SJack F Vogel 	/* Function pointers */
4528cfa0ad2SJack F Vogel 
4538cfa0ad2SJack F Vogel 	/* bus type/speed/width */
4548cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_pcie_generic;
4558cfa0ad2SJack F Vogel 	/* reset */
456a69ed8dfSJack F Vogel 	if (mac->type >= e1000_82580)
4574edd8523SJack F Vogel 		mac->ops.reset_hw = e1000_reset_hw_82580;
4584edd8523SJack F Vogel 	else
4598cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_82575;
4608cfa0ad2SJack F Vogel 	/* hw initialization */
4618cc64f1eSJack F Vogel 	if ((mac->type == e1000_i210) || (mac->type == e1000_i211))
4628cc64f1eSJack F Vogel 		mac->ops.init_hw = e1000_init_hw_i210;
4638cc64f1eSJack F Vogel 	else
4648cfa0ad2SJack F Vogel 		mac->ops.init_hw = e1000_init_hw_82575;
4658cfa0ad2SJack F Vogel 	/* link setup */
4668cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_generic;
4678cfa0ad2SJack F Vogel 	/* physical interface link setup */
4688cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface =
4698cfa0ad2SJack F Vogel 		(hw->phy.media_type == e1000_media_type_copper)
4704dab5c37SJack F Vogel 		? e1000_setup_copper_link_82575 : e1000_setup_serdes_link_82575;
4718cfa0ad2SJack F Vogel 	/* physical interface shutdown */
4724edd8523SJack F Vogel 	mac->ops.shutdown_serdes = e1000_shutdown_serdes_link_82575;
473a69ed8dfSJack F Vogel 	/* physical interface power up */
474a69ed8dfSJack F Vogel 	mac->ops.power_up_serdes = e1000_power_up_serdes_link_82575;
4758cfa0ad2SJack F Vogel 	/* check for link */
4768cfa0ad2SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_link_82575;
4778cfa0ad2SJack F Vogel 	/* read mac address */
4788cfa0ad2SJack F Vogel 	mac->ops.read_mac_addr = e1000_read_mac_addr_82575;
479a69ed8dfSJack F Vogel 	/* configure collision distance */
480a69ed8dfSJack F Vogel 	mac->ops.config_collision_dist = e1000_config_collision_dist_82575;
4818cfa0ad2SJack F Vogel 	/* multicast address update */
482d035aa2dSJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
4837609433eSJack F Vogel 	if (hw->mac.type == e1000_i350 || mac->type == e1000_i354) {
4844dab5c37SJack F Vogel 		/* writing VFTA */
4854dab5c37SJack F Vogel 		mac->ops.write_vfta = e1000_write_vfta_i350;
4864dab5c37SJack F Vogel 		/* clearing VFTA */
4874dab5c37SJack F Vogel 		mac->ops.clear_vfta = e1000_clear_vfta_i350;
4884dab5c37SJack F Vogel 	} else {
4898cfa0ad2SJack F Vogel 		/* writing VFTA */
4908cfa0ad2SJack F Vogel 		mac->ops.write_vfta = e1000_write_vfta_generic;
4918cfa0ad2SJack F Vogel 		/* clearing VFTA */
4928cfa0ad2SJack F Vogel 		mac->ops.clear_vfta = e1000_clear_vfta_generic;
4934dab5c37SJack F Vogel 	}
4946ab6bfe3SJack F Vogel 	if (hw->mac.type >= e1000_82580)
4956ab6bfe3SJack F Vogel 		mac->ops.validate_mdi_setting =
4966ab6bfe3SJack F Vogel 				e1000_validate_mdi_setting_crossover_generic;
497d035aa2dSJack F Vogel 	/* ID LED init */
498d035aa2dSJack F Vogel 	mac->ops.id_led_init = e1000_id_led_init_generic;
4998cfa0ad2SJack F Vogel 	/* blink LED */
5008cfa0ad2SJack F Vogel 	mac->ops.blink_led = e1000_blink_led_generic;
5018cfa0ad2SJack F Vogel 	/* setup LED */
5028cfa0ad2SJack F Vogel 	mac->ops.setup_led = e1000_setup_led_generic;
5038cfa0ad2SJack F Vogel 	/* cleanup LED */
5048cfa0ad2SJack F Vogel 	mac->ops.cleanup_led = e1000_cleanup_led_generic;
5058cfa0ad2SJack F Vogel 	/* turn on/off LED */
5068cfa0ad2SJack F Vogel 	mac->ops.led_on = e1000_led_on_generic;
5078cfa0ad2SJack F Vogel 	mac->ops.led_off = e1000_led_off_generic;
5088cfa0ad2SJack F Vogel 	/* clear hardware counters */
5098cfa0ad2SJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82575;
5108cfa0ad2SJack F Vogel 	/* link info */
5118cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_82575;
512ab5d0362SJack F Vogel 	/* acquire SW_FW sync */
513d5210708SMatt Macy 	mac->ops.acquire_swfw_sync = e1000_acquire_swfw_sync;
514d5210708SMatt Macy 	mac->ops.release_swfw_sync = e1000_release_swfw_sync;
5158cfa0ad2SJack F Vogel 
5164edd8523SJack F Vogel 	/* set lan id for port to determine which phy lock to use */
5174edd8523SJack F Vogel 	hw->mac.ops.set_lan_id(hw);
5184edd8523SJack F Vogel 
519daf9197cSJack F Vogel 	return E1000_SUCCESS;
5208cfa0ad2SJack F Vogel }
5218cfa0ad2SJack F Vogel 
5228cfa0ad2SJack F Vogel /**
5238cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_82575 - Init func ptrs.
5248cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5258cfa0ad2SJack F Vogel  *
526daf9197cSJack F Vogel  *  Called to initialize all function pointers and parameters.
5278cfa0ad2SJack F Vogel  **/
5288cfa0ad2SJack F Vogel void e1000_init_function_pointers_82575(struct e1000_hw *hw)
5298cfa0ad2SJack F Vogel {
5308cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_82575");
5318cfa0ad2SJack F Vogel 
5328cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_82575;
5338cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_82575;
5348cfa0ad2SJack F Vogel 	hw->phy.ops.init_params = e1000_init_phy_params_82575;
5357d9119bdSJack F Vogel 	hw->mbx.ops.init_params = e1000_init_mbx_params_pf;
5368cfa0ad2SJack F Vogel }
5378cfa0ad2SJack F Vogel 
5388cfa0ad2SJack F Vogel /**
5398cfa0ad2SJack F Vogel  *  e1000_acquire_phy_82575 - Acquire rights to access PHY
5408cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5418cfa0ad2SJack F Vogel  *
542daf9197cSJack F Vogel  *  Acquire access rights to the correct PHY.
5438cfa0ad2SJack F Vogel  **/
5448cfa0ad2SJack F Vogel static s32 e1000_acquire_phy_82575(struct e1000_hw *hw)
5458cfa0ad2SJack F Vogel {
5469d81738fSJack F Vogel 	u16 mask = E1000_SWFW_PHY0_SM;
5478cfa0ad2SJack F Vogel 
5488cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_phy_82575");
5498cfa0ad2SJack F Vogel 
5509d81738fSJack F Vogel 	if (hw->bus.func == E1000_FUNC_1)
5519d81738fSJack F Vogel 		mask = E1000_SWFW_PHY1_SM;
5524edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_2)
5534edd8523SJack F Vogel 		mask = E1000_SWFW_PHY2_SM;
5544edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_3)
5554edd8523SJack F Vogel 		mask = E1000_SWFW_PHY3_SM;
5568cfa0ad2SJack F Vogel 
557ab5d0362SJack F Vogel 	return hw->mac.ops.acquire_swfw_sync(hw, mask);
5588cfa0ad2SJack F Vogel }
5598cfa0ad2SJack F Vogel 
5608cfa0ad2SJack F Vogel /**
5618cfa0ad2SJack F Vogel  *  e1000_release_phy_82575 - Release rights to access PHY
5628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5638cfa0ad2SJack F Vogel  *
564daf9197cSJack F Vogel  *  A wrapper to release access rights to the correct PHY.
5658cfa0ad2SJack F Vogel  **/
5668cfa0ad2SJack F Vogel static void e1000_release_phy_82575(struct e1000_hw *hw)
5678cfa0ad2SJack F Vogel {
5689d81738fSJack F Vogel 	u16 mask = E1000_SWFW_PHY0_SM;
5698cfa0ad2SJack F Vogel 
5708cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_phy_82575");
5718cfa0ad2SJack F Vogel 
5729d81738fSJack F Vogel 	if (hw->bus.func == E1000_FUNC_1)
5739d81738fSJack F Vogel 		mask = E1000_SWFW_PHY1_SM;
5744edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_2)
5754edd8523SJack F Vogel 		mask = E1000_SWFW_PHY2_SM;
5764edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_3)
5774edd8523SJack F Vogel 		mask = E1000_SWFW_PHY3_SM;
5789d81738fSJack F Vogel 
579ab5d0362SJack F Vogel 	hw->mac.ops.release_swfw_sync(hw, mask);
5808cfa0ad2SJack F Vogel }
5818cfa0ad2SJack F Vogel 
5828cfa0ad2SJack F Vogel /**
5838cfa0ad2SJack F Vogel  *  e1000_read_phy_reg_sgmii_82575 - Read PHY register using sgmii
5848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5858cfa0ad2SJack F Vogel  *  @offset: register offset to be read
5868cfa0ad2SJack F Vogel  *  @data: pointer to the read data
5878cfa0ad2SJack F Vogel  *
5888cfa0ad2SJack F Vogel  *  Reads the PHY register at offset using the serial gigabit media independent
5898cfa0ad2SJack F Vogel  *  interface and stores the retrieved information in data.
5908cfa0ad2SJack F Vogel  **/
5918cfa0ad2SJack F Vogel static s32 e1000_read_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
5928cfa0ad2SJack F Vogel 					  u16 *data)
5938cfa0ad2SJack F Vogel {
5944edd8523SJack F Vogel 	s32 ret_val = -E1000_ERR_PARAM;
5958cfa0ad2SJack F Vogel 
5968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_phy_reg_sgmii_82575");
5978cfa0ad2SJack F Vogel 
5988cfa0ad2SJack F Vogel 	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
5998cfa0ad2SJack F Vogel 		DEBUGOUT1("PHY Address %u is out of range\n", offset);
6004edd8523SJack F Vogel 		goto out;
6018cfa0ad2SJack F Vogel 	}
6028cfa0ad2SJack F Vogel 
6034edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
6044edd8523SJack F Vogel 	if (ret_val)
6054edd8523SJack F Vogel 		goto out;
6068cfa0ad2SJack F Vogel 
6074edd8523SJack F Vogel 	ret_val = e1000_read_phy_reg_i2c(hw, offset, data);
6088cfa0ad2SJack F Vogel 
6094edd8523SJack F Vogel 	hw->phy.ops.release(hw);
6108cfa0ad2SJack F Vogel 
6114edd8523SJack F Vogel out:
6124edd8523SJack F Vogel 	return ret_val;
6138cfa0ad2SJack F Vogel }
6148cfa0ad2SJack F Vogel 
6158cfa0ad2SJack F Vogel /**
6168cfa0ad2SJack F Vogel  *  e1000_write_phy_reg_sgmii_82575 - Write PHY register using sgmii
6178cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6188cfa0ad2SJack F Vogel  *  @offset: register offset to write to
6198cfa0ad2SJack F Vogel  *  @data: data to write at register offset
6208cfa0ad2SJack F Vogel  *
6218cfa0ad2SJack F Vogel  *  Writes the data to PHY register at the offset using the serial gigabit
6228cfa0ad2SJack F Vogel  *  media independent interface.
6238cfa0ad2SJack F Vogel  **/
6248cfa0ad2SJack F Vogel static s32 e1000_write_phy_reg_sgmii_82575(struct e1000_hw *hw, u32 offset,
6258cfa0ad2SJack F Vogel 					   u16 data)
6268cfa0ad2SJack F Vogel {
6274edd8523SJack F Vogel 	s32 ret_val = -E1000_ERR_PARAM;
6288cfa0ad2SJack F Vogel 
6298cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_phy_reg_sgmii_82575");
6308cfa0ad2SJack F Vogel 
6318cfa0ad2SJack F Vogel 	if (offset > E1000_MAX_SGMII_PHY_REG_ADDR) {
6328cfa0ad2SJack F Vogel 		DEBUGOUT1("PHY Address %d is out of range\n", offset);
6334edd8523SJack F Vogel 		goto out;
6348cfa0ad2SJack F Vogel 	}
6358cfa0ad2SJack F Vogel 
6364edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
6374edd8523SJack F Vogel 	if (ret_val)
6384edd8523SJack F Vogel 		goto out;
6398cfa0ad2SJack F Vogel 
6404edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_i2c(hw, offset, data);
6418cfa0ad2SJack F Vogel 
6424edd8523SJack F Vogel 	hw->phy.ops.release(hw);
6438cfa0ad2SJack F Vogel 
6444edd8523SJack F Vogel out:
6454edd8523SJack F Vogel 	return ret_val;
6468cfa0ad2SJack F Vogel }
6478cfa0ad2SJack F Vogel 
6488cfa0ad2SJack F Vogel /**
6498cfa0ad2SJack F Vogel  *  e1000_get_phy_id_82575 - Retrieve PHY addr and id
6508cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
6518cfa0ad2SJack F Vogel  *
6528cfa0ad2SJack F Vogel  *  Retrieves the PHY address and ID for both PHY's which do and do not use
6538cfa0ad2SJack F Vogel  *  sgmi interface.
6548cfa0ad2SJack F Vogel  **/
6558cfa0ad2SJack F Vogel static s32 e1000_get_phy_id_82575(struct e1000_hw *hw)
6568cfa0ad2SJack F Vogel {
6578cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
6588cfa0ad2SJack F Vogel 	s32  ret_val = E1000_SUCCESS;
6598cfa0ad2SJack F Vogel 	u16 phy_id;
6604edd8523SJack F Vogel 	u32 ctrl_ext;
6617d9119bdSJack F Vogel 	u32 mdic;
6628cfa0ad2SJack F Vogel 
6638cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_phy_id_82575");
6648cfa0ad2SJack F Vogel 
6657609433eSJack F Vogel 	/* some i354 devices need an extra read for phy id */
6667609433eSJack F Vogel 	if (hw->mac.type == e1000_i354)
6677609433eSJack F Vogel 		e1000_get_phy_id(hw);
6687609433eSJack F Vogel 
6698cfa0ad2SJack F Vogel 	/*
6708cfa0ad2SJack F Vogel 	 * For SGMII PHYs, we try the list of possible addresses until
6718cfa0ad2SJack F Vogel 	 * we find one that works.  For non-SGMII PHYs
6728cfa0ad2SJack F Vogel 	 * (e.g. integrated copper PHYs), an address of 1 should
6738cfa0ad2SJack F Vogel 	 * work.  The result of this function should mean phy->phy_addr
6748cfa0ad2SJack F Vogel 	 * and phy->id are set correctly.
6758cfa0ad2SJack F Vogel 	 */
6764edd8523SJack F Vogel 	if (!e1000_sgmii_active_82575(hw)) {
6778cfa0ad2SJack F Vogel 		phy->addr = 1;
6788cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
6798cfa0ad2SJack F Vogel 		goto out;
6808cfa0ad2SJack F Vogel 	}
6818cfa0ad2SJack F Vogel 
6827d9119bdSJack F Vogel 	if (e1000_sgmii_uses_mdio_82575(hw)) {
6837d9119bdSJack F Vogel 		switch (hw->mac.type) {
6847d9119bdSJack F Vogel 		case e1000_82575:
6857d9119bdSJack F Vogel 		case e1000_82576:
6867d9119bdSJack F Vogel 			mdic = E1000_READ_REG(hw, E1000_MDIC);
6877d9119bdSJack F Vogel 			mdic &= E1000_MDIC_PHY_MASK;
6887d9119bdSJack F Vogel 			phy->addr = mdic >> E1000_MDIC_PHY_SHIFT;
6897d9119bdSJack F Vogel 			break;
6907d9119bdSJack F Vogel 		case e1000_82580:
691f0ecc46dSJack F Vogel 		case e1000_i350:
6927609433eSJack F Vogel 		case e1000_i354:
6936ab6bfe3SJack F Vogel 		case e1000_i210:
6946ab6bfe3SJack F Vogel 		case e1000_i211:
6957d9119bdSJack F Vogel 			mdic = E1000_READ_REG(hw, E1000_MDICNFG);
6967d9119bdSJack F Vogel 			mdic &= E1000_MDICNFG_PHY_MASK;
6977d9119bdSJack F Vogel 			phy->addr = mdic >> E1000_MDICNFG_PHY_SHIFT;
6987d9119bdSJack F Vogel 			break;
6997d9119bdSJack F Vogel 		default:
7007d9119bdSJack F Vogel 			ret_val = -E1000_ERR_PHY;
7017d9119bdSJack F Vogel 			goto out;
7027d9119bdSJack F Vogel 			break;
7037d9119bdSJack F Vogel 		}
7047d9119bdSJack F Vogel 		ret_val = e1000_get_phy_id(hw);
7057d9119bdSJack F Vogel 		goto out;
7067d9119bdSJack F Vogel 	}
7077d9119bdSJack F Vogel 
7084edd8523SJack F Vogel 	/* Power on sgmii phy if it is disabled */
7094edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
7104edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT,
7114edd8523SJack F Vogel 			ctrl_ext & ~E1000_CTRL_EXT_SDP3_DATA);
7124edd8523SJack F Vogel 	E1000_WRITE_FLUSH(hw);
7134edd8523SJack F Vogel 	msec_delay(300);
7144edd8523SJack F Vogel 
7158cfa0ad2SJack F Vogel 	/*
7168cfa0ad2SJack F Vogel 	 * The address field in the I2CCMD register is 3 bits and 0 is invalid.
7178cfa0ad2SJack F Vogel 	 * Therefore, we need to test 1-7
7188cfa0ad2SJack F Vogel 	 */
7198cfa0ad2SJack F Vogel 	for (phy->addr = 1; phy->addr < 8; phy->addr++) {
7208cfa0ad2SJack F Vogel 		ret_val = e1000_read_phy_reg_sgmii_82575(hw, PHY_ID1, &phy_id);
7218cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
7228cfa0ad2SJack F Vogel 			DEBUGOUT2("Vendor ID 0x%08X read at address %u\n",
7234dab5c37SJack F Vogel 				  phy_id, phy->addr);
7248cfa0ad2SJack F Vogel 			/*
7258cfa0ad2SJack F Vogel 			 * At the time of this writing, The M88 part is
7268cfa0ad2SJack F Vogel 			 * the only supported SGMII PHY product.
7278cfa0ad2SJack F Vogel 			 */
7288cfa0ad2SJack F Vogel 			if (phy_id == M88_VENDOR)
7298cfa0ad2SJack F Vogel 				break;
7308cfa0ad2SJack F Vogel 		} else {
7318cfa0ad2SJack F Vogel 			DEBUGOUT1("PHY address %u was unreadable\n",
7328cfa0ad2SJack F Vogel 				  phy->addr);
7338cfa0ad2SJack F Vogel 		}
7348cfa0ad2SJack F Vogel 	}
7358cfa0ad2SJack F Vogel 
7368cfa0ad2SJack F Vogel 	/* A valid PHY type couldn't be found. */
7378cfa0ad2SJack F Vogel 	if (phy->addr == 8) {
7388cfa0ad2SJack F Vogel 		phy->addr = 0;
7398cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
7404edd8523SJack F Vogel 	} else {
7414edd8523SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
7428cfa0ad2SJack F Vogel 	}
7438cfa0ad2SJack F Vogel 
7444edd8523SJack F Vogel 	/* restore previous sfp cage power state */
7454edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
7468cfa0ad2SJack F Vogel 
7478cfa0ad2SJack F Vogel out:
7488cfa0ad2SJack F Vogel 	return ret_val;
7498cfa0ad2SJack F Vogel }
7508cfa0ad2SJack F Vogel 
7518cfa0ad2SJack F Vogel /**
7528cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_sgmii_82575 - Performs a PHY reset
7538cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7548cfa0ad2SJack F Vogel  *
7558cfa0ad2SJack F Vogel  *  Resets the PHY using the serial gigabit media independent interface.
7568cfa0ad2SJack F Vogel  **/
7578cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_sgmii_82575(struct e1000_hw *hw)
7588cfa0ad2SJack F Vogel {
7598cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
7608cc64f1eSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
7618cfa0ad2SJack F Vogel 
7628cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_sgmii_82575");
7638cfa0ad2SJack F Vogel 
7648cfa0ad2SJack F Vogel 	/*
7658cfa0ad2SJack F Vogel 	 * This isn't a TRUE "hard" reset, but is the only reset
7668cfa0ad2SJack F Vogel 	 * available to us at this time.
7678cfa0ad2SJack F Vogel 	 */
7688cfa0ad2SJack F Vogel 
7698cfa0ad2SJack F Vogel 	DEBUGOUT("Soft resetting SGMII attached PHY...\n");
7708cfa0ad2SJack F Vogel 
7718cfa0ad2SJack F Vogel 	if (!(hw->phy.ops.write_reg))
7728cfa0ad2SJack F Vogel 		goto out;
7738cfa0ad2SJack F Vogel 
7748cfa0ad2SJack F Vogel 	/*
7758cfa0ad2SJack F Vogel 	 * SFP documentation requires the following to configure the SPF module
7768cfa0ad2SJack F Vogel 	 * to work on SGMII.  No further documentation is given.
7778cfa0ad2SJack F Vogel 	 */
7788cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, 0x1B, 0x8084);
7798cfa0ad2SJack F Vogel 	if (ret_val)
7808cfa0ad2SJack F Vogel 		goto out;
7818cfa0ad2SJack F Vogel 
7828cfa0ad2SJack F Vogel 	ret_val = hw->phy.ops.commit(hw);
7838cc64f1eSJack F Vogel 	if (ret_val)
7848cc64f1eSJack F Vogel 		goto out;
7858cfa0ad2SJack F Vogel 
7868cc64f1eSJack F Vogel 	if (phy->id == M88E1512_E_PHY_ID)
7878cc64f1eSJack F Vogel 		ret_val = e1000_initialize_M88E1512_phy(hw);
7888cfa0ad2SJack F Vogel out:
7898cfa0ad2SJack F Vogel 	return ret_val;
7908cfa0ad2SJack F Vogel }
7918cfa0ad2SJack F Vogel 
7928cfa0ad2SJack F Vogel /**
7938cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_82575 - Set Low Power Linkup D0 state
7948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7958cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
7968cfa0ad2SJack F Vogel  *
7978cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
7988cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
7998cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
8008cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
8018cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
8028cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
8038cfa0ad2SJack F Vogel  *  PHY setup routines.
8048cfa0ad2SJack F Vogel  **/
8058cfa0ad2SJack F Vogel static s32 e1000_set_d0_lplu_state_82575(struct e1000_hw *hw, bool active)
8068cfa0ad2SJack F Vogel {
8078cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
8088cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
8098cfa0ad2SJack F Vogel 	u16 data;
8108cfa0ad2SJack F Vogel 
8118cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_82575");
8128cfa0ad2SJack F Vogel 
8138cfa0ad2SJack F Vogel 	if (!(hw->phy.ops.read_reg))
8148cfa0ad2SJack F Vogel 		goto out;
8158cfa0ad2SJack F Vogel 
8168cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, IGP02E1000_PHY_POWER_MGMT, &data);
8178cfa0ad2SJack F Vogel 	if (ret_val)
8188cfa0ad2SJack F Vogel 		goto out;
8198cfa0ad2SJack F Vogel 
8208cfa0ad2SJack F Vogel 	if (active) {
8218cfa0ad2SJack F Vogel 		data |= IGP02E1000_PM_D0_LPLU;
8228cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
8238cfa0ad2SJack F Vogel 					     data);
8248cfa0ad2SJack F Vogel 		if (ret_val)
8258cfa0ad2SJack F Vogel 			goto out;
8268cfa0ad2SJack F Vogel 
8278cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
8288cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
8298cfa0ad2SJack F Vogel 					    &data);
8308cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
8318cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP01E1000_PHY_PORT_CONFIG,
8328cfa0ad2SJack F Vogel 					     data);
8338cfa0ad2SJack F Vogel 		if (ret_val)
8348cfa0ad2SJack F Vogel 			goto out;
8358cfa0ad2SJack F Vogel 	} else {
8368cfa0ad2SJack F Vogel 		data &= ~IGP02E1000_PM_D0_LPLU;
8378cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw, IGP02E1000_PHY_POWER_MGMT,
8388cfa0ad2SJack F Vogel 					     data);
8398cfa0ad2SJack F Vogel 		/*
8408cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
8418cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
8428cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
8438cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
8448cfa0ad2SJack F Vogel 		 */
8458cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
8468cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
8478cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
8488cfa0ad2SJack F Vogel 						    &data);
8498cfa0ad2SJack F Vogel 			if (ret_val)
8508cfa0ad2SJack F Vogel 				goto out;
8518cfa0ad2SJack F Vogel 
8528cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
8538cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
8548cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
8558cfa0ad2SJack F Vogel 						     data);
8568cfa0ad2SJack F Vogel 			if (ret_val)
8578cfa0ad2SJack F Vogel 				goto out;
8588cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
8598cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
8608cfa0ad2SJack F Vogel 						    IGP01E1000_PHY_PORT_CONFIG,
8618cfa0ad2SJack F Vogel 						    &data);
8628cfa0ad2SJack F Vogel 			if (ret_val)
8638cfa0ad2SJack F Vogel 				goto out;
8648cfa0ad2SJack F Vogel 
8658cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
8668cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
8678cfa0ad2SJack F Vogel 						     IGP01E1000_PHY_PORT_CONFIG,
8688cfa0ad2SJack F Vogel 						     data);
8698cfa0ad2SJack F Vogel 			if (ret_val)
8708cfa0ad2SJack F Vogel 				goto out;
8718cfa0ad2SJack F Vogel 		}
8728cfa0ad2SJack F Vogel 	}
8738cfa0ad2SJack F Vogel 
8748cfa0ad2SJack F Vogel out:
8758cfa0ad2SJack F Vogel 	return ret_val;
8768cfa0ad2SJack F Vogel }
8778cfa0ad2SJack F Vogel 
8788cfa0ad2SJack F Vogel /**
879f0ecc46dSJack F Vogel  *  e1000_set_d0_lplu_state_82580 - Set Low Power Linkup D0 state
880f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
881f0ecc46dSJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
882f0ecc46dSJack F Vogel  *
883f0ecc46dSJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
884f0ecc46dSJack F Vogel  *  activating LPLU this function also disables smart speed
885f0ecc46dSJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
886f0ecc46dSJack F Vogel  *  device autonegotiation advertisement meets standards of
887f0ecc46dSJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
888f0ecc46dSJack F Vogel  *  This is a function pointer entry point only called by
889f0ecc46dSJack F Vogel  *  PHY setup routines.
890f0ecc46dSJack F Vogel  **/
891f0ecc46dSJack F Vogel static s32 e1000_set_d0_lplu_state_82580(struct e1000_hw *hw, bool active)
892f0ecc46dSJack F Vogel {
893f0ecc46dSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
894ab5d0362SJack F Vogel 	u32 data;
895f0ecc46dSJack F Vogel 
896f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_82580");
897f0ecc46dSJack F Vogel 
898f0ecc46dSJack F Vogel 	data = E1000_READ_REG(hw, E1000_82580_PHY_POWER_MGMT);
899f0ecc46dSJack F Vogel 
900f0ecc46dSJack F Vogel 	if (active) {
901f0ecc46dSJack F Vogel 		data |= E1000_82580_PM_D0_LPLU;
902f0ecc46dSJack F Vogel 
903f0ecc46dSJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
904f0ecc46dSJack F Vogel 		data &= ~E1000_82580_PM_SPD;
905f0ecc46dSJack F Vogel 	} else {
906f0ecc46dSJack F Vogel 		data &= ~E1000_82580_PM_D0_LPLU;
907f0ecc46dSJack F Vogel 
908f0ecc46dSJack F Vogel 		/*
909f0ecc46dSJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
910f0ecc46dSJack F Vogel 		 * during Dx states where the power conservation is most
911f0ecc46dSJack F Vogel 		 * important.  During driver activity we should enable
912f0ecc46dSJack F Vogel 		 * SmartSpeed, so performance is maintained.
913f0ecc46dSJack F Vogel 		 */
9144dab5c37SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on)
915f0ecc46dSJack F Vogel 			data |= E1000_82580_PM_SPD;
9164dab5c37SJack F Vogel 		else if (phy->smart_speed == e1000_smart_speed_off)
917f0ecc46dSJack F Vogel 			data &= ~E1000_82580_PM_SPD;
918f0ecc46dSJack F Vogel 	}
919f0ecc46dSJack F Vogel 
920f0ecc46dSJack F Vogel 	E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, data);
9218cc64f1eSJack F Vogel 	return E1000_SUCCESS;
922f0ecc46dSJack F Vogel }
923f0ecc46dSJack F Vogel 
924f0ecc46dSJack F Vogel /**
925f0ecc46dSJack F Vogel  *  e1000_set_d3_lplu_state_82580 - Sets low power link up state for D3
926f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
927f0ecc46dSJack F Vogel  *  @active: boolean used to enable/disable lplu
928f0ecc46dSJack F Vogel  *
929f0ecc46dSJack F Vogel  *  Success returns 0, Failure returns 1
930f0ecc46dSJack F Vogel  *
931f0ecc46dSJack F Vogel  *  The low power link up (lplu) state is set to the power management level D3
932f0ecc46dSJack F Vogel  *  and SmartSpeed is disabled when active is TRUE, else clear lplu for D3
933f0ecc46dSJack F Vogel  *  and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
934f0ecc46dSJack F Vogel  *  is used during Dx states where the power conservation is most important.
935f0ecc46dSJack F Vogel  *  During driver activity, SmartSpeed should be enabled so performance is
936f0ecc46dSJack F Vogel  *  maintained.
937f0ecc46dSJack F Vogel  **/
938f0ecc46dSJack F Vogel s32 e1000_set_d3_lplu_state_82580(struct e1000_hw *hw, bool active)
939f0ecc46dSJack F Vogel {
940f0ecc46dSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
941ab5d0362SJack F Vogel 	u32 data;
942f0ecc46dSJack F Vogel 
943f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_82580");
944f0ecc46dSJack F Vogel 
945f0ecc46dSJack F Vogel 	data = E1000_READ_REG(hw, E1000_82580_PHY_POWER_MGMT);
946f0ecc46dSJack F Vogel 
947f0ecc46dSJack F Vogel 	if (!active) {
948f0ecc46dSJack F Vogel 		data &= ~E1000_82580_PM_D3_LPLU;
949f0ecc46dSJack F Vogel 		/*
950f0ecc46dSJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
951f0ecc46dSJack F Vogel 		 * during Dx states where the power conservation is most
952f0ecc46dSJack F Vogel 		 * important.  During driver activity we should enable
953f0ecc46dSJack F Vogel 		 * SmartSpeed, so performance is maintained.
954f0ecc46dSJack F Vogel 		 */
9554dab5c37SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on)
956f0ecc46dSJack F Vogel 			data |= E1000_82580_PM_SPD;
9574dab5c37SJack F Vogel 		else if (phy->smart_speed == e1000_smart_speed_off)
958f0ecc46dSJack F Vogel 			data &= ~E1000_82580_PM_SPD;
959f0ecc46dSJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
960f0ecc46dSJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
961f0ecc46dSJack F Vogel 		   (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
962f0ecc46dSJack F Vogel 		data |= E1000_82580_PM_D3_LPLU;
963f0ecc46dSJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
964f0ecc46dSJack F Vogel 		data &= ~E1000_82580_PM_SPD;
965f0ecc46dSJack F Vogel 	}
966f0ecc46dSJack F Vogel 
967f0ecc46dSJack F Vogel 	E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, data);
9688cc64f1eSJack F Vogel 	return E1000_SUCCESS;
969f0ecc46dSJack F Vogel }
970f0ecc46dSJack F Vogel 
971f0ecc46dSJack F Vogel /**
9728cfa0ad2SJack F Vogel  *  e1000_acquire_nvm_82575 - Request for access to EEPROM
9738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
9748cfa0ad2SJack F Vogel  *
9758cfa0ad2SJack F Vogel  *  Acquire the necessary semaphores for exclusive access to the EEPROM.
9768cfa0ad2SJack F Vogel  *  Set the EEPROM access request bit and wait for EEPROM access grant bit.
9778cfa0ad2SJack F Vogel  *  Return successful if access grant bit set, else clear the request for
9788cfa0ad2SJack F Vogel  *  EEPROM access and return -E1000_ERR_NVM (-1).
9798cfa0ad2SJack F Vogel  **/
9808cfa0ad2SJack F Vogel static s32 e1000_acquire_nvm_82575(struct e1000_hw *hw)
9818cfa0ad2SJack F Vogel {
9828cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
9838cfa0ad2SJack F Vogel 
9848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_nvm_82575");
9858cfa0ad2SJack F Vogel 
986d5210708SMatt Macy 	ret_val = e1000_acquire_swfw_sync(hw, E1000_SWFW_EEP_SM);
9878cfa0ad2SJack F Vogel 	if (ret_val)
9888cfa0ad2SJack F Vogel 		goto out;
9894dab5c37SJack F Vogel 
9904dab5c37SJack F Vogel 	/*
9914dab5c37SJack F Vogel 	 * Check if there is some access
9924dab5c37SJack F Vogel 	 * error this access may hook on
9934dab5c37SJack F Vogel 	 */
9944dab5c37SJack F Vogel 	if (hw->mac.type == e1000_i350) {
9954dab5c37SJack F Vogel 		u32 eecd = E1000_READ_REG(hw, E1000_EECD);
9964dab5c37SJack F Vogel 		if (eecd & (E1000_EECD_BLOCKED | E1000_EECD_ABORT |
9974dab5c37SJack F Vogel 		    E1000_EECD_TIMEOUT)) {
9984dab5c37SJack F Vogel 			/* Clear all access error flags */
9994dab5c37SJack F Vogel 			E1000_WRITE_REG(hw, E1000_EECD, eecd |
10004dab5c37SJack F Vogel 					E1000_EECD_ERROR_CLR);
10014dab5c37SJack F Vogel 			DEBUGOUT("Nvm bit banging access error detected and cleared.\n");
10024dab5c37SJack F Vogel 		}
10034dab5c37SJack F Vogel 	}
10048cc64f1eSJack F Vogel 
10054dab5c37SJack F Vogel 	if (hw->mac.type == e1000_82580) {
10064dab5c37SJack F Vogel 		u32 eecd = E1000_READ_REG(hw, E1000_EECD);
10074dab5c37SJack F Vogel 		if (eecd & E1000_EECD_BLOCKED) {
10084dab5c37SJack F Vogel 			/* Clear access error flag */
10094dab5c37SJack F Vogel 			E1000_WRITE_REG(hw, E1000_EECD, eecd |
10104dab5c37SJack F Vogel 					E1000_EECD_BLOCKED);
10114dab5c37SJack F Vogel 			DEBUGOUT("Nvm bit banging access error detected and cleared.\n");
10124dab5c37SJack F Vogel 		}
10134dab5c37SJack F Vogel 	}
10144dab5c37SJack F Vogel 
10158cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_nvm_generic(hw);
10168cfa0ad2SJack F Vogel 	if (ret_val)
1017d5210708SMatt Macy 		e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM);
10188cfa0ad2SJack F Vogel 
10198cfa0ad2SJack F Vogel out:
10208cfa0ad2SJack F Vogel 	return ret_val;
10218cfa0ad2SJack F Vogel }
10228cfa0ad2SJack F Vogel 
10238cfa0ad2SJack F Vogel /**
10248cfa0ad2SJack F Vogel  *  e1000_release_nvm_82575 - Release exclusive access to EEPROM
10258cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10268cfa0ad2SJack F Vogel  *
10278cfa0ad2SJack F Vogel  *  Stop any current commands to the EEPROM and clear the EEPROM request bit,
10288cfa0ad2SJack F Vogel  *  then release the semaphores acquired.
10298cfa0ad2SJack F Vogel  **/
10308cfa0ad2SJack F Vogel static void e1000_release_nvm_82575(struct e1000_hw *hw)
10318cfa0ad2SJack F Vogel {
10328cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_nvm_82575");
10338cfa0ad2SJack F Vogel 
10344dab5c37SJack F Vogel 	e1000_release_nvm_generic(hw);
1035ab5d0362SJack F Vogel 
1036d5210708SMatt Macy 	e1000_release_swfw_sync(hw, E1000_SWFW_EEP_SM);
10378cfa0ad2SJack F Vogel }
10388cfa0ad2SJack F Vogel 
10398cfa0ad2SJack F Vogel /**
10408cfa0ad2SJack F Vogel  *  e1000_get_cfg_done_82575 - Read config done bit
10418cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10428cfa0ad2SJack F Vogel  *
10438cfa0ad2SJack F Vogel  *  Read the management control register for the config done bit for
10448cfa0ad2SJack F Vogel  *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
10458cfa0ad2SJack F Vogel  *  to read the config done bit, so an error is *ONLY* logged and returns
10468cfa0ad2SJack F Vogel  *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
10478cfa0ad2SJack F Vogel  *  would not be able to be reset or change link.
10488cfa0ad2SJack F Vogel  **/
10498cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_82575(struct e1000_hw *hw)
10508cfa0ad2SJack F Vogel {
10518cfa0ad2SJack F Vogel 	s32 timeout = PHY_CFG_TIMEOUT;
10528cfa0ad2SJack F Vogel 	u32 mask = E1000_NVM_CFG_DONE_PORT_0;
10538cfa0ad2SJack F Vogel 
10548cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_cfg_done_82575");
10558cfa0ad2SJack F Vogel 
10569d81738fSJack F Vogel 	if (hw->bus.func == E1000_FUNC_1)
10578cfa0ad2SJack F Vogel 		mask = E1000_NVM_CFG_DONE_PORT_1;
10584edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_2)
10594edd8523SJack F Vogel 		mask = E1000_NVM_CFG_DONE_PORT_2;
10604edd8523SJack F Vogel 	else if (hw->bus.func == E1000_FUNC_3)
10614edd8523SJack F Vogel 		mask = E1000_NVM_CFG_DONE_PORT_3;
10628cfa0ad2SJack F Vogel 	while (timeout) {
10638cfa0ad2SJack F Vogel 		if (E1000_READ_REG(hw, E1000_EEMNGCTL) & mask)
10648cfa0ad2SJack F Vogel 			break;
10658cfa0ad2SJack F Vogel 		msec_delay(1);
10668cfa0ad2SJack F Vogel 		timeout--;
10678cfa0ad2SJack F Vogel 	}
10684edd8523SJack F Vogel 	if (!timeout)
10698cfa0ad2SJack F Vogel 		DEBUGOUT("MNG configuration cycle has not completed.\n");
10708cfa0ad2SJack F Vogel 
10718cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the PHY manually */
1072ab5d0362SJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) &&
10734edd8523SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3))
10748cfa0ad2SJack F Vogel 		e1000_phy_init_script_igp3(hw);
10758cfa0ad2SJack F Vogel 
10768cc64f1eSJack F Vogel 	return E1000_SUCCESS;
10778cfa0ad2SJack F Vogel }
10788cfa0ad2SJack F Vogel 
10798cfa0ad2SJack F Vogel /**
10808cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_82575 - Get link speed/duplex info
10818cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10828cfa0ad2SJack F Vogel  *  @speed: stores the current speed
10838cfa0ad2SJack F Vogel  *  @duplex: stores the current duplex
10848cfa0ad2SJack F Vogel  *
10858cfa0ad2SJack F Vogel  *  This is a wrapper function, if using the serial gigabit media independent
10868cfa0ad2SJack F Vogel  *  interface, use PCS to retrieve the link speed and duplex information.
10878cfa0ad2SJack F Vogel  *  Otherwise, use the generic function to get the link speed and duplex info.
10888cfa0ad2SJack F Vogel  **/
10898cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_82575(struct e1000_hw *hw, u16 *speed,
10908cfa0ad2SJack F Vogel 					u16 *duplex)
10918cfa0ad2SJack F Vogel {
10928cfa0ad2SJack F Vogel 	s32 ret_val;
10938cfa0ad2SJack F Vogel 
10948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_82575");
10958cfa0ad2SJack F Vogel 
10964edd8523SJack F Vogel 	if (hw->phy.media_type != e1000_media_type_copper)
10978cfa0ad2SJack F Vogel 		ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, speed,
10988cfa0ad2SJack F Vogel 							       duplex);
10994edd8523SJack F Vogel 	else
11008cfa0ad2SJack F Vogel 		ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed,
11018cfa0ad2SJack F Vogel 								    duplex);
11028cfa0ad2SJack F Vogel 
11038cfa0ad2SJack F Vogel 	return ret_val;
11048cfa0ad2SJack F Vogel }
11058cfa0ad2SJack F Vogel 
11068cfa0ad2SJack F Vogel /**
11078cfa0ad2SJack F Vogel  *  e1000_check_for_link_82575 - Check for link
11088cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
11098cfa0ad2SJack F Vogel  *
11108cfa0ad2SJack F Vogel  *  If sgmii is enabled, then use the pcs register to determine link, otherwise
11118cfa0ad2SJack F Vogel  *  use the generic interface for determining link.
11128cfa0ad2SJack F Vogel  **/
11138cfa0ad2SJack F Vogel static s32 e1000_check_for_link_82575(struct e1000_hw *hw)
11148cfa0ad2SJack F Vogel {
11158cfa0ad2SJack F Vogel 	s32 ret_val;
11168cfa0ad2SJack F Vogel 	u16 speed, duplex;
11178cfa0ad2SJack F Vogel 
11188cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_for_link_82575");
11198cfa0ad2SJack F Vogel 
11204edd8523SJack F Vogel 	if (hw->phy.media_type != e1000_media_type_copper) {
11218cfa0ad2SJack F Vogel 		ret_val = e1000_get_pcs_speed_and_duplex_82575(hw, &speed,
11228cfa0ad2SJack F Vogel 							       &duplex);
1123d035aa2dSJack F Vogel 		/*
1124d035aa2dSJack F Vogel 		 * Use this flag to determine if link needs to be checked or
1125d035aa2dSJack F Vogel 		 * not.  If we have link clear the flag so that we do not
1126d035aa2dSJack F Vogel 		 * continue to check for link.
1127d035aa2dSJack F Vogel 		 */
1128d035aa2dSJack F Vogel 		hw->mac.get_link_status = !hw->mac.serdes_has_link;
1129ab5d0362SJack F Vogel 
11306ab6bfe3SJack F Vogel 		/*
11316ab6bfe3SJack F Vogel 		 * Configure Flow Control now that Auto-Neg has completed.
11326ab6bfe3SJack F Vogel 		 * First, we need to restore the desired flow control
11336ab6bfe3SJack F Vogel 		 * settings because we may have had to re-autoneg with a
11346ab6bfe3SJack F Vogel 		 * different link partner.
11356ab6bfe3SJack F Vogel 		 */
11366ab6bfe3SJack F Vogel 		ret_val = e1000_config_fc_after_link_up_generic(hw);
11376ab6bfe3SJack F Vogel 		if (ret_val)
11386ab6bfe3SJack F Vogel 			DEBUGOUT("Error configuring flow control\n");
1139d035aa2dSJack F Vogel 	} else {
11408cfa0ad2SJack F Vogel 		ret_val = e1000_check_for_copper_link_generic(hw);
1141d035aa2dSJack F Vogel 	}
11428cfa0ad2SJack F Vogel 
11438cfa0ad2SJack F Vogel 	return ret_val;
11448cfa0ad2SJack F Vogel }
11458cfa0ad2SJack F Vogel 
11468cfa0ad2SJack F Vogel /**
11477609433eSJack F Vogel  *  e1000_check_for_link_media_swap - Check which M88E1112 interface linked
11487609433eSJack F Vogel  *  @hw: pointer to the HW structure
11497609433eSJack F Vogel  *
11507609433eSJack F Vogel  *  Poll the M88E1112 interfaces to see which interface achieved link.
11517609433eSJack F Vogel  */
11527609433eSJack F Vogel static s32 e1000_check_for_link_media_swap(struct e1000_hw *hw)
11537609433eSJack F Vogel {
11547609433eSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
11557609433eSJack F Vogel 	s32 ret_val;
11567609433eSJack F Vogel 	u16 data;
11577609433eSJack F Vogel 	u8 port = 0;
11587609433eSJack F Vogel 
11597609433eSJack F Vogel 	DEBUGFUNC("e1000_check_for_link_media_swap");
11607609433eSJack F Vogel 
1161c80429ceSEric Joyner 	/* Check for copper. */
11627609433eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
11637609433eSJack F Vogel 	if (ret_val)
11647609433eSJack F Vogel 		return ret_val;
11657609433eSJack F Vogel 
11667609433eSJack F Vogel 	ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data);
11677609433eSJack F Vogel 	if (ret_val)
11687609433eSJack F Vogel 		return ret_val;
11697609433eSJack F Vogel 
11707609433eSJack F Vogel 	if (data & E1000_M88E1112_STATUS_LINK)
11717609433eSJack F Vogel 		port = E1000_MEDIA_PORT_COPPER;
11727609433eSJack F Vogel 
1173c80429ceSEric Joyner 	/* Check for other. */
11747609433eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 1);
11757609433eSJack F Vogel 	if (ret_val)
11767609433eSJack F Vogel 		return ret_val;
11777609433eSJack F Vogel 
11787609433eSJack F Vogel 	ret_val = phy->ops.read_reg(hw, E1000_M88E1112_STATUS, &data);
11797609433eSJack F Vogel 	if (ret_val)
11807609433eSJack F Vogel 		return ret_val;
11817609433eSJack F Vogel 
11827609433eSJack F Vogel 	if (data & E1000_M88E1112_STATUS_LINK)
11837609433eSJack F Vogel 		port = E1000_MEDIA_PORT_OTHER;
11847609433eSJack F Vogel 
11857609433eSJack F Vogel 	/* Determine if a swap needs to happen. */
11867609433eSJack F Vogel 	if (port && (hw->dev_spec._82575.media_port != port)) {
11877609433eSJack F Vogel 		hw->dev_spec._82575.media_port = port;
11887609433eSJack F Vogel 		hw->dev_spec._82575.media_changed = TRUE;
1189c80429ceSEric Joyner 	}
1190c80429ceSEric Joyner 
1191c80429ceSEric Joyner 	if (port == E1000_MEDIA_PORT_COPPER) {
1192c80429ceSEric Joyner 		/* reset page to 0 */
1193c80429ceSEric Joyner 		ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
1194c80429ceSEric Joyner 		if (ret_val)
1195c80429ceSEric Joyner 			return ret_val;
1196c80429ceSEric Joyner 		e1000_check_for_link_82575(hw);
11977609433eSJack F Vogel 	} else {
1198c80429ceSEric Joyner 		e1000_check_for_link_82575(hw);
1199c80429ceSEric Joyner 		/* reset page to 0 */
1200c80429ceSEric Joyner 		ret_val = phy->ops.write_reg(hw, E1000_M88E1112_PAGE_ADDR, 0);
1201c80429ceSEric Joyner 		if (ret_val)
1202c80429ceSEric Joyner 			return ret_val;
12037609433eSJack F Vogel 	}
12047609433eSJack F Vogel 
12057609433eSJack F Vogel 	return E1000_SUCCESS;
12067609433eSJack F Vogel }
12077609433eSJack F Vogel 
12087609433eSJack F Vogel /**
1209a69ed8dfSJack F Vogel  *  e1000_power_up_serdes_link_82575 - Power up the serdes link after shutdown
1210a69ed8dfSJack F Vogel  *  @hw: pointer to the HW structure
1211a69ed8dfSJack F Vogel  **/
1212a69ed8dfSJack F Vogel static void e1000_power_up_serdes_link_82575(struct e1000_hw *hw)
1213a69ed8dfSJack F Vogel {
1214a69ed8dfSJack F Vogel 	u32 reg;
1215a69ed8dfSJack F Vogel 
1216a69ed8dfSJack F Vogel 	DEBUGFUNC("e1000_power_up_serdes_link_82575");
1217a69ed8dfSJack F Vogel 
1218a69ed8dfSJack F Vogel 	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
1219a69ed8dfSJack F Vogel 	    !e1000_sgmii_active_82575(hw))
1220a69ed8dfSJack F Vogel 		return;
1221a69ed8dfSJack F Vogel 
1222a69ed8dfSJack F Vogel 	/* Enable PCS to turn on link */
1223a69ed8dfSJack F Vogel 	reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
1224a69ed8dfSJack F Vogel 	reg |= E1000_PCS_CFG_PCS_EN;
1225a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
1226a69ed8dfSJack F Vogel 
1227a69ed8dfSJack F Vogel 	/* Power up the laser */
1228a69ed8dfSJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
1229a69ed8dfSJack F Vogel 	reg &= ~E1000_CTRL_EXT_SDP3_DATA;
1230a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
1231a69ed8dfSJack F Vogel 
1232a69ed8dfSJack F Vogel 	/* flush the write to verify completion */
1233a69ed8dfSJack F Vogel 	E1000_WRITE_FLUSH(hw);
1234a69ed8dfSJack F Vogel 	msec_delay(1);
1235a69ed8dfSJack F Vogel }
1236a69ed8dfSJack F Vogel 
1237a69ed8dfSJack F Vogel /**
12388cfa0ad2SJack F Vogel  *  e1000_get_pcs_speed_and_duplex_82575 - Retrieve current speed/duplex
12398cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12408cfa0ad2SJack F Vogel  *  @speed: stores the current speed
12418cfa0ad2SJack F Vogel  *  @duplex: stores the current duplex
12428cfa0ad2SJack F Vogel  *
12438cfa0ad2SJack F Vogel  *  Using the physical coding sub-layer (PCS), retrieve the current speed and
12448cfa0ad2SJack F Vogel  *  duplex, then store the values in the pointers provided.
12458cfa0ad2SJack F Vogel  **/
12468cfa0ad2SJack F Vogel static s32 e1000_get_pcs_speed_and_duplex_82575(struct e1000_hw *hw,
12478cfa0ad2SJack F Vogel 						u16 *speed, u16 *duplex)
12488cfa0ad2SJack F Vogel {
12498cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
12508cfa0ad2SJack F Vogel 	u32 pcs;
12517609433eSJack F Vogel 	u32 status;
12528cfa0ad2SJack F Vogel 
12538cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_pcs_speed_and_duplex_82575");
12548cfa0ad2SJack F Vogel 
12558cfa0ad2SJack F Vogel 	/*
12568cfa0ad2SJack F Vogel 	 * Read the PCS Status register for link state. For non-copper mode,
12578cfa0ad2SJack F Vogel 	 * the status register is not accurate. The PCS status register is
12588cfa0ad2SJack F Vogel 	 * used instead.
12598cfa0ad2SJack F Vogel 	 */
12608cfa0ad2SJack F Vogel 	pcs = E1000_READ_REG(hw, E1000_PCS_LSTAT);
12618cfa0ad2SJack F Vogel 
12628cfa0ad2SJack F Vogel 	/*
1263ab5d0362SJack F Vogel 	 * The link up bit determines when link is up on autoneg.
12648cfa0ad2SJack F Vogel 	 */
1265ab5d0362SJack F Vogel 	if (pcs & E1000_PCS_LSTS_LINK_OK) {
12668cfa0ad2SJack F Vogel 		mac->serdes_has_link = TRUE;
12678cfa0ad2SJack F Vogel 
12688cfa0ad2SJack F Vogel 		/* Detect and store PCS speed */
12694dab5c37SJack F Vogel 		if (pcs & E1000_PCS_LSTS_SPEED_1000)
12708cfa0ad2SJack F Vogel 			*speed = SPEED_1000;
12714dab5c37SJack F Vogel 		else if (pcs & E1000_PCS_LSTS_SPEED_100)
12728cfa0ad2SJack F Vogel 			*speed = SPEED_100;
12734dab5c37SJack F Vogel 		else
12748cfa0ad2SJack F Vogel 			*speed = SPEED_10;
12758cfa0ad2SJack F Vogel 
12768cfa0ad2SJack F Vogel 		/* Detect and store PCS duplex */
12774dab5c37SJack F Vogel 		if (pcs & E1000_PCS_LSTS_DUPLEX_FULL)
12788cfa0ad2SJack F Vogel 			*duplex = FULL_DUPLEX;
12794dab5c37SJack F Vogel 		else
12808cfa0ad2SJack F Vogel 			*duplex = HALF_DUPLEX;
12816ab6bfe3SJack F Vogel 
12827609433eSJack F Vogel 		/* Check if it is an I354 2.5Gb backplane connection. */
12837609433eSJack F Vogel 		if (mac->type == e1000_i354) {
12847609433eSJack F Vogel 			status = E1000_READ_REG(hw, E1000_STATUS);
12857609433eSJack F Vogel 			if ((status & E1000_STATUS_2P5_SKU) &&
12867609433eSJack F Vogel 			    !(status & E1000_STATUS_2P5_SKU_OVER)) {
12877609433eSJack F Vogel 				*speed = SPEED_2500;
12887609433eSJack F Vogel 				*duplex = FULL_DUPLEX;
12897609433eSJack F Vogel 				DEBUGOUT("2500 Mbs, ");
12907609433eSJack F Vogel 				DEBUGOUT("Full Duplex\n");
12917609433eSJack F Vogel 			}
12927609433eSJack F Vogel 		}
12937609433eSJack F Vogel 
1294ab5d0362SJack F Vogel 	} else {
1295ab5d0362SJack F Vogel 		mac->serdes_has_link = FALSE;
1296ab5d0362SJack F Vogel 		*speed = 0;
1297ab5d0362SJack F Vogel 		*duplex = 0;
12988cfa0ad2SJack F Vogel 	}
12998cfa0ad2SJack F Vogel 
13008cfa0ad2SJack F Vogel 	return E1000_SUCCESS;
13018cfa0ad2SJack F Vogel }
13028cfa0ad2SJack F Vogel 
13038cfa0ad2SJack F Vogel /**
13044edd8523SJack F Vogel  *  e1000_shutdown_serdes_link_82575 - Remove link during power down
13058cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13068cfa0ad2SJack F Vogel  *
13074edd8523SJack F Vogel  *  In the case of serdes shut down sfp and PCS on driver unload
13088cfa0ad2SJack F Vogel  *  when management pass thru is not enabled.
13098cfa0ad2SJack F Vogel  **/
13104edd8523SJack F Vogel void e1000_shutdown_serdes_link_82575(struct e1000_hw *hw)
13118cfa0ad2SJack F Vogel {
13128cfa0ad2SJack F Vogel 	u32 reg;
1313a69ed8dfSJack F Vogel 
1314a69ed8dfSJack F Vogel 	DEBUGFUNC("e1000_shutdown_serdes_link_82575");
13158cfa0ad2SJack F Vogel 
13164edd8523SJack F Vogel 	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
13174edd8523SJack F Vogel 	    !e1000_sgmii_active_82575(hw))
13188cfa0ad2SJack F Vogel 		return;
13198cfa0ad2SJack F Vogel 
1320a69ed8dfSJack F Vogel 	if (!e1000_enable_mng_pass_thru(hw)) {
13218cfa0ad2SJack F Vogel 		/* Disable PCS to turn off link */
13228cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PCS_CFG0);
13238cfa0ad2SJack F Vogel 		reg &= ~E1000_PCS_CFG_PCS_EN;
13248cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PCS_CFG0, reg);
13258cfa0ad2SJack F Vogel 
13268cfa0ad2SJack F Vogel 		/* shutdown the laser */
13278cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
13284edd8523SJack F Vogel 		reg |= E1000_CTRL_EXT_SDP3_DATA;
13298cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
13308cfa0ad2SJack F Vogel 
13314edd8523SJack F Vogel 		/* flush the write to verify completion */
13328cfa0ad2SJack F Vogel 		E1000_WRITE_FLUSH(hw);
13338cfa0ad2SJack F Vogel 		msec_delay(1);
13348cfa0ad2SJack F Vogel 	}
13358cfa0ad2SJack F Vogel 
13368cfa0ad2SJack F Vogel 	return;
13378cfa0ad2SJack F Vogel }
13388cfa0ad2SJack F Vogel 
13398cfa0ad2SJack F Vogel /**
13408cfa0ad2SJack F Vogel  *  e1000_reset_hw_82575 - Reset hardware
13418cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13428cfa0ad2SJack F Vogel  *
1343daf9197cSJack F Vogel  *  This resets the hardware into a known state.
13448cfa0ad2SJack F Vogel  **/
13458cfa0ad2SJack F Vogel static s32 e1000_reset_hw_82575(struct e1000_hw *hw)
13468cfa0ad2SJack F Vogel {
1347f0ecc46dSJack F Vogel 	u32 ctrl;
13488cfa0ad2SJack F Vogel 	s32 ret_val;
13498cfa0ad2SJack F Vogel 
13508cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_82575");
13518cfa0ad2SJack F Vogel 
13528cfa0ad2SJack F Vogel 	/*
13538cfa0ad2SJack F Vogel 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
13548cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
13558cfa0ad2SJack F Vogel 	 */
13568cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
13574dab5c37SJack F Vogel 	if (ret_val)
13588cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
13598cfa0ad2SJack F Vogel 
13609d81738fSJack F Vogel 	/* set the completion timeout for interface */
13619d81738fSJack F Vogel 	ret_val = e1000_set_pcie_completion_timeout(hw);
13624dab5c37SJack F Vogel 	if (ret_val)
13639d81738fSJack F Vogel 		DEBUGOUT("PCI-E Set completion timeout has failed.\n");
13649d81738fSJack F Vogel 
13658cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
13668cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
13678cfa0ad2SJack F Vogel 
13688cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
13698cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
13708cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
13718cfa0ad2SJack F Vogel 
13728cfa0ad2SJack F Vogel 	msec_delay(10);
13738cfa0ad2SJack F Vogel 
13748cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
13758cfa0ad2SJack F Vogel 
13768cfa0ad2SJack F Vogel 	DEBUGOUT("Issuing a global reset to MAC\n");
13778cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
13788cfa0ad2SJack F Vogel 
13798cfa0ad2SJack F Vogel 	ret_val = e1000_get_auto_rd_done_generic(hw);
13808cfa0ad2SJack F Vogel 	if (ret_val) {
13818cfa0ad2SJack F Vogel 		/*
13828cfa0ad2SJack F Vogel 		 * When auto config read does not complete, do not
13838cfa0ad2SJack F Vogel 		 * return with an error. This can happen in situations
13848cfa0ad2SJack F Vogel 		 * where there is no eeprom and prevents getting link.
13858cfa0ad2SJack F Vogel 		 */
13868cfa0ad2SJack F Vogel 		DEBUGOUT("Auto Read Done did not complete\n");
13878cfa0ad2SJack F Vogel 	}
13888cfa0ad2SJack F Vogel 
13898cfa0ad2SJack F Vogel 	/* If EEPROM is not present, run manual init scripts */
1390ab5d0362SJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES))
13918cfa0ad2SJack F Vogel 		e1000_reset_init_script_82575(hw);
13928cfa0ad2SJack F Vogel 
13938cfa0ad2SJack F Vogel 	/* Clear any pending interrupt events. */
13948cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
1395f0ecc46dSJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
13968cfa0ad2SJack F Vogel 
1397d035aa2dSJack F Vogel 	/* Install any alternate MAC address into RAR0 */
1398d035aa2dSJack F Vogel 	ret_val = e1000_check_alt_mac_addr_generic(hw);
13998cfa0ad2SJack F Vogel 
14008cfa0ad2SJack F Vogel 	return ret_val;
14018cfa0ad2SJack F Vogel }
14028cfa0ad2SJack F Vogel 
14038cfa0ad2SJack F Vogel /**
14048cfa0ad2SJack F Vogel  *  e1000_init_hw_82575 - Initialize hardware
14058cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
14068cfa0ad2SJack F Vogel  *
14078cfa0ad2SJack F Vogel  *  This inits the hardware readying it for operation.
14088cfa0ad2SJack F Vogel  **/
14098cc64f1eSJack F Vogel s32 e1000_init_hw_82575(struct e1000_hw *hw)
14108cfa0ad2SJack F Vogel {
14118cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
14128cfa0ad2SJack F Vogel 	s32 ret_val;
14138cfa0ad2SJack F Vogel 	u16 i, rar_count = mac->rar_entry_count;
14148cfa0ad2SJack F Vogel 
14158cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_82575");
14168cfa0ad2SJack F Vogel 
14178cfa0ad2SJack F Vogel 	/* Initialize identification LED */
1418d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
14198cfa0ad2SJack F Vogel 	if (ret_val) {
14208cfa0ad2SJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
14218cfa0ad2SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
14228cfa0ad2SJack F Vogel 	}
14238cfa0ad2SJack F Vogel 
14248cfa0ad2SJack F Vogel 	/* Disabling VLAN filtering */
14258cfa0ad2SJack F Vogel 	DEBUGOUT("Initializing the IEEE VLAN\n");
14268cfa0ad2SJack F Vogel 	mac->ops.clear_vfta(hw);
14278cfa0ad2SJack F Vogel 
14288cfa0ad2SJack F Vogel 	/* Setup the receive address */
1429d035aa2dSJack F Vogel 	e1000_init_rx_addrs_generic(hw, rar_count);
1430d035aa2dSJack F Vogel 
14318cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
14328cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
14338cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
14348cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
14358cfa0ad2SJack F Vogel 
14364edd8523SJack F Vogel 	/* Zero out the Unicast HASH table */
14374edd8523SJack F Vogel 	DEBUGOUT("Zeroing the UTA\n");
14384edd8523SJack F Vogel 	for (i = 0; i < mac->uta_reg_count; i++)
14394edd8523SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_UTA, i, 0);
14404edd8523SJack F Vogel 
14418cfa0ad2SJack F Vogel 	/* Setup link and flow control */
14428cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
14438cfa0ad2SJack F Vogel 
14444dab5c37SJack F Vogel 	/* Set the default MTU size */
14454dab5c37SJack F Vogel 	hw->dev_spec._82575.mtu = 1500;
14464dab5c37SJack F Vogel 
14478cfa0ad2SJack F Vogel 	/*
14488cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
14498cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
14508cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
14518cfa0ad2SJack F Vogel 	 * is no link.
14528cfa0ad2SJack F Vogel 	 */
14538cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_82575(hw);
14548cfa0ad2SJack F Vogel 
14558cfa0ad2SJack F Vogel 	return ret_val;
14568cfa0ad2SJack F Vogel }
14578cfa0ad2SJack F Vogel 
14588cfa0ad2SJack F Vogel /**
14598cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_82575 - Configure copper link settings
14608cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
14618cfa0ad2SJack F Vogel  *
14628cfa0ad2SJack F Vogel  *  Configures the link for auto-neg or forced speed and duplex.  Then we check
14638cfa0ad2SJack F Vogel  *  for link, once link is established calls to configure collision distance
14648cfa0ad2SJack F Vogel  *  and flow control are called.
14658cfa0ad2SJack F Vogel  **/
14668cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_82575(struct e1000_hw *hw)
14678cfa0ad2SJack F Vogel {
14689d81738fSJack F Vogel 	u32 ctrl;
14698cfa0ad2SJack F Vogel 	s32 ret_val;
14706ab6bfe3SJack F Vogel 	u32 phpm_reg;
14718cfa0ad2SJack F Vogel 
14728cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_82575");
14738cfa0ad2SJack F Vogel 
14748cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
14758cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
14768cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
14778cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
14788cfa0ad2SJack F Vogel 
14797609433eSJack F Vogel 	/* Clear Go Link Disconnect bit on supported devices */
14807609433eSJack F Vogel 	switch (hw->mac.type) {
14817609433eSJack F Vogel 	case e1000_82580:
14827609433eSJack F Vogel 	case e1000_i350:
14837609433eSJack F Vogel 	case e1000_i210:
14847609433eSJack F Vogel 	case e1000_i211:
14856ab6bfe3SJack F Vogel 		phpm_reg = E1000_READ_REG(hw, E1000_82580_PHY_POWER_MGMT);
14866ab6bfe3SJack F Vogel 		phpm_reg &= ~E1000_82580_PM_GO_LINKD;
14876ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_82580_PHY_POWER_MGMT, phpm_reg);
14887609433eSJack F Vogel 		break;
14897609433eSJack F Vogel 	default:
14907609433eSJack F Vogel 		break;
14916ab6bfe3SJack F Vogel 	}
14926ab6bfe3SJack F Vogel 
14934edd8523SJack F Vogel 	ret_val = e1000_setup_serdes_link_82575(hw);
14944edd8523SJack F Vogel 	if (ret_val)
14954edd8523SJack F Vogel 		goto out;
14964edd8523SJack F Vogel 
14974dab5c37SJack F Vogel 	if (e1000_sgmii_active_82575(hw)) {
14984edd8523SJack F Vogel 		/* allow time for SFP cage time to power up phy */
14994edd8523SJack F Vogel 		msec_delay(300);
15004edd8523SJack F Vogel 
15014edd8523SJack F Vogel 		ret_val = hw->phy.ops.reset(hw);
15024edd8523SJack F Vogel 		if (ret_val) {
15034edd8523SJack F Vogel 			DEBUGOUT("Error resetting the PHY.\n");
15044edd8523SJack F Vogel 			goto out;
15054edd8523SJack F Vogel 		}
15064edd8523SJack F Vogel 	}
15078cfa0ad2SJack F Vogel 	switch (hw->phy.type) {
1508ab5d0362SJack F Vogel 	case e1000_phy_i210:
15098cfa0ad2SJack F Vogel 	case e1000_phy_m88:
15106ab6bfe3SJack F Vogel 		switch (hw->phy.id) {
15116ab6bfe3SJack F Vogel 		case I347AT4_E_PHY_ID:
15126ab6bfe3SJack F Vogel 		case M88E1112_E_PHY_ID:
15136ab6bfe3SJack F Vogel 		case M88E1340M_E_PHY_ID:
15147609433eSJack F Vogel 		case M88E1543_E_PHY_ID:
15157609433eSJack F Vogel 		case M88E1512_E_PHY_ID:
15166ab6bfe3SJack F Vogel 		case I210_I_PHY_ID:
1517f0ecc46dSJack F Vogel 			ret_val = e1000_copper_link_setup_m88_gen2(hw);
15186ab6bfe3SJack F Vogel 			break;
15196ab6bfe3SJack F Vogel 		default:
15208cfa0ad2SJack F Vogel 			ret_val = e1000_copper_link_setup_m88(hw);
15218cfa0ad2SJack F Vogel 			break;
15226ab6bfe3SJack F Vogel 		}
15236ab6bfe3SJack F Vogel 		break;
15248cfa0ad2SJack F Vogel 	case e1000_phy_igp_3:
15258cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
15268cfa0ad2SJack F Vogel 		break;
15274edd8523SJack F Vogel 	case e1000_phy_82580:
15284edd8523SJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
15294edd8523SJack F Vogel 		break;
15308cfa0ad2SJack F Vogel 	default:
15318cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
15328cfa0ad2SJack F Vogel 		break;
15338cfa0ad2SJack F Vogel 	}
15348cfa0ad2SJack F Vogel 
15358cfa0ad2SJack F Vogel 	if (ret_val)
15368cfa0ad2SJack F Vogel 		goto out;
15378cfa0ad2SJack F Vogel 
15384edd8523SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
15398cfa0ad2SJack F Vogel out:
15408cfa0ad2SJack F Vogel 	return ret_val;
15418cfa0ad2SJack F Vogel }
15428cfa0ad2SJack F Vogel 
15438cfa0ad2SJack F Vogel /**
15444edd8523SJack F Vogel  *  e1000_setup_serdes_link_82575 - Setup link for serdes
15458cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
15468cfa0ad2SJack F Vogel  *
15474edd8523SJack F Vogel  *  Configure the physical coding sub-layer (PCS) link.  The PCS link is
15484edd8523SJack F Vogel  *  used on copper connections where the serialized gigabit media independent
15494edd8523SJack F Vogel  *  interface (sgmii), or serdes fiber is being used.  Configures the link
15504edd8523SJack F Vogel  *  for auto-negotiation or forces speed/duplex.
15518cfa0ad2SJack F Vogel  **/
15524edd8523SJack F Vogel static s32 e1000_setup_serdes_link_82575(struct e1000_hw *hw)
15538cfa0ad2SJack F Vogel {
15546ab6bfe3SJack F Vogel 	u32 ctrl_ext, ctrl_reg, reg, anadv_reg;
15554edd8523SJack F Vogel 	bool pcs_autoneg;
15564dab5c37SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
15574dab5c37SJack F Vogel 	u16 data;
15588cfa0ad2SJack F Vogel 
15594edd8523SJack F Vogel 	DEBUGFUNC("e1000_setup_serdes_link_82575");
15604edd8523SJack F Vogel 
15614edd8523SJack F Vogel 	if ((hw->phy.media_type != e1000_media_type_internal_serdes) &&
15624edd8523SJack F Vogel 	    !e1000_sgmii_active_82575(hw))
15634dab5c37SJack F Vogel 		return ret_val;
15648cfa0ad2SJack F Vogel 
15658cfa0ad2SJack F Vogel 	/*
15668cfa0ad2SJack F Vogel 	 * On the 82575, SerDes loopback mode persists until it is
15678cfa0ad2SJack F Vogel 	 * explicitly turned off or a power cycle is performed.  A read to
15688cfa0ad2SJack F Vogel 	 * the register does not indicate its status.  Therefore, we ensure
15698cfa0ad2SJack F Vogel 	 * loopback mode is disabled during initialization.
15708cfa0ad2SJack F Vogel 	 */
15718cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_SCTL, E1000_SCTL_DISABLE_SERDES_LOOPBACK);
15728cfa0ad2SJack F Vogel 
15734edd8523SJack F Vogel 	/* power on the sfp cage if present */
15744edd8523SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
15754edd8523SJack F Vogel 	ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
15764edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
15774edd8523SJack F Vogel 
15784edd8523SJack F Vogel 	ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
15794edd8523SJack F Vogel 	ctrl_reg |= E1000_CTRL_SLU;
15804edd8523SJack F Vogel 
1581a69ed8dfSJack F Vogel 	/* set both sw defined pins on 82575/82576*/
1582a69ed8dfSJack F Vogel 	if (hw->mac.type == e1000_82575 || hw->mac.type == e1000_82576)
15834edd8523SJack F Vogel 		ctrl_reg |= E1000_CTRL_SWDPIN0 | E1000_CTRL_SWDPIN1;
15848cfa0ad2SJack F Vogel 
15854edd8523SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_PCS_LCTL);
15864edd8523SJack F Vogel 
15874edd8523SJack F Vogel 	/* default pcs_autoneg to the same setting as mac autoneg */
15884edd8523SJack F Vogel 	pcs_autoneg = hw->mac.autoneg;
15894edd8523SJack F Vogel 
15904edd8523SJack F Vogel 	switch (ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK) {
15914edd8523SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_SGMII:
15924edd8523SJack F Vogel 		/* sgmii mode lets the phy handle forcing speed/duplex */
15934edd8523SJack F Vogel 		pcs_autoneg = TRUE;
15944edd8523SJack F Vogel 		/* autoneg time out should be disabled for SGMII mode */
15954edd8523SJack F Vogel 		reg &= ~(E1000_PCS_LCTL_AN_TIMEOUT);
15964edd8523SJack F Vogel 		break;
15974edd8523SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
15984edd8523SJack F Vogel 		/* disable PCS autoneg and support parallel detect only */
15994edd8523SJack F Vogel 		pcs_autoneg = FALSE;
1600a5b0fd9cSToomas Soome 		/* FALLTHROUGH */
16014edd8523SJack F Vogel 	default:
16024dab5c37SJack F Vogel 		if (hw->mac.type == e1000_82575 ||
16034dab5c37SJack F Vogel 		    hw->mac.type == e1000_82576) {
16044dab5c37SJack F Vogel 			ret_val = hw->nvm.ops.read(hw, NVM_COMPAT, 1, &data);
16054dab5c37SJack F Vogel 			if (ret_val) {
16064dab5c37SJack F Vogel 				DEBUGOUT("NVM Read Error\n");
16074dab5c37SJack F Vogel 				return ret_val;
16084dab5c37SJack F Vogel 			}
16094dab5c37SJack F Vogel 
16104dab5c37SJack F Vogel 			if (data & E1000_EEPROM_PCS_AUTONEG_DISABLE_BIT)
16114dab5c37SJack F Vogel 				pcs_autoneg = FALSE;
16124dab5c37SJack F Vogel 		}
16134dab5c37SJack F Vogel 
16144edd8523SJack F Vogel 		/*
16154edd8523SJack F Vogel 		 * non-SGMII modes only supports a speed of 1000/Full for the
16164edd8523SJack F Vogel 		 * link so it is best to just force the MAC and let the pcs
16174edd8523SJack F Vogel 		 * link either autoneg or be forced to 1000/Full
16184edd8523SJack F Vogel 		 */
16194edd8523SJack F Vogel 		ctrl_reg |= E1000_CTRL_SPD_1000 | E1000_CTRL_FRCSPD |
16204edd8523SJack F Vogel 			    E1000_CTRL_FD | E1000_CTRL_FRCDPX;
16214edd8523SJack F Vogel 
16224edd8523SJack F Vogel 		/* set speed of 1000/Full if speed/duplex is forced */
16234edd8523SJack F Vogel 		reg |= E1000_PCS_LCTL_FSV_1000 | E1000_PCS_LCTL_FDV_FULL;
16244edd8523SJack F Vogel 		break;
16254edd8523SJack F Vogel 	}
16264edd8523SJack F Vogel 
16274edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
16288cfa0ad2SJack F Vogel 
16298cfa0ad2SJack F Vogel 	/*
16308cfa0ad2SJack F Vogel 	 * New SerDes mode allows for forcing speed or autonegotiating speed
16318cfa0ad2SJack F Vogel 	 * at 1gb. Autoneg should be default set by most drivers. This is the
16328cfa0ad2SJack F Vogel 	 * mode that will be compatible with older link partners and switches.
16338cfa0ad2SJack F Vogel 	 * However, both are supported by the hardware and some drivers/tools.
16348cfa0ad2SJack F Vogel 	 */
16358cfa0ad2SJack F Vogel 	reg &= ~(E1000_PCS_LCTL_AN_ENABLE | E1000_PCS_LCTL_FLV_LINK_UP |
16368cfa0ad2SJack F Vogel 		 E1000_PCS_LCTL_FSD | E1000_PCS_LCTL_FORCE_LINK);
16378cfa0ad2SJack F Vogel 
16384edd8523SJack F Vogel 	if (pcs_autoneg) {
16394edd8523SJack F Vogel 		/* Set PCS register for autoneg */
16404edd8523SJack F Vogel 		reg |= E1000_PCS_LCTL_AN_ENABLE | /* Enable Autoneg */
16414edd8523SJack F Vogel 		       E1000_PCS_LCTL_AN_RESTART; /* Restart autoneg */
16426ab6bfe3SJack F Vogel 
16436ab6bfe3SJack F Vogel 		/* Disable force flow control for autoneg */
16446ab6bfe3SJack F Vogel 		reg &= ~E1000_PCS_LCTL_FORCE_FCTRL;
16456ab6bfe3SJack F Vogel 
16466ab6bfe3SJack F Vogel 		/* Configure flow control advertisement for autoneg */
16476ab6bfe3SJack F Vogel 		anadv_reg = E1000_READ_REG(hw, E1000_PCS_ANADV);
16486ab6bfe3SJack F Vogel 		anadv_reg &= ~(E1000_TXCW_ASM_DIR | E1000_TXCW_PAUSE);
16496ab6bfe3SJack F Vogel 
16506ab6bfe3SJack F Vogel 		switch (hw->fc.requested_mode) {
16516ab6bfe3SJack F Vogel 		case e1000_fc_full:
16526ab6bfe3SJack F Vogel 		case e1000_fc_rx_pause:
16536ab6bfe3SJack F Vogel 			anadv_reg |= E1000_TXCW_ASM_DIR;
16546ab6bfe3SJack F Vogel 			anadv_reg |= E1000_TXCW_PAUSE;
16556ab6bfe3SJack F Vogel 			break;
16566ab6bfe3SJack F Vogel 		case e1000_fc_tx_pause:
16576ab6bfe3SJack F Vogel 			anadv_reg |= E1000_TXCW_ASM_DIR;
16586ab6bfe3SJack F Vogel 			break;
16596ab6bfe3SJack F Vogel 		default:
16606ab6bfe3SJack F Vogel 			break;
16616ab6bfe3SJack F Vogel 		}
16626ab6bfe3SJack F Vogel 
16636ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PCS_ANADV, anadv_reg);
16646ab6bfe3SJack F Vogel 
16654edd8523SJack F Vogel 		DEBUGOUT1("Configuring Autoneg:PCS_LCTL=0x%08X\n", reg);
16664edd8523SJack F Vogel 	} else {
16674edd8523SJack F Vogel 		/* Set PCS register for forced link */
1668a69ed8dfSJack F Vogel 		reg |= E1000_PCS_LCTL_FSD;	/* Force Speed */
16696ab6bfe3SJack F Vogel 
16706ab6bfe3SJack F Vogel 		/* Force flow control for forced link */
16716ab6bfe3SJack F Vogel 		reg |= E1000_PCS_LCTL_FORCE_FCTRL;
16726ab6bfe3SJack F Vogel 
16734edd8523SJack F Vogel 		DEBUGOUT1("Configuring Forced Link:PCS_LCTL=0x%08X\n", reg);
16748cfa0ad2SJack F Vogel 	}
16758cfa0ad2SJack F Vogel 
16768cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PCS_LCTL, reg);
16778cfa0ad2SJack F Vogel 
16786ab6bfe3SJack F Vogel 	if (!pcs_autoneg && !e1000_sgmii_active_82575(hw))
16794edd8523SJack F Vogel 		e1000_force_mac_fc_generic(hw);
16804edd8523SJack F Vogel 
16814dab5c37SJack F Vogel 	return ret_val;
16824dab5c37SJack F Vogel }
16834dab5c37SJack F Vogel 
16844dab5c37SJack F Vogel /**
16854dab5c37SJack F Vogel  *  e1000_get_media_type_82575 - derives current media type.
16864dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
16874dab5c37SJack F Vogel  *
16884dab5c37SJack F Vogel  *  The media type is chosen reflecting few settings.
16894dab5c37SJack F Vogel  *  The following are taken into account:
16904dab5c37SJack F Vogel  *  - link mode set in the current port Init Control Word #3
16914dab5c37SJack F Vogel  *  - current link mode settings in CSR register
16924dab5c37SJack F Vogel  *  - MDIO vs. I2C PHY control interface chosen
16934dab5c37SJack F Vogel  *  - SFP module media type
16944dab5c37SJack F Vogel  **/
16954dab5c37SJack F Vogel static s32 e1000_get_media_type_82575(struct e1000_hw *hw)
16964dab5c37SJack F Vogel {
16974dab5c37SJack F Vogel 	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
16986ab6bfe3SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
16994dab5c37SJack F Vogel 	u32 ctrl_ext = 0;
17006ab6bfe3SJack F Vogel 	u32 link_mode = 0;
17014dab5c37SJack F Vogel 
17024dab5c37SJack F Vogel 	/* Set internal phy as default */
17034dab5c37SJack F Vogel 	dev_spec->sgmii_active = FALSE;
17044dab5c37SJack F Vogel 	dev_spec->module_plugged = FALSE;
17054dab5c37SJack F Vogel 
17064dab5c37SJack F Vogel 	/* Get CSR setting */
17074dab5c37SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
17084dab5c37SJack F Vogel 
17096ab6bfe3SJack F Vogel 	/* extract link mode setting */
17106ab6bfe3SJack F Vogel 	link_mode = ctrl_ext & E1000_CTRL_EXT_LINK_MODE_MASK;
17114dab5c37SJack F Vogel 
17126ab6bfe3SJack F Vogel 	switch (link_mode) {
17134dab5c37SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_1000BASE_KX:
17144dab5c37SJack F Vogel 		hw->phy.media_type = e1000_media_type_internal_serdes;
17154dab5c37SJack F Vogel 		break;
17164dab5c37SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_GMII:
17174dab5c37SJack F Vogel 		hw->phy.media_type = e1000_media_type_copper;
17184dab5c37SJack F Vogel 		break;
17194dab5c37SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_SGMII:
17204dab5c37SJack F Vogel 		/* Get phy control interface type set (MDIO vs. I2C)*/
17214dab5c37SJack F Vogel 		if (e1000_sgmii_uses_mdio_82575(hw)) {
17224dab5c37SJack F Vogel 			hw->phy.media_type = e1000_media_type_copper;
17234dab5c37SJack F Vogel 			dev_spec->sgmii_active = TRUE;
17244dab5c37SJack F Vogel 			break;
17254dab5c37SJack F Vogel 		}
17266ab6bfe3SJack F Vogel 		/* fall through for I2C based SGMII */
1727a5b0fd9cSToomas Soome 		/* FALLTHROUGH */
17286ab6bfe3SJack F Vogel 	case E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES:
17296ab6bfe3SJack F Vogel 		/* read media type from SFP EEPROM */
17306ab6bfe3SJack F Vogel 		ret_val = e1000_set_sfp_media_type_82575(hw);
17316ab6bfe3SJack F Vogel 		if ((ret_val != E1000_SUCCESS) ||
17326ab6bfe3SJack F Vogel 		    (hw->phy.media_type == e1000_media_type_unknown)) {
17334dab5c37SJack F Vogel 			/*
17346ab6bfe3SJack F Vogel 			 * If media type was not identified then return media
17356ab6bfe3SJack F Vogel 			 * type defined by the CTRL_EXT settings.
17364dab5c37SJack F Vogel 			 */
17376ab6bfe3SJack F Vogel 			hw->phy.media_type = e1000_media_type_internal_serdes;
17386ab6bfe3SJack F Vogel 
17396ab6bfe3SJack F Vogel 			if (link_mode == E1000_CTRL_EXT_LINK_MODE_SGMII) {
17406ab6bfe3SJack F Vogel 				hw->phy.media_type = e1000_media_type_copper;
17416ab6bfe3SJack F Vogel 				dev_spec->sgmii_active = TRUE;
17424dab5c37SJack F Vogel 			}
17434dab5c37SJack F Vogel 
17446ab6bfe3SJack F Vogel 			break;
17456ab6bfe3SJack F Vogel 		}
17466ab6bfe3SJack F Vogel 
17476ab6bfe3SJack F Vogel 		/* do not change link mode for 100BaseFX */
17486ab6bfe3SJack F Vogel 		if (dev_spec->eth_flags.e100_base_fx)
17496ab6bfe3SJack F Vogel 			break;
17506ab6bfe3SJack F Vogel 
17516ab6bfe3SJack F Vogel 		/* change current link mode setting */
17526ab6bfe3SJack F Vogel 		ctrl_ext &= ~E1000_CTRL_EXT_LINK_MODE_MASK;
17536ab6bfe3SJack F Vogel 
17546ab6bfe3SJack F Vogel 		if (hw->phy.media_type == e1000_media_type_copper)
17556ab6bfe3SJack F Vogel 			ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_SGMII;
17564dab5c37SJack F Vogel 		else
17576ab6bfe3SJack F Vogel 			ctrl_ext |= E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES;
17586ab6bfe3SJack F Vogel 
17596ab6bfe3SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
17606ab6bfe3SJack F Vogel 
17616ab6bfe3SJack F Vogel 		break;
17624dab5c37SJack F Vogel 	}
17634dab5c37SJack F Vogel 
17644dab5c37SJack F Vogel 	return ret_val;
17654dab5c37SJack F Vogel }
17664dab5c37SJack F Vogel 
17674dab5c37SJack F Vogel /**
17684dab5c37SJack F Vogel  *  e1000_set_sfp_media_type_82575 - derives SFP module media type.
17694dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
17704dab5c37SJack F Vogel  *
17714dab5c37SJack F Vogel  *  The media type is chosen based on SFP module.
17724dab5c37SJack F Vogel  *  compatibility flags retrieved from SFP ID EEPROM.
17734dab5c37SJack F Vogel  **/
17744dab5c37SJack F Vogel static s32 e1000_set_sfp_media_type_82575(struct e1000_hw *hw)
17754dab5c37SJack F Vogel {
17764dab5c37SJack F Vogel 	s32 ret_val = E1000_ERR_CONFIG;
17774dab5c37SJack F Vogel 	u32 ctrl_ext = 0;
17784dab5c37SJack F Vogel 	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
17796ab6bfe3SJack F Vogel 	struct sfp_e1000_flags *eth_flags = &dev_spec->eth_flags;
17804dab5c37SJack F Vogel 	u8 tranceiver_type = 0;
17816ab6bfe3SJack F Vogel 	s32 timeout = 3;
17824dab5c37SJack F Vogel 
17836ab6bfe3SJack F Vogel 	/* Turn I2C interface ON and power on sfp cage */
17844dab5c37SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
17856ab6bfe3SJack F Vogel 	ctrl_ext &= ~E1000_CTRL_EXT_SDP3_DATA;
17864dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext | E1000_CTRL_I2C_ENA);
17874dab5c37SJack F Vogel 
17886ab6bfe3SJack F Vogel 	E1000_WRITE_FLUSH(hw);
17896ab6bfe3SJack F Vogel 
17904dab5c37SJack F Vogel 	/* Read SFP module data */
17916ab6bfe3SJack F Vogel 	while (timeout) {
17924dab5c37SJack F Vogel 		ret_val = e1000_read_sfp_data_byte(hw,
17934dab5c37SJack F Vogel 			E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_IDENTIFIER_OFFSET),
17944dab5c37SJack F Vogel 			&tranceiver_type);
17956ab6bfe3SJack F Vogel 		if (ret_val == E1000_SUCCESS)
17966ab6bfe3SJack F Vogel 			break;
17976ab6bfe3SJack F Vogel 		msec_delay(100);
17986ab6bfe3SJack F Vogel 		timeout--;
17996ab6bfe3SJack F Vogel 	}
18004dab5c37SJack F Vogel 	if (ret_val != E1000_SUCCESS)
18014dab5c37SJack F Vogel 		goto out;
18026ab6bfe3SJack F Vogel 
18034dab5c37SJack F Vogel 	ret_val = e1000_read_sfp_data_byte(hw,
18044dab5c37SJack F Vogel 			E1000_I2CCMD_SFP_DATA_ADDR(E1000_SFF_ETH_FLAGS_OFFSET),
18056ab6bfe3SJack F Vogel 			(u8 *)eth_flags);
18064dab5c37SJack F Vogel 	if (ret_val != E1000_SUCCESS)
18074dab5c37SJack F Vogel 		goto out;
18086ab6bfe3SJack F Vogel 
18096ab6bfe3SJack F Vogel 	/* Check if there is some SFP module plugged and powered */
18104dab5c37SJack F Vogel 	if ((tranceiver_type == E1000_SFF_IDENTIFIER_SFP) ||
18114dab5c37SJack F Vogel 	    (tranceiver_type == E1000_SFF_IDENTIFIER_SFF)) {
18124dab5c37SJack F Vogel 		dev_spec->module_plugged = TRUE;
18136ab6bfe3SJack F Vogel 		if (eth_flags->e1000_base_lx || eth_flags->e1000_base_sx) {
18144dab5c37SJack F Vogel 			hw->phy.media_type = e1000_media_type_internal_serdes;
18156ab6bfe3SJack F Vogel 		} else if (eth_flags->e100_base_fx) {
18166ab6bfe3SJack F Vogel 			dev_spec->sgmii_active = TRUE;
18176ab6bfe3SJack F Vogel 			hw->phy.media_type = e1000_media_type_internal_serdes;
18186ab6bfe3SJack F Vogel 		} else if (eth_flags->e1000_base_t) {
18194dab5c37SJack F Vogel 			dev_spec->sgmii_active = TRUE;
18204dab5c37SJack F Vogel 			hw->phy.media_type = e1000_media_type_copper;
18214dab5c37SJack F Vogel 		} else {
18224dab5c37SJack F Vogel 			hw->phy.media_type = e1000_media_type_unknown;
18234dab5c37SJack F Vogel 			DEBUGOUT("PHY module has not been recognized\n");
18244dab5c37SJack F Vogel 			goto out;
18254dab5c37SJack F Vogel 		}
18264dab5c37SJack F Vogel 	} else {
18274dab5c37SJack F Vogel 		hw->phy.media_type = e1000_media_type_unknown;
18284dab5c37SJack F Vogel 	}
18294dab5c37SJack F Vogel 	ret_val = E1000_SUCCESS;
18304dab5c37SJack F Vogel out:
18314dab5c37SJack F Vogel 	/* Restore I2C interface setting */
18324dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
18334dab5c37SJack F Vogel 	return ret_val;
18348cfa0ad2SJack F Vogel }
18358cfa0ad2SJack F Vogel 
18368cfa0ad2SJack F Vogel /**
18378cfa0ad2SJack F Vogel  *  e1000_valid_led_default_82575 - Verify a valid default LED config
18388cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18398cfa0ad2SJack F Vogel  *  @data: pointer to the NVM (EEPROM)
18408cfa0ad2SJack F Vogel  *
18418cfa0ad2SJack F Vogel  *  Read the EEPROM for the current default LED configuration.  If the
18428cfa0ad2SJack F Vogel  *  LED configuration is not valid, set to a valid LED configuration.
18438cfa0ad2SJack F Vogel  **/
18448cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_82575(struct e1000_hw *hw, u16 *data)
18458cfa0ad2SJack F Vogel {
18468cfa0ad2SJack F Vogel 	s32 ret_val;
18478cfa0ad2SJack F Vogel 
18488cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_82575");
18498cfa0ad2SJack F Vogel 
18508cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
18518cfa0ad2SJack F Vogel 	if (ret_val) {
18528cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
18538cfa0ad2SJack F Vogel 		goto out;
18548cfa0ad2SJack F Vogel 	}
18558cfa0ad2SJack F Vogel 
18568cfa0ad2SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) {
18578cfa0ad2SJack F Vogel 		switch (hw->phy.media_type) {
18588cfa0ad2SJack F Vogel 		case e1000_media_type_internal_serdes:
18598cfa0ad2SJack F Vogel 			*data = ID_LED_DEFAULT_82575_SERDES;
18608cfa0ad2SJack F Vogel 			break;
18618cfa0ad2SJack F Vogel 		case e1000_media_type_copper:
18628cfa0ad2SJack F Vogel 		default:
18638cfa0ad2SJack F Vogel 			*data = ID_LED_DEFAULT;
18648cfa0ad2SJack F Vogel 			break;
18658cfa0ad2SJack F Vogel 		}
18668cfa0ad2SJack F Vogel 	}
18678cfa0ad2SJack F Vogel out:
18688cfa0ad2SJack F Vogel 	return ret_val;
18698cfa0ad2SJack F Vogel }
18708cfa0ad2SJack F Vogel 
18718cfa0ad2SJack F Vogel /**
18728cfa0ad2SJack F Vogel  *  e1000_sgmii_active_82575 - Return sgmii state
18738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18748cfa0ad2SJack F Vogel  *
18758cfa0ad2SJack F Vogel  *  82575 silicon has a serialized gigabit media independent interface (sgmii)
18768cfa0ad2SJack F Vogel  *  which can be enabled for use in the embedded applications.  Simply
18778cfa0ad2SJack F Vogel  *  return the current state of the sgmii interface.
18788cfa0ad2SJack F Vogel  **/
18798cfa0ad2SJack F Vogel static bool e1000_sgmii_active_82575(struct e1000_hw *hw)
18808cfa0ad2SJack F Vogel {
1881daf9197cSJack F Vogel 	struct e1000_dev_spec_82575 *dev_spec = &hw->dev_spec._82575;
1882daf9197cSJack F Vogel 	return dev_spec->sgmii_active;
18838cfa0ad2SJack F Vogel }
18848cfa0ad2SJack F Vogel 
18858cfa0ad2SJack F Vogel /**
18868cfa0ad2SJack F Vogel  *  e1000_reset_init_script_82575 - Inits HW defaults after reset
18878cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18888cfa0ad2SJack F Vogel  *
18898cfa0ad2SJack F Vogel  *  Inits recommended HW defaults after a reset when there is no EEPROM
18908cfa0ad2SJack F Vogel  *  detected. This is only for the 82575.
18918cfa0ad2SJack F Vogel  **/
18928cfa0ad2SJack F Vogel static s32 e1000_reset_init_script_82575(struct e1000_hw *hw)
18938cfa0ad2SJack F Vogel {
18948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_init_script_82575");
18958cfa0ad2SJack F Vogel 
18968cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_82575) {
18978cfa0ad2SJack F Vogel 		DEBUGOUT("Running reset init script for 82575\n");
18988cfa0ad2SJack F Vogel 		/* SerDes configuration via SERDESCTRL */
18998cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x00, 0x0C);
19008cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x01, 0x78);
19018cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x1B, 0x23);
19028cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCTL, 0x23, 0x15);
19038cfa0ad2SJack F Vogel 
19048cfa0ad2SJack F Vogel 		/* CCM configuration via CCMCTL register */
19058cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x14, 0x00);
19068cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_CCMCTL, 0x10, 0x00);
19078cfa0ad2SJack F Vogel 
19088cfa0ad2SJack F Vogel 		/* PCIe lanes configuration */
19098cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x00, 0xEC);
19108cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x61, 0xDF);
19118cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x34, 0x05);
19128cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_GIOCTL, 0x2F, 0x81);
19138cfa0ad2SJack F Vogel 
19148cfa0ad2SJack F Vogel 		/* PCIe PLL Configuration */
19158cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x02, 0x47);
19168cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x14, 0x00);
19178cfa0ad2SJack F Vogel 		e1000_write_8bit_ctrl_reg_generic(hw, E1000_SCCTL, 0x10, 0x00);
19188cfa0ad2SJack F Vogel 	}
19198cfa0ad2SJack F Vogel 
19208cfa0ad2SJack F Vogel 	return E1000_SUCCESS;
19218cfa0ad2SJack F Vogel }
19228cfa0ad2SJack F Vogel 
19238cfa0ad2SJack F Vogel /**
19248cfa0ad2SJack F Vogel  *  e1000_read_mac_addr_82575 - Read device MAC address
19258cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19268cfa0ad2SJack F Vogel  **/
19278cfa0ad2SJack F Vogel static s32 e1000_read_mac_addr_82575(struct e1000_hw *hw)
19288cfa0ad2SJack F Vogel {
19298cc64f1eSJack F Vogel 	s32 ret_val;
19308cfa0ad2SJack F Vogel 
19318cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_mac_addr_82575");
1932d035aa2dSJack F Vogel 
1933d035aa2dSJack F Vogel 	/*
1934d035aa2dSJack F Vogel 	 * If there's an alternate MAC address place it in RAR0
1935d035aa2dSJack F Vogel 	 * so that it will override the Si installed default perm
1936d035aa2dSJack F Vogel 	 * address.
1937d035aa2dSJack F Vogel 	 */
1938d035aa2dSJack F Vogel 	ret_val = e1000_check_alt_mac_addr_generic(hw);
1939d035aa2dSJack F Vogel 	if (ret_val)
1940d035aa2dSJack F Vogel 		goto out;
1941d035aa2dSJack F Vogel 
19428cfa0ad2SJack F Vogel 	ret_val = e1000_read_mac_addr_generic(hw);
19438cfa0ad2SJack F Vogel 
1944d035aa2dSJack F Vogel out:
19458cfa0ad2SJack F Vogel 	return ret_val;
19468cfa0ad2SJack F Vogel }
19478cfa0ad2SJack F Vogel 
19488cfa0ad2SJack F Vogel /**
1949a69ed8dfSJack F Vogel  *  e1000_config_collision_dist_82575 - Configure collision distance
1950a69ed8dfSJack F Vogel  *  @hw: pointer to the HW structure
1951a69ed8dfSJack F Vogel  *
1952a69ed8dfSJack F Vogel  *  Configures the collision distance to the default value and is used
1953a69ed8dfSJack F Vogel  *  during link setup.
1954a69ed8dfSJack F Vogel  **/
1955a69ed8dfSJack F Vogel static void e1000_config_collision_dist_82575(struct e1000_hw *hw)
1956a69ed8dfSJack F Vogel {
1957a69ed8dfSJack F Vogel 	u32 tctl_ext;
1958a69ed8dfSJack F Vogel 
1959a69ed8dfSJack F Vogel 	DEBUGFUNC("e1000_config_collision_dist_82575");
1960a69ed8dfSJack F Vogel 
1961a69ed8dfSJack F Vogel 	tctl_ext = E1000_READ_REG(hw, E1000_TCTL_EXT);
1962a69ed8dfSJack F Vogel 
1963a69ed8dfSJack F Vogel 	tctl_ext &= ~E1000_TCTL_EXT_COLD;
1964a69ed8dfSJack F Vogel 	tctl_ext |= E1000_COLLISION_DISTANCE << E1000_TCTL_EXT_COLD_SHIFT;
1965a69ed8dfSJack F Vogel 
1966a69ed8dfSJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL_EXT, tctl_ext);
1967a69ed8dfSJack F Vogel 	E1000_WRITE_FLUSH(hw);
1968a69ed8dfSJack F Vogel }
1969a69ed8dfSJack F Vogel 
1970a69ed8dfSJack F Vogel /**
19718cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_82575 - Remove link during PHY power down
19728cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
19738cfa0ad2SJack F Vogel  *
19748cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
19758cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
19768cfa0ad2SJack F Vogel  **/
19778cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_82575(struct e1000_hw *hw)
19788cfa0ad2SJack F Vogel {
19798cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
19808cfa0ad2SJack F Vogel 
19818cfa0ad2SJack F Vogel 	if (!(phy->ops.check_reset_block))
19828cfa0ad2SJack F Vogel 		return;
19838cfa0ad2SJack F Vogel 
19848cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
19858ec87fc5SJack F Vogel 	if (!(e1000_enable_mng_pass_thru(hw) || phy->ops.check_reset_block(hw)))
19868cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
19878cfa0ad2SJack F Vogel 
19888cfa0ad2SJack F Vogel 	return;
19898cfa0ad2SJack F Vogel }
19908cfa0ad2SJack F Vogel 
19918cfa0ad2SJack F Vogel /**
19928cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_82575 - Clear device specific hardware counters
19938cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19948cfa0ad2SJack F Vogel  *
19958cfa0ad2SJack F Vogel  *  Clears the hardware counters by reading the counter registers.
19968cfa0ad2SJack F Vogel  **/
19978cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_82575(struct e1000_hw *hw)
19988cfa0ad2SJack F Vogel {
19998cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_82575");
20008cfa0ad2SJack F Vogel 
20018cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
20028cfa0ad2SJack F Vogel 
2003daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC64);
2004daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC127);
2005daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC255);
2006daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC511);
2007daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC1023);
2008daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PRC1522);
2009daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC64);
2010daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC127);
2011daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC255);
2012daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC511);
2013daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC1023);
2014daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_PTC1522);
20158cfa0ad2SJack F Vogel 
2016daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
2017daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
2018daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
2019daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
2020daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
2021daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
20228cfa0ad2SJack F Vogel 
2023daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
2024daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
2025daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
20268cfa0ad2SJack F Vogel 
2027daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
2028daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
20298cfa0ad2SJack F Vogel 
2030daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXPTC);
2031daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXATC);
2032daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICTXPTC);
2033daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICTXATC);
2034daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICTXQEC);
2035daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICTXQMTC);
2036daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXDMTC);
20378cfa0ad2SJack F Vogel 
2038daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CBTMPC);
2039daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HTDPMC);
2040daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CBRMPC);
2041daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RPTHC);
2042daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HGPTC);
2043daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HTCBDPC);
2044daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HGORCL);
2045daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HGORCH);
2046daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HGOTCL);
2047daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_HGOTCH);
2048daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_LENERRS);
20498cfa0ad2SJack F Vogel 
20508cfa0ad2SJack F Vogel 	/* This register should not be read in copper configurations */
20514edd8523SJack F Vogel 	if ((hw->phy.media_type == e1000_media_type_internal_serdes) ||
20524edd8523SJack F Vogel 	    e1000_sgmii_active_82575(hw))
2053daf9197cSJack F Vogel 		E1000_READ_REG(hw, E1000_SCVPC);
20548cfa0ad2SJack F Vogel }
20559d81738fSJack F Vogel 
20568cfa0ad2SJack F Vogel /**
2057f0ecc46dSJack F Vogel  *  e1000_rx_fifo_flush_82575 - Clean rx fifo after Rx enable
20588cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20598cfa0ad2SJack F Vogel  *
206048600901SSean Bruno  *  After Rx enable, if manageability is enabled then there is likely some
20618cfa0ad2SJack F Vogel  *  bad data at the start of the fifo and possibly in the DMA fifo.  This
20628cfa0ad2SJack F Vogel  *  function clears the fifos and flushes any packets that came in as rx was
20638cfa0ad2SJack F Vogel  *  being enabled.
20648cfa0ad2SJack F Vogel  **/
20658cfa0ad2SJack F Vogel void e1000_rx_fifo_flush_82575(struct e1000_hw *hw)
20668cfa0ad2SJack F Vogel {
20678cfa0ad2SJack F Vogel 	u32 rctl, rlpml, rxdctl[4], rfctl, temp_rctl, rx_enabled;
20688cfa0ad2SJack F Vogel 	int i, ms_wait;
20698cfa0ad2SJack F Vogel 
2070c80429ceSEric Joyner 	DEBUGFUNC("e1000_rx_fifo_flush_82575");
2071c80429ceSEric Joyner 
2072c80429ceSEric Joyner 	/* disable IPv6 options as per hardware errata */
2073c80429ceSEric Joyner 	rfctl = E1000_READ_REG(hw, E1000_RFCTL);
2074c80429ceSEric Joyner 	rfctl |= E1000_RFCTL_IPV6_EX_DIS;
2075c80429ceSEric Joyner 	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
2076c80429ceSEric Joyner 
20778cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_82575 ||
20788cfa0ad2SJack F Vogel 	    !(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_RCV_TCO_EN))
20798cfa0ad2SJack F Vogel 		return;
20808cfa0ad2SJack F Vogel 
2081f0ecc46dSJack F Vogel 	/* Disable all Rx queues */
20828cfa0ad2SJack F Vogel 	for (i = 0; i < 4; i++) {
20838cfa0ad2SJack F Vogel 		rxdctl[i] = E1000_READ_REG(hw, E1000_RXDCTL(i));
20848cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RXDCTL(i),
20858cfa0ad2SJack F Vogel 				rxdctl[i] & ~E1000_RXDCTL_QUEUE_ENABLE);
20868cfa0ad2SJack F Vogel 	}
20878cfa0ad2SJack F Vogel 	/* Poll all queues to verify they have shut down */
20888cfa0ad2SJack F Vogel 	for (ms_wait = 0; ms_wait < 10; ms_wait++) {
20898cfa0ad2SJack F Vogel 		msec_delay(1);
20908cfa0ad2SJack F Vogel 		rx_enabled = 0;
20918cfa0ad2SJack F Vogel 		for (i = 0; i < 4; i++)
20928cfa0ad2SJack F Vogel 			rx_enabled |= E1000_READ_REG(hw, E1000_RXDCTL(i));
20938cfa0ad2SJack F Vogel 		if (!(rx_enabled & E1000_RXDCTL_QUEUE_ENABLE))
20948cfa0ad2SJack F Vogel 			break;
20958cfa0ad2SJack F Vogel 	}
20968cfa0ad2SJack F Vogel 
20978cfa0ad2SJack F Vogel 	if (ms_wait == 10)
20988cfa0ad2SJack F Vogel 		DEBUGOUT("Queue disable timed out after 10ms\n");
20998cfa0ad2SJack F Vogel 
21008cfa0ad2SJack F Vogel 	/* Clear RLPML, RCTL.SBP, RFCTL.LEF, and set RCTL.LPE so that all
21018cfa0ad2SJack F Vogel 	 * incoming packets are rejected.  Set enable and wait 2ms so that
21028cfa0ad2SJack F Vogel 	 * any packet that was coming in as RCTL.EN was set is flushed
21038cfa0ad2SJack F Vogel 	 */
21048cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl & ~E1000_RFCTL_LEF);
21058cfa0ad2SJack F Vogel 
21068cfa0ad2SJack F Vogel 	rlpml = E1000_READ_REG(hw, E1000_RLPML);
21078cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RLPML, 0);
21088cfa0ad2SJack F Vogel 
21098cfa0ad2SJack F Vogel 	rctl = E1000_READ_REG(hw, E1000_RCTL);
21108cfa0ad2SJack F Vogel 	temp_rctl = rctl & ~(E1000_RCTL_EN | E1000_RCTL_SBP);
21118cfa0ad2SJack F Vogel 	temp_rctl |= E1000_RCTL_LPE;
21128cfa0ad2SJack F Vogel 
21138cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl);
21148cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, temp_rctl | E1000_RCTL_EN);
21158cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
21168cfa0ad2SJack F Vogel 	msec_delay(2);
21178cfa0ad2SJack F Vogel 
2118f0ecc46dSJack F Vogel 	/* Enable Rx queues that were previously enabled and restore our
21198cfa0ad2SJack F Vogel 	 * previous state
21208cfa0ad2SJack F Vogel 	 */
21218cfa0ad2SJack F Vogel 	for (i = 0; i < 4; i++)
21228cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_RXDCTL(i), rxdctl[i]);
21238cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, rctl);
21248cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
21258cfa0ad2SJack F Vogel 
21268cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RLPML, rlpml);
21278cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RFCTL, rfctl);
21288cfa0ad2SJack F Vogel 
21298cfa0ad2SJack F Vogel 	/* Flush receive errors generated by workaround */
21308cfa0ad2SJack F Vogel 	E1000_READ_REG(hw, E1000_ROC);
21318cfa0ad2SJack F Vogel 	E1000_READ_REG(hw, E1000_RNBC);
21328cfa0ad2SJack F Vogel 	E1000_READ_REG(hw, E1000_MPC);
21338cfa0ad2SJack F Vogel }
2134daf9197cSJack F Vogel 
21359d81738fSJack F Vogel /**
21369d81738fSJack F Vogel  *  e1000_set_pcie_completion_timeout - set pci-e completion timeout
21379d81738fSJack F Vogel  *  @hw: pointer to the HW structure
21389d81738fSJack F Vogel  *
21399d81738fSJack F Vogel  *  The defaults for 82575 and 82576 should be in the range of 50us to 50ms,
21409d81738fSJack F Vogel  *  however the hardware default for these parts is 500us to 1ms which is less
21419d81738fSJack F Vogel  *  than the 10ms recommended by the pci-e spec.  To address this we need to
21429d81738fSJack F Vogel  *  increase the value to either 10ms to 200ms for capability version 1 config,
21439d81738fSJack F Vogel  *  or 16ms to 55ms for version 2.
21449d81738fSJack F Vogel  **/
21459d81738fSJack F Vogel static s32 e1000_set_pcie_completion_timeout(struct e1000_hw *hw)
21469d81738fSJack F Vogel {
21479d81738fSJack F Vogel 	u32 gcr = E1000_READ_REG(hw, E1000_GCR);
21489d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
21499d81738fSJack F Vogel 	u16 pcie_devctl2;
21509d81738fSJack F Vogel 
21519d81738fSJack F Vogel 	/* only take action if timeout value is defaulted to 0 */
21529d81738fSJack F Vogel 	if (gcr & E1000_GCR_CMPL_TMOUT_MASK)
21539d81738fSJack F Vogel 		goto out;
21549d81738fSJack F Vogel 
21559d81738fSJack F Vogel 	/*
21569d81738fSJack F Vogel 	 * if capababilities version is type 1 we can write the
21579d81738fSJack F Vogel 	 * timeout of 10ms to 200ms through the GCR register
21589d81738fSJack F Vogel 	 */
21599d81738fSJack F Vogel 	if (!(gcr & E1000_GCR_CAP_VER2)) {
21609d81738fSJack F Vogel 		gcr |= E1000_GCR_CMPL_TMOUT_10ms;
21619d81738fSJack F Vogel 		goto out;
21629d81738fSJack F Vogel 	}
21639d81738fSJack F Vogel 
21649d81738fSJack F Vogel 	/*
21659d81738fSJack F Vogel 	 * for version 2 capabilities we need to write the config space
21669d81738fSJack F Vogel 	 * directly in order to set the completion timeout value for
21679d81738fSJack F Vogel 	 * 16ms to 55ms
21689d81738fSJack F Vogel 	 */
21699d81738fSJack F Vogel 	ret_val = e1000_read_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
21709d81738fSJack F Vogel 					  &pcie_devctl2);
21719d81738fSJack F Vogel 	if (ret_val)
21729d81738fSJack F Vogel 		goto out;
21739d81738fSJack F Vogel 
21749d81738fSJack F Vogel 	pcie_devctl2 |= PCIE_DEVICE_CONTROL2_16ms;
21759d81738fSJack F Vogel 
21769d81738fSJack F Vogel 	ret_val = e1000_write_pcie_cap_reg(hw, PCIE_DEVICE_CONTROL2,
21779d81738fSJack F Vogel 					   &pcie_devctl2);
21789d81738fSJack F Vogel out:
21799d81738fSJack F Vogel 	/* disable completion timeout resend */
21809d81738fSJack F Vogel 	gcr &= ~E1000_GCR_CMPL_TMOUT_RESEND;
21819d81738fSJack F Vogel 
21829d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_GCR, gcr);
21839d81738fSJack F Vogel 	return ret_val;
21849d81738fSJack F Vogel }
21859d81738fSJack F Vogel 
21867d9119bdSJack F Vogel /**
21877d9119bdSJack F Vogel  *  e1000_vmdq_set_anti_spoofing_pf - enable or disable anti-spoofing
21887d9119bdSJack F Vogel  *  @hw: pointer to the hardware struct
21897d9119bdSJack F Vogel  *  @enable: state to enter, either enabled or disabled
21907d9119bdSJack F Vogel  *  @pf: Physical Function pool - do not set anti-spoofing for the PF
21917d9119bdSJack F Vogel  *
21927d9119bdSJack F Vogel  *  enables/disables L2 switch anti-spoofing functionality.
21937d9119bdSJack F Vogel  **/
21947d9119bdSJack F Vogel void e1000_vmdq_set_anti_spoofing_pf(struct e1000_hw *hw, bool enable, int pf)
21957d9119bdSJack F Vogel {
21967609433eSJack F Vogel 	u32 reg_val, reg_offset;
21977d9119bdSJack F Vogel 
21987d9119bdSJack F Vogel 	switch (hw->mac.type) {
21997d9119bdSJack F Vogel 	case e1000_82576:
22007609433eSJack F Vogel 		reg_offset = E1000_DTXSWC;
22017d9119bdSJack F Vogel 		break;
22024dab5c37SJack F Vogel 	case e1000_i350:
22037609433eSJack F Vogel 	case e1000_i354:
22047609433eSJack F Vogel 		reg_offset = E1000_TXSWC;
22057609433eSJack F Vogel 		break;
22067609433eSJack F Vogel 	default:
22077609433eSJack F Vogel 		return;
22087609433eSJack F Vogel 	}
22097609433eSJack F Vogel 
22107609433eSJack F Vogel 	reg_val = E1000_READ_REG(hw, reg_offset);
22114dab5c37SJack F Vogel 	if (enable) {
22127609433eSJack F Vogel 		reg_val |= (E1000_DTXSWC_MAC_SPOOF_MASK |
22134dab5c37SJack F Vogel 			     E1000_DTXSWC_VLAN_SPOOF_MASK);
22144dab5c37SJack F Vogel 		/* The PF can spoof - it has to in order to
22154dab5c37SJack F Vogel 		 * support emulation mode NICs
22164dab5c37SJack F Vogel 		 */
22177609433eSJack F Vogel 		reg_val ^= (1 << pf | 1 << (pf + MAX_NUM_VFS));
22184dab5c37SJack F Vogel 	} else {
22197609433eSJack F Vogel 		reg_val &= ~(E1000_DTXSWC_MAC_SPOOF_MASK |
22204dab5c37SJack F Vogel 			     E1000_DTXSWC_VLAN_SPOOF_MASK);
22214dab5c37SJack F Vogel 	}
22227609433eSJack F Vogel 	E1000_WRITE_REG(hw, reg_offset, reg_val);
22237d9119bdSJack F Vogel }
22247d9119bdSJack F Vogel 
22254edd8523SJack F Vogel /**
22264edd8523SJack F Vogel  *  e1000_vmdq_set_loopback_pf - enable or disable vmdq loopback
22274edd8523SJack F Vogel  *  @hw: pointer to the hardware struct
22284edd8523SJack F Vogel  *  @enable: state to enter, either enabled or disabled
22294edd8523SJack F Vogel  *
22304edd8523SJack F Vogel  *  enables/disables L2 switch loopback functionality.
22314edd8523SJack F Vogel  **/
22324edd8523SJack F Vogel void e1000_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
22334edd8523SJack F Vogel {
22348ec87fc5SJack F Vogel 	u32 dtxswc;
22354edd8523SJack F Vogel 
22368ec87fc5SJack F Vogel 	switch (hw->mac.type) {
22378ec87fc5SJack F Vogel 	case e1000_82576:
22388ec87fc5SJack F Vogel 		dtxswc = E1000_READ_REG(hw, E1000_DTXSWC);
22394edd8523SJack F Vogel 		if (enable)
22404edd8523SJack F Vogel 			dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
22414edd8523SJack F Vogel 		else
22424edd8523SJack F Vogel 			dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
22434edd8523SJack F Vogel 		E1000_WRITE_REG(hw, E1000_DTXSWC, dtxswc);
22448ec87fc5SJack F Vogel 		break;
2245f0ecc46dSJack F Vogel 	case e1000_i350:
22467609433eSJack F Vogel 	case e1000_i354:
2247f0ecc46dSJack F Vogel 		dtxswc = E1000_READ_REG(hw, E1000_TXSWC);
2248f0ecc46dSJack F Vogel 		if (enable)
2249f0ecc46dSJack F Vogel 			dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
2250f0ecc46dSJack F Vogel 		else
2251f0ecc46dSJack F Vogel 			dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
2252f0ecc46dSJack F Vogel 		E1000_WRITE_REG(hw, E1000_TXSWC, dtxswc);
2253f0ecc46dSJack F Vogel 		break;
22548ec87fc5SJack F Vogel 	default:
22558ec87fc5SJack F Vogel 		/* Currently no other hardware supports loopback */
22568ec87fc5SJack F Vogel 		break;
22578ec87fc5SJack F Vogel 	}
22588ec87fc5SJack F Vogel 
22598ec87fc5SJack F Vogel 
22604edd8523SJack F Vogel }
22614edd8523SJack F Vogel 
22624edd8523SJack F Vogel /**
22634edd8523SJack F Vogel  *  e1000_vmdq_set_replication_pf - enable or disable vmdq replication
22644edd8523SJack F Vogel  *  @hw: pointer to the hardware struct
22654edd8523SJack F Vogel  *  @enable: state to enter, either enabled or disabled
22664edd8523SJack F Vogel  *
22674edd8523SJack F Vogel  *  enables/disables replication of packets across multiple pools.
22684edd8523SJack F Vogel  **/
22694edd8523SJack F Vogel void e1000_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
22704edd8523SJack F Vogel {
22714edd8523SJack F Vogel 	u32 vt_ctl = E1000_READ_REG(hw, E1000_VT_CTL);
22724edd8523SJack F Vogel 
22734edd8523SJack F Vogel 	if (enable)
22744edd8523SJack F Vogel 		vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
22754edd8523SJack F Vogel 	else
22764edd8523SJack F Vogel 		vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
22774edd8523SJack F Vogel 
22784edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_VT_CTL, vt_ctl);
22794edd8523SJack F Vogel }
22804edd8523SJack F Vogel 
22814edd8523SJack F Vogel /**
22824edd8523SJack F Vogel  *  e1000_read_phy_reg_82580 - Read 82580 MDI control register
22834edd8523SJack F Vogel  *  @hw: pointer to the HW structure
22844edd8523SJack F Vogel  *  @offset: register offset to be read
22854edd8523SJack F Vogel  *  @data: pointer to the read data
22864edd8523SJack F Vogel  *
22874edd8523SJack F Vogel  *  Reads the MDI control register in the PHY at offset and stores the
22884edd8523SJack F Vogel  *  information read to data.
22894edd8523SJack F Vogel  **/
22904edd8523SJack F Vogel static s32 e1000_read_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 *data)
22914edd8523SJack F Vogel {
22924edd8523SJack F Vogel 	s32 ret_val;
22934edd8523SJack F Vogel 
22944edd8523SJack F Vogel 	DEBUGFUNC("e1000_read_phy_reg_82580");
22954edd8523SJack F Vogel 
22964edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
22974edd8523SJack F Vogel 	if (ret_val)
22984edd8523SJack F Vogel 		goto out;
22994edd8523SJack F Vogel 
23004edd8523SJack F Vogel 	ret_val = e1000_read_phy_reg_mdic(hw, offset, data);
23014edd8523SJack F Vogel 
23024edd8523SJack F Vogel 	hw->phy.ops.release(hw);
23034edd8523SJack F Vogel 
23044edd8523SJack F Vogel out:
23054edd8523SJack F Vogel 	return ret_val;
23064edd8523SJack F Vogel }
23074edd8523SJack F Vogel 
23084edd8523SJack F Vogel /**
23094edd8523SJack F Vogel  *  e1000_write_phy_reg_82580 - Write 82580 MDI control register
23104edd8523SJack F Vogel  *  @hw: pointer to the HW structure
23114edd8523SJack F Vogel  *  @offset: register offset to write to
23124edd8523SJack F Vogel  *  @data: data to write to register at offset
23134edd8523SJack F Vogel  *
23144edd8523SJack F Vogel  *  Writes data to MDI control register in the PHY at offset.
23154edd8523SJack F Vogel  **/
23164edd8523SJack F Vogel static s32 e1000_write_phy_reg_82580(struct e1000_hw *hw, u32 offset, u16 data)
23174edd8523SJack F Vogel {
23184edd8523SJack F Vogel 	s32 ret_val;
23194edd8523SJack F Vogel 
23204edd8523SJack F Vogel 	DEBUGFUNC("e1000_write_phy_reg_82580");
23214edd8523SJack F Vogel 
23224edd8523SJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
23234edd8523SJack F Vogel 	if (ret_val)
23244edd8523SJack F Vogel 		goto out;
23254edd8523SJack F Vogel 
23264edd8523SJack F Vogel 	ret_val = e1000_write_phy_reg_mdic(hw, offset, data);
23274edd8523SJack F Vogel 
23284edd8523SJack F Vogel 	hw->phy.ops.release(hw);
23294edd8523SJack F Vogel 
23304edd8523SJack F Vogel out:
23314edd8523SJack F Vogel 	return ret_val;
23324edd8523SJack F Vogel }
2333a69ed8dfSJack F Vogel 
23344edd8523SJack F Vogel /**
23357d9119bdSJack F Vogel  *  e1000_reset_mdicnfg_82580 - Reset MDICNFG destination and com_mdio bits
23367d9119bdSJack F Vogel  *  @hw: pointer to the HW structure
23377d9119bdSJack F Vogel  *
2338cef367e6SEitan Adler  *  This resets the MDICNFG.Destination and MDICNFG.Com_MDIO bits based on
23397d9119bdSJack F Vogel  *  the values found in the EEPROM.  This addresses an issue in which these
23407d9119bdSJack F Vogel  *  bits are not restored from EEPROM after reset.
23417d9119bdSJack F Vogel  **/
23427d9119bdSJack F Vogel static s32 e1000_reset_mdicnfg_82580(struct e1000_hw *hw)
23437d9119bdSJack F Vogel {
23447d9119bdSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23457d9119bdSJack F Vogel 	u32 mdicnfg;
2346f0ecc46dSJack F Vogel 	u16 nvm_data = 0;
23477d9119bdSJack F Vogel 
23487d9119bdSJack F Vogel 	DEBUGFUNC("e1000_reset_mdicnfg_82580");
23497d9119bdSJack F Vogel 
23507d9119bdSJack F Vogel 	if (hw->mac.type != e1000_82580)
23517d9119bdSJack F Vogel 		goto out;
23527d9119bdSJack F Vogel 	if (!e1000_sgmii_active_82575(hw))
23537d9119bdSJack F Vogel 		goto out;
23547d9119bdSJack F Vogel 
23557d9119bdSJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A +
23567d9119bdSJack F Vogel 				   NVM_82580_LAN_FUNC_OFFSET(hw->bus.func), 1,
23577d9119bdSJack F Vogel 				   &nvm_data);
23587d9119bdSJack F Vogel 	if (ret_val) {
23597d9119bdSJack F Vogel 		DEBUGOUT("NVM Read Error\n");
23607d9119bdSJack F Vogel 		goto out;
23617d9119bdSJack F Vogel 	}
23627d9119bdSJack F Vogel 
23637d9119bdSJack F Vogel 	mdicnfg = E1000_READ_REG(hw, E1000_MDICNFG);
23647d9119bdSJack F Vogel 	if (nvm_data & NVM_WORD24_EXT_MDIO)
23657d9119bdSJack F Vogel 		mdicnfg |= E1000_MDICNFG_EXT_MDIO;
23667d9119bdSJack F Vogel 	if (nvm_data & NVM_WORD24_COM_MDIO)
23677d9119bdSJack F Vogel 		mdicnfg |= E1000_MDICNFG_COM_MDIO;
23687d9119bdSJack F Vogel 	E1000_WRITE_REG(hw, E1000_MDICNFG, mdicnfg);
23697d9119bdSJack F Vogel out:
23707d9119bdSJack F Vogel 	return ret_val;
23717d9119bdSJack F Vogel }
23727d9119bdSJack F Vogel 
23737d9119bdSJack F Vogel /**
23744edd8523SJack F Vogel  *  e1000_reset_hw_82580 - Reset hardware
23754edd8523SJack F Vogel  *  @hw: pointer to the HW structure
23764edd8523SJack F Vogel  *
23774edd8523SJack F Vogel  *  This resets function or entire device (all ports, etc.)
23784edd8523SJack F Vogel  *  to a known state.
23794edd8523SJack F Vogel  **/
23804edd8523SJack F Vogel static s32 e1000_reset_hw_82580(struct e1000_hw *hw)
23814edd8523SJack F Vogel {
23824edd8523SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
23834edd8523SJack F Vogel 	/* BH SW mailbox bit in SW_FW_SYNC */
23844edd8523SJack F Vogel 	u16 swmbsw_mask = E1000_SW_SYNCH_MB;
2385f0ecc46dSJack F Vogel 	u32 ctrl;
23864edd8523SJack F Vogel 	bool global_device_reset = hw->dev_spec._82575.global_device_reset;
23874edd8523SJack F Vogel 
23884edd8523SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_82580");
23894edd8523SJack F Vogel 
23904edd8523SJack F Vogel 	hw->dev_spec._82575.global_device_reset = FALSE;
23914edd8523SJack F Vogel 
23926ab6bfe3SJack F Vogel 	/* 82580 does not reliably do global_device_reset due to hw errata */
23936ab6bfe3SJack F Vogel 	if (hw->mac.type == e1000_82580)
23946ab6bfe3SJack F Vogel 		global_device_reset = FALSE;
23956ab6bfe3SJack F Vogel 
23964edd8523SJack F Vogel 	/* Get current control state. */
23974edd8523SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
23984edd8523SJack F Vogel 
23994edd8523SJack F Vogel 	/*
24004edd8523SJack F Vogel 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
24014edd8523SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
24024edd8523SJack F Vogel 	 */
24034edd8523SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
24044edd8523SJack F Vogel 	if (ret_val)
24054edd8523SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
24064edd8523SJack F Vogel 
24074edd8523SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
24084edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
24094edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
24104edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
24114edd8523SJack F Vogel 	E1000_WRITE_FLUSH(hw);
24124edd8523SJack F Vogel 
24134edd8523SJack F Vogel 	msec_delay(10);
24144edd8523SJack F Vogel 
24154edd8523SJack F Vogel 	/* Determine whether or not a global dev reset is requested */
2416ab5d0362SJack F Vogel 	if (global_device_reset && hw->mac.ops.acquire_swfw_sync(hw,
24174dab5c37SJack F Vogel 	    swmbsw_mask))
24184edd8523SJack F Vogel 			global_device_reset = FALSE;
24194edd8523SJack F Vogel 
24204dab5c37SJack F Vogel 	if (global_device_reset && !(E1000_READ_REG(hw, E1000_STATUS) &
24214dab5c37SJack F Vogel 	    E1000_STAT_DEV_RST_SET))
24224edd8523SJack F Vogel 		ctrl |= E1000_CTRL_DEV_RST;
24234edd8523SJack F Vogel 	else
24244edd8523SJack F Vogel 		ctrl |= E1000_CTRL_RST;
24254edd8523SJack F Vogel 
24264edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
24274edd8523SJack F Vogel 
24288cc64f1eSJack F Vogel 	switch (hw->device_id) {
24298cc64f1eSJack F Vogel 	case E1000_DEV_ID_DH89XXCC_SGMII:
24308cc64f1eSJack F Vogel 		break;
24318cc64f1eSJack F Vogel 	default:
24328cc64f1eSJack F Vogel 		E1000_WRITE_FLUSH(hw);
24338cc64f1eSJack F Vogel 		break;
24348cc64f1eSJack F Vogel 	}
24358cc64f1eSJack F Vogel 
24368cc64f1eSJack F Vogel 	/* Add delay to insure DEV_RST or RST has time to complete */
24374edd8523SJack F Vogel 	msec_delay(5);
24384edd8523SJack F Vogel 
24394edd8523SJack F Vogel 	ret_val = e1000_get_auto_rd_done_generic(hw);
24404edd8523SJack F Vogel 	if (ret_val) {
24414edd8523SJack F Vogel 		/*
24424edd8523SJack F Vogel 		 * When auto config read does not complete, do not
24434edd8523SJack F Vogel 		 * return with an error. This can happen in situations
24444edd8523SJack F Vogel 		 * where there is no eeprom and prevents getting link.
24454edd8523SJack F Vogel 		 */
24464edd8523SJack F Vogel 		DEBUGOUT("Auto Read Done did not complete\n");
24474edd8523SJack F Vogel 	}
24484edd8523SJack F Vogel 
24494edd8523SJack F Vogel 	/* clear global device reset status bit */
24504edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, E1000_STAT_DEV_RST_SET);
24514edd8523SJack F Vogel 
24524edd8523SJack F Vogel 	/* Clear any pending interrupt events. */
24534edd8523SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
2454f0ecc46dSJack F Vogel 	E1000_READ_REG(hw, E1000_ICR);
24554edd8523SJack F Vogel 
24567d9119bdSJack F Vogel 	ret_val = e1000_reset_mdicnfg_82580(hw);
24577d9119bdSJack F Vogel 	if (ret_val)
24587d9119bdSJack F Vogel 		DEBUGOUT("Could not reset MDICNFG based on EEPROM\n");
24597d9119bdSJack F Vogel 
24604edd8523SJack F Vogel 	/* Install any alternate MAC address into RAR0 */
24614edd8523SJack F Vogel 	ret_val = e1000_check_alt_mac_addr_generic(hw);
24624edd8523SJack F Vogel 
24634edd8523SJack F Vogel 	/* Release semaphore */
24644edd8523SJack F Vogel 	if (global_device_reset)
2465ab5d0362SJack F Vogel 		hw->mac.ops.release_swfw_sync(hw, swmbsw_mask);
24664edd8523SJack F Vogel 
24674edd8523SJack F Vogel 	return ret_val;
24684edd8523SJack F Vogel }
24694edd8523SJack F Vogel 
24704edd8523SJack F Vogel /**
2471f0ecc46dSJack F Vogel  *  e1000_rxpbs_adjust_82580 - adjust RXPBS value to reflect actual Rx PBA size
24724edd8523SJack F Vogel  *  @data: data received by reading RXPBS register
24734edd8523SJack F Vogel  *
24744edd8523SJack F Vogel  *  The 82580 uses a table based approach for packet buffer allocation sizes.
24754edd8523SJack F Vogel  *  This function converts the retrieved value into the correct table value
24764edd8523SJack F Vogel  *     0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7
24774edd8523SJack F Vogel  *  0x0 36  72 144   1   2   4   8  16
24784edd8523SJack F Vogel  *  0x8 35  70 140 rsv rsv rsv rsv rsv
24794edd8523SJack F Vogel  */
24804edd8523SJack F Vogel u16 e1000_rxpbs_adjust_82580(u32 data)
24814edd8523SJack F Vogel {
24824edd8523SJack F Vogel 	u16 ret_val = 0;
24834edd8523SJack F Vogel 
24844edd8523SJack F Vogel 	if (data < E1000_82580_RXPBS_TABLE_SIZE)
24854edd8523SJack F Vogel 		ret_val = e1000_82580_rxpbs_table[data];
24864edd8523SJack F Vogel 
24874edd8523SJack F Vogel 	return ret_val;
24884edd8523SJack F Vogel }
2489f0ecc46dSJack F Vogel 
2490f0ecc46dSJack F Vogel /**
2491f0ecc46dSJack F Vogel  *  e1000_validate_nvm_checksum_with_offset - Validate EEPROM
2492f0ecc46dSJack F Vogel  *  checksum
2493f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2494f0ecc46dSJack F Vogel  *  @offset: offset in words of the checksum protected region
2495f0ecc46dSJack F Vogel  *
2496f0ecc46dSJack F Vogel  *  Calculates the EEPROM checksum by reading/adding each word of the EEPROM
2497f0ecc46dSJack F Vogel  *  and then verifies that the sum of the EEPROM is equal to 0xBABA.
2498f0ecc46dSJack F Vogel  **/
2499f0ecc46dSJack F Vogel s32 e1000_validate_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
2500f0ecc46dSJack F Vogel {
2501f0ecc46dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2502f0ecc46dSJack F Vogel 	u16 checksum = 0;
2503f0ecc46dSJack F Vogel 	u16 i, nvm_data;
2504f0ecc46dSJack F Vogel 
2505f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_with_offset");
2506f0ecc46dSJack F Vogel 
2507f0ecc46dSJack F Vogel 	for (i = offset; i < ((NVM_CHECKSUM_REG + offset) + 1); i++) {
2508f0ecc46dSJack F Vogel 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
2509f0ecc46dSJack F Vogel 		if (ret_val) {
2510f0ecc46dSJack F Vogel 			DEBUGOUT("NVM Read Error\n");
2511f0ecc46dSJack F Vogel 			goto out;
2512f0ecc46dSJack F Vogel 		}
2513f0ecc46dSJack F Vogel 		checksum += nvm_data;
2514f0ecc46dSJack F Vogel 	}
2515f0ecc46dSJack F Vogel 
2516f0ecc46dSJack F Vogel 	if (checksum != (u16) NVM_SUM) {
2517f0ecc46dSJack F Vogel 		DEBUGOUT("NVM Checksum Invalid\n");
2518f0ecc46dSJack F Vogel 		ret_val = -E1000_ERR_NVM;
2519f0ecc46dSJack F Vogel 		goto out;
2520f0ecc46dSJack F Vogel 	}
2521f0ecc46dSJack F Vogel 
2522f0ecc46dSJack F Vogel out:
2523f0ecc46dSJack F Vogel 	return ret_val;
2524f0ecc46dSJack F Vogel }
2525f0ecc46dSJack F Vogel 
2526f0ecc46dSJack F Vogel /**
2527f0ecc46dSJack F Vogel  *  e1000_update_nvm_checksum_with_offset - Update EEPROM
2528f0ecc46dSJack F Vogel  *  checksum
2529f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2530f0ecc46dSJack F Vogel  *  @offset: offset in words of the checksum protected region
2531f0ecc46dSJack F Vogel  *
2532f0ecc46dSJack F Vogel  *  Updates the EEPROM checksum by reading/adding each word of the EEPROM
2533f0ecc46dSJack F Vogel  *  up to the checksum.  Then calculates the EEPROM checksum and writes the
2534f0ecc46dSJack F Vogel  *  value to the EEPROM.
2535f0ecc46dSJack F Vogel  **/
2536f0ecc46dSJack F Vogel s32 e1000_update_nvm_checksum_with_offset(struct e1000_hw *hw, u16 offset)
2537f0ecc46dSJack F Vogel {
2538f0ecc46dSJack F Vogel 	s32 ret_val;
2539f0ecc46dSJack F Vogel 	u16 checksum = 0;
2540f0ecc46dSJack F Vogel 	u16 i, nvm_data;
2541f0ecc46dSJack F Vogel 
2542f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_with_offset");
2543f0ecc46dSJack F Vogel 
2544f0ecc46dSJack F Vogel 	for (i = offset; i < (NVM_CHECKSUM_REG + offset); i++) {
2545f0ecc46dSJack F Vogel 		ret_val = hw->nvm.ops.read(hw, i, 1, &nvm_data);
2546f0ecc46dSJack F Vogel 		if (ret_val) {
2547f0ecc46dSJack F Vogel 			DEBUGOUT("NVM Read Error while updating checksum.\n");
2548f0ecc46dSJack F Vogel 			goto out;
2549f0ecc46dSJack F Vogel 		}
2550f0ecc46dSJack F Vogel 		checksum += nvm_data;
2551f0ecc46dSJack F Vogel 	}
2552f0ecc46dSJack F Vogel 	checksum = (u16) NVM_SUM - checksum;
2553f0ecc46dSJack F Vogel 	ret_val = hw->nvm.ops.write(hw, (NVM_CHECKSUM_REG + offset), 1,
2554f0ecc46dSJack F Vogel 				    &checksum);
2555f0ecc46dSJack F Vogel 	if (ret_val)
2556f0ecc46dSJack F Vogel 		DEBUGOUT("NVM Write Error while updating checksum.\n");
2557f0ecc46dSJack F Vogel 
2558f0ecc46dSJack F Vogel out:
2559f0ecc46dSJack F Vogel 	return ret_val;
2560f0ecc46dSJack F Vogel }
2561f0ecc46dSJack F Vogel 
2562f0ecc46dSJack F Vogel /**
2563f0ecc46dSJack F Vogel  *  e1000_validate_nvm_checksum_82580 - Validate EEPROM checksum
2564f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2565f0ecc46dSJack F Vogel  *
2566f0ecc46dSJack F Vogel  *  Calculates the EEPROM section checksum by reading/adding each word of
2567f0ecc46dSJack F Vogel  *  the EEPROM and then verifies that the sum of the EEPROM is
2568f0ecc46dSJack F Vogel  *  equal to 0xBABA.
2569f0ecc46dSJack F Vogel  **/
2570f0ecc46dSJack F Vogel static s32 e1000_validate_nvm_checksum_82580(struct e1000_hw *hw)
2571f0ecc46dSJack F Vogel {
25728cc64f1eSJack F Vogel 	s32 ret_val;
2573f0ecc46dSJack F Vogel 	u16 eeprom_regions_count = 1;
2574f0ecc46dSJack F Vogel 	u16 j, nvm_data;
2575f0ecc46dSJack F Vogel 	u16 nvm_offset;
2576f0ecc46dSJack F Vogel 
2577f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_82580");
2578f0ecc46dSJack F Vogel 
2579f0ecc46dSJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_COMPATIBILITY_REG_3, 1, &nvm_data);
2580f0ecc46dSJack F Vogel 	if (ret_val) {
2581f0ecc46dSJack F Vogel 		DEBUGOUT("NVM Read Error\n");
2582f0ecc46dSJack F Vogel 		goto out;
2583f0ecc46dSJack F Vogel 	}
2584f0ecc46dSJack F Vogel 
2585f0ecc46dSJack F Vogel 	if (nvm_data & NVM_COMPATIBILITY_BIT_MASK) {
2586f0ecc46dSJack F Vogel 		/* if chekcsums compatibility bit is set validate checksums
2587f0ecc46dSJack F Vogel 		 * for all 4 ports. */
2588f0ecc46dSJack F Vogel 		eeprom_regions_count = 4;
2589f0ecc46dSJack F Vogel 	}
2590f0ecc46dSJack F Vogel 
2591f0ecc46dSJack F Vogel 	for (j = 0; j < eeprom_regions_count; j++) {
2592f0ecc46dSJack F Vogel 		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
2593f0ecc46dSJack F Vogel 		ret_val = e1000_validate_nvm_checksum_with_offset(hw,
2594f0ecc46dSJack F Vogel 								  nvm_offset);
2595f0ecc46dSJack F Vogel 		if (ret_val != E1000_SUCCESS)
2596f0ecc46dSJack F Vogel 			goto out;
2597f0ecc46dSJack F Vogel 	}
2598f0ecc46dSJack F Vogel 
2599f0ecc46dSJack F Vogel out:
2600f0ecc46dSJack F Vogel 	return ret_val;
2601f0ecc46dSJack F Vogel }
2602f0ecc46dSJack F Vogel 
2603f0ecc46dSJack F Vogel /**
2604f0ecc46dSJack F Vogel  *  e1000_update_nvm_checksum_82580 - Update EEPROM checksum
2605f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2606f0ecc46dSJack F Vogel  *
2607f0ecc46dSJack F Vogel  *  Updates the EEPROM section checksums for all 4 ports by reading/adding
2608f0ecc46dSJack F Vogel  *  each word of the EEPROM up to the checksum.  Then calculates the EEPROM
2609f0ecc46dSJack F Vogel  *  checksum and writes the value to the EEPROM.
2610f0ecc46dSJack F Vogel  **/
2611f0ecc46dSJack F Vogel static s32 e1000_update_nvm_checksum_82580(struct e1000_hw *hw)
2612f0ecc46dSJack F Vogel {
2613f0ecc46dSJack F Vogel 	s32 ret_val;
2614f0ecc46dSJack F Vogel 	u16 j, nvm_data;
2615f0ecc46dSJack F Vogel 	u16 nvm_offset;
2616f0ecc46dSJack F Vogel 
2617f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_82580");
2618f0ecc46dSJack F Vogel 
2619f0ecc46dSJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_COMPATIBILITY_REG_3, 1, &nvm_data);
2620f0ecc46dSJack F Vogel 	if (ret_val) {
26214dab5c37SJack F Vogel 		DEBUGOUT("NVM Read Error while updating checksum compatibility bit.\n");
2622f0ecc46dSJack F Vogel 		goto out;
2623f0ecc46dSJack F Vogel 	}
2624f0ecc46dSJack F Vogel 
2625ab5d0362SJack F Vogel 	if (!(nvm_data & NVM_COMPATIBILITY_BIT_MASK)) {
2626f0ecc46dSJack F Vogel 		/* set compatibility bit to validate checksums appropriately */
2627f0ecc46dSJack F Vogel 		nvm_data = nvm_data | NVM_COMPATIBILITY_BIT_MASK;
2628f0ecc46dSJack F Vogel 		ret_val = hw->nvm.ops.write(hw, NVM_COMPATIBILITY_REG_3, 1,
2629f0ecc46dSJack F Vogel 					    &nvm_data);
2630f0ecc46dSJack F Vogel 		if (ret_val) {
26314dab5c37SJack F Vogel 			DEBUGOUT("NVM Write Error while updating checksum compatibility bit.\n");
2632f0ecc46dSJack F Vogel 			goto out;
2633f0ecc46dSJack F Vogel 		}
2634f0ecc46dSJack F Vogel 	}
2635f0ecc46dSJack F Vogel 
2636f0ecc46dSJack F Vogel 	for (j = 0; j < 4; j++) {
2637f0ecc46dSJack F Vogel 		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
2638f0ecc46dSJack F Vogel 		ret_val = e1000_update_nvm_checksum_with_offset(hw, nvm_offset);
26394dab5c37SJack F Vogel 		if (ret_val)
2640f0ecc46dSJack F Vogel 			goto out;
2641f0ecc46dSJack F Vogel 	}
2642f0ecc46dSJack F Vogel 
2643f0ecc46dSJack F Vogel out:
2644f0ecc46dSJack F Vogel 	return ret_val;
2645f0ecc46dSJack F Vogel }
2646f0ecc46dSJack F Vogel 
2647f0ecc46dSJack F Vogel /**
2648f0ecc46dSJack F Vogel  *  e1000_validate_nvm_checksum_i350 - Validate EEPROM checksum
2649f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2650f0ecc46dSJack F Vogel  *
2651f0ecc46dSJack F Vogel  *  Calculates the EEPROM section checksum by reading/adding each word of
2652f0ecc46dSJack F Vogel  *  the EEPROM and then verifies that the sum of the EEPROM is
2653f0ecc46dSJack F Vogel  *  equal to 0xBABA.
2654f0ecc46dSJack F Vogel  **/
2655f0ecc46dSJack F Vogel static s32 e1000_validate_nvm_checksum_i350(struct e1000_hw *hw)
2656f0ecc46dSJack F Vogel {
2657f0ecc46dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2658f0ecc46dSJack F Vogel 	u16 j;
2659f0ecc46dSJack F Vogel 	u16 nvm_offset;
2660f0ecc46dSJack F Vogel 
2661f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_i350");
2662f0ecc46dSJack F Vogel 
2663f0ecc46dSJack F Vogel 	for (j = 0; j < 4; j++) {
2664f0ecc46dSJack F Vogel 		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
2665f0ecc46dSJack F Vogel 		ret_val = e1000_validate_nvm_checksum_with_offset(hw,
2666f0ecc46dSJack F Vogel 								  nvm_offset);
2667f0ecc46dSJack F Vogel 		if (ret_val != E1000_SUCCESS)
2668f0ecc46dSJack F Vogel 			goto out;
2669f0ecc46dSJack F Vogel 	}
2670f0ecc46dSJack F Vogel 
2671f0ecc46dSJack F Vogel out:
2672f0ecc46dSJack F Vogel 	return ret_val;
2673f0ecc46dSJack F Vogel }
2674f0ecc46dSJack F Vogel 
2675f0ecc46dSJack F Vogel /**
2676f0ecc46dSJack F Vogel  *  e1000_update_nvm_checksum_i350 - Update EEPROM checksum
2677f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2678f0ecc46dSJack F Vogel  *
2679f0ecc46dSJack F Vogel  *  Updates the EEPROM section checksums for all 4 ports by reading/adding
2680f0ecc46dSJack F Vogel  *  each word of the EEPROM up to the checksum.  Then calculates the EEPROM
2681f0ecc46dSJack F Vogel  *  checksum and writes the value to the EEPROM.
2682f0ecc46dSJack F Vogel  **/
2683f0ecc46dSJack F Vogel static s32 e1000_update_nvm_checksum_i350(struct e1000_hw *hw)
2684f0ecc46dSJack F Vogel {
2685f0ecc46dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2686f0ecc46dSJack F Vogel 	u16 j;
2687f0ecc46dSJack F Vogel 	u16 nvm_offset;
2688f0ecc46dSJack F Vogel 
2689f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_i350");
2690f0ecc46dSJack F Vogel 
2691f0ecc46dSJack F Vogel 	for (j = 0; j < 4; j++) {
2692f0ecc46dSJack F Vogel 		nvm_offset = NVM_82580_LAN_FUNC_OFFSET(j);
2693f0ecc46dSJack F Vogel 		ret_val = e1000_update_nvm_checksum_with_offset(hw, nvm_offset);
2694f0ecc46dSJack F Vogel 		if (ret_val != E1000_SUCCESS)
2695f0ecc46dSJack F Vogel 			goto out;
2696f0ecc46dSJack F Vogel 	}
2697f0ecc46dSJack F Vogel 
2698f0ecc46dSJack F Vogel out:
2699f0ecc46dSJack F Vogel 	return ret_val;
2700f0ecc46dSJack F Vogel }
2701f0ecc46dSJack F Vogel 
2702f0ecc46dSJack F Vogel /**
27037609433eSJack F Vogel  *  __e1000_access_emi_reg - Read/write EMI register
27047609433eSJack F Vogel  *  @hw: pointer to the HW structure
2705*5b426b3eSGuinan Sun  *  @address: EMI address to program
27067609433eSJack F Vogel  *  @data: pointer to value to read/write from/to the EMI address
27077609433eSJack F Vogel  *  @read: boolean flag to indicate read or write
27087609433eSJack F Vogel  **/
27097609433eSJack F Vogel static s32 __e1000_access_emi_reg(struct e1000_hw *hw, u16 address,
27107609433eSJack F Vogel 				  u16 *data, bool read)
27117609433eSJack F Vogel {
27128cc64f1eSJack F Vogel 	s32 ret_val;
27137609433eSJack F Vogel 
27147609433eSJack F Vogel 	DEBUGFUNC("__e1000_access_emi_reg");
27157609433eSJack F Vogel 
27167609433eSJack F Vogel 	ret_val = hw->phy.ops.write_reg(hw, E1000_EMIADD, address);
27177609433eSJack F Vogel 	if (ret_val)
27187609433eSJack F Vogel 		return ret_val;
27197609433eSJack F Vogel 
27207609433eSJack F Vogel 	if (read)
27217609433eSJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, E1000_EMIDATA, data);
27227609433eSJack F Vogel 	else
27237609433eSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, E1000_EMIDATA, *data);
27247609433eSJack F Vogel 
27257609433eSJack F Vogel 	return ret_val;
27267609433eSJack F Vogel }
27277609433eSJack F Vogel 
27287609433eSJack F Vogel /**
27297609433eSJack F Vogel  *  e1000_read_emi_reg - Read Extended Management Interface register
27307609433eSJack F Vogel  *  @hw: pointer to the HW structure
27317609433eSJack F Vogel  *  @addr: EMI address to program
27327609433eSJack F Vogel  *  @data: value to be read from the EMI address
27337609433eSJack F Vogel  **/
27347609433eSJack F Vogel s32 e1000_read_emi_reg(struct e1000_hw *hw, u16 addr, u16 *data)
27357609433eSJack F Vogel {
27367609433eSJack F Vogel 	DEBUGFUNC("e1000_read_emi_reg");
27377609433eSJack F Vogel 
27387609433eSJack F Vogel 	return __e1000_access_emi_reg(hw, addr, data, TRUE);
27397609433eSJack F Vogel }
27407609433eSJack F Vogel 
27417609433eSJack F Vogel /**
27428cc64f1eSJack F Vogel  *  e1000_initialize_M88E1512_phy - Initialize M88E1512 PHY
27438cc64f1eSJack F Vogel  *  @hw: pointer to the HW structure
27448cc64f1eSJack F Vogel  *
2745c80429ceSEric Joyner  *  Initialize Marvell 1512 to work correctly with Avoton.
27468cc64f1eSJack F Vogel  **/
27478cc64f1eSJack F Vogel s32 e1000_initialize_M88E1512_phy(struct e1000_hw *hw)
27488cc64f1eSJack F Vogel {
27498cc64f1eSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
27508cc64f1eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
27518cc64f1eSJack F Vogel 
27528cc64f1eSJack F Vogel 	DEBUGFUNC("e1000_initialize_M88E1512_phy");
27538cc64f1eSJack F Vogel 
27548cc64f1eSJack F Vogel 	/* Check if this is correct PHY. */
27558cc64f1eSJack F Vogel 	if (phy->id != M88E1512_E_PHY_ID)
27568cc64f1eSJack F Vogel 		goto out;
27578cc64f1eSJack F Vogel 
27588cc64f1eSJack F Vogel 	/* Switch to PHY page 0xFF. */
27598cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FF);
27608cc64f1eSJack F Vogel 	if (ret_val)
27618cc64f1eSJack F Vogel 		goto out;
27628cc64f1eSJack F Vogel 
27638cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x214B);
27648cc64f1eSJack F Vogel 	if (ret_val)
27658cc64f1eSJack F Vogel 		goto out;
27668cc64f1eSJack F Vogel 
27678cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2144);
27688cc64f1eSJack F Vogel 	if (ret_val)
27698cc64f1eSJack F Vogel 		goto out;
27708cc64f1eSJack F Vogel 
27718cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x0C28);
27728cc64f1eSJack F Vogel 	if (ret_val)
27738cc64f1eSJack F Vogel 		goto out;
27748cc64f1eSJack F Vogel 
27758cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2146);
27768cc64f1eSJack F Vogel 	if (ret_val)
27778cc64f1eSJack F Vogel 		goto out;
27788cc64f1eSJack F Vogel 
27798cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xB233);
27808cc64f1eSJack F Vogel 	if (ret_val)
27818cc64f1eSJack F Vogel 		goto out;
27828cc64f1eSJack F Vogel 
27838cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x214D);
27848cc64f1eSJack F Vogel 	if (ret_val)
27858cc64f1eSJack F Vogel 		goto out;
27868cc64f1eSJack F Vogel 
27878cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xCC0C);
27888cc64f1eSJack F Vogel 	if (ret_val)
27898cc64f1eSJack F Vogel 		goto out;
27908cc64f1eSJack F Vogel 
27918cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2159);
27928cc64f1eSJack F Vogel 	if (ret_val)
27938cc64f1eSJack F Vogel 		goto out;
27948cc64f1eSJack F Vogel 
27958cc64f1eSJack F Vogel 	/* Switch to PHY page 0xFB. */
27968cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FB);
27978cc64f1eSJack F Vogel 	if (ret_val)
27988cc64f1eSJack F Vogel 		goto out;
27998cc64f1eSJack F Vogel 
28008cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_3, 0x000D);
28018cc64f1eSJack F Vogel 	if (ret_val)
28028cc64f1eSJack F Vogel 		goto out;
28038cc64f1eSJack F Vogel 
28048cc64f1eSJack F Vogel 	/* Switch to PHY page 0x12. */
28058cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x12);
28068cc64f1eSJack F Vogel 	if (ret_val)
28078cc64f1eSJack F Vogel 		goto out;
28088cc64f1eSJack F Vogel 
28098cc64f1eSJack F Vogel 	/* Change mode to SGMII-to-Copper */
28108cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_MODE, 0x8001);
28118cc64f1eSJack F Vogel 	if (ret_val)
28128cc64f1eSJack F Vogel 		goto out;
28138cc64f1eSJack F Vogel 
28148cc64f1eSJack F Vogel 	/* Return the PHY to page 0. */
28158cc64f1eSJack F Vogel 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
28168cc64f1eSJack F Vogel 	if (ret_val)
28178cc64f1eSJack F Vogel 		goto out;
28188cc64f1eSJack F Vogel 
28198cc64f1eSJack F Vogel 	ret_val = phy->ops.commit(hw);
28208cc64f1eSJack F Vogel 	if (ret_val) {
28218cc64f1eSJack F Vogel 		DEBUGOUT("Error committing the PHY changes\n");
28228cc64f1eSJack F Vogel 		return ret_val;
28238cc64f1eSJack F Vogel 	}
28248cc64f1eSJack F Vogel 
28258cc64f1eSJack F Vogel 	msec_delay(1000);
28268cc64f1eSJack F Vogel out:
28278cc64f1eSJack F Vogel 	return ret_val;
28288cc64f1eSJack F Vogel }
28298cc64f1eSJack F Vogel 
28308cc64f1eSJack F Vogel /**
2831c80429ceSEric Joyner  *  e1000_initialize_M88E1543_phy - Initialize M88E1543 PHY
2832c80429ceSEric Joyner  *  @hw: pointer to the HW structure
2833c80429ceSEric Joyner  *
2834c80429ceSEric Joyner  *  Initialize Marvell 1543 to work correctly with Avoton.
2835c80429ceSEric Joyner  **/
2836c80429ceSEric Joyner s32 e1000_initialize_M88E1543_phy(struct e1000_hw *hw)
2837c80429ceSEric Joyner {
2838c80429ceSEric Joyner 	struct e1000_phy_info *phy = &hw->phy;
2839c80429ceSEric Joyner 	s32 ret_val = E1000_SUCCESS;
2840c80429ceSEric Joyner 
2841c80429ceSEric Joyner 	DEBUGFUNC("e1000_initialize_M88E1543_phy");
2842c80429ceSEric Joyner 
2843c80429ceSEric Joyner 	/* Check if this is correct PHY. */
2844c80429ceSEric Joyner 	if (phy->id != M88E1543_E_PHY_ID)
2845c80429ceSEric Joyner 		goto out;
2846c80429ceSEric Joyner 
2847c80429ceSEric Joyner 	/* Switch to PHY page 0xFF. */
2848c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FF);
2849c80429ceSEric Joyner 	if (ret_val)
2850c80429ceSEric Joyner 		goto out;
2851c80429ceSEric Joyner 
2852c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x214B);
2853c80429ceSEric Joyner 	if (ret_val)
2854c80429ceSEric Joyner 		goto out;
2855c80429ceSEric Joyner 
2856c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2144);
2857c80429ceSEric Joyner 	if (ret_val)
2858c80429ceSEric Joyner 		goto out;
2859c80429ceSEric Joyner 
2860c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0x0C28);
2861c80429ceSEric Joyner 	if (ret_val)
2862c80429ceSEric Joyner 		goto out;
2863c80429ceSEric Joyner 
2864c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2146);
2865c80429ceSEric Joyner 	if (ret_val)
2866c80429ceSEric Joyner 		goto out;
2867c80429ceSEric Joyner 
2868c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xB233);
2869c80429ceSEric Joyner 	if (ret_val)
2870c80429ceSEric Joyner 		goto out;
2871c80429ceSEric Joyner 
2872c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x214D);
2873c80429ceSEric Joyner 	if (ret_val)
2874c80429ceSEric Joyner 		goto out;
2875c80429ceSEric Joyner 
2876c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_2, 0xDC0C);
2877c80429ceSEric Joyner 	if (ret_val)
2878c80429ceSEric Joyner 		goto out;
2879c80429ceSEric Joyner 
2880c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_1, 0x2159);
2881c80429ceSEric Joyner 	if (ret_val)
2882c80429ceSEric Joyner 		goto out;
2883c80429ceSEric Joyner 
2884c80429ceSEric Joyner 	/* Switch to PHY page 0xFB. */
2885c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x00FB);
2886c80429ceSEric Joyner 	if (ret_val)
2887c80429ceSEric Joyner 		goto out;
2888c80429ceSEric Joyner 
2889c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_CFG_REG_3, 0xC00D);
2890c80429ceSEric Joyner 	if (ret_val)
2891c80429ceSEric Joyner 		goto out;
2892c80429ceSEric Joyner 
2893c80429ceSEric Joyner 	/* Switch to PHY page 0x12. */
2894c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x12);
2895c80429ceSEric Joyner 	if (ret_val)
2896c80429ceSEric Joyner 		goto out;
2897c80429ceSEric Joyner 
2898c80429ceSEric Joyner 	/* Change mode to SGMII-to-Copper */
2899c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1512_MODE, 0x8001);
2900c80429ceSEric Joyner 	if (ret_val)
2901c80429ceSEric Joyner 		goto out;
2902c80429ceSEric Joyner 
2903c80429ceSEric Joyner 	/* Switch to PHY page 1. */
2904c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0x1);
2905c80429ceSEric Joyner 	if (ret_val)
2906c80429ceSEric Joyner 		goto out;
2907c80429ceSEric Joyner 
2908c80429ceSEric Joyner 	/* Change mode to 1000BASE-X/SGMII and autoneg enable; reset */
2909c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_FIBER_CTRL, 0x9140);
2910c80429ceSEric Joyner 	if (ret_val)
2911c80429ceSEric Joyner 		goto out;
2912c80429ceSEric Joyner 
2913c80429ceSEric Joyner 	/* Return the PHY to page 0. */
2914c80429ceSEric Joyner 	ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
2915c80429ceSEric Joyner 	if (ret_val)
2916c80429ceSEric Joyner 		goto out;
2917c80429ceSEric Joyner 
2918c80429ceSEric Joyner 	ret_val = phy->ops.commit(hw);
2919c80429ceSEric Joyner 	if (ret_val) {
2920c80429ceSEric Joyner 		DEBUGOUT("Error committing the PHY changes\n");
2921c80429ceSEric Joyner 		return ret_val;
2922c80429ceSEric Joyner 	}
2923c80429ceSEric Joyner 
2924c80429ceSEric Joyner 	msec_delay(1000);
2925c80429ceSEric Joyner out:
2926c80429ceSEric Joyner 	return ret_val;
2927c80429ceSEric Joyner }
2928c80429ceSEric Joyner 
2929c80429ceSEric Joyner /**
2930f0ecc46dSJack F Vogel  *  e1000_set_eee_i350 - Enable/disable EEE support
2931f0ecc46dSJack F Vogel  *  @hw: pointer to the HW structure
2932*5b426b3eSGuinan Sun  *  @adv1G: boolean flag enabling 1G EEE advertisement
2933*5b426b3eSGuinan Sun  *  @adv100M: boolean flag enabling 100M EEE advertisement
2934f0ecc46dSJack F Vogel  *
2935f0ecc46dSJack F Vogel  *  Enable/disable EEE based on setting in dev_spec structure.
2936f0ecc46dSJack F Vogel  *
2937f0ecc46dSJack F Vogel  **/
2938c80429ceSEric Joyner s32 e1000_set_eee_i350(struct e1000_hw *hw, bool adv1G, bool adv100M)
2939f0ecc46dSJack F Vogel {
29404dab5c37SJack F Vogel 	u32 ipcnfg, eeer;
2941f0ecc46dSJack F Vogel 
2942f0ecc46dSJack F Vogel 	DEBUGFUNC("e1000_set_eee_i350");
2943f0ecc46dSJack F Vogel 
29444dab5c37SJack F Vogel 	if ((hw->mac.type < e1000_i350) ||
29454dab5c37SJack F Vogel 	    (hw->phy.media_type != e1000_media_type_copper))
2946f0ecc46dSJack F Vogel 		goto out;
2947f0ecc46dSJack F Vogel 	ipcnfg = E1000_READ_REG(hw, E1000_IPCNFG);
2948f0ecc46dSJack F Vogel 	eeer = E1000_READ_REG(hw, E1000_EEER);
2949f0ecc46dSJack F Vogel 
2950f0ecc46dSJack F Vogel 	/* enable or disable per user setting */
2951f0ecc46dSJack F Vogel 	if (!(hw->dev_spec._82575.eee_disable)) {
29526ab6bfe3SJack F Vogel 		u32 eee_su = E1000_READ_REG(hw, E1000_EEE_SU);
29536ab6bfe3SJack F Vogel 
2954c80429ceSEric Joyner 		if (adv100M)
2955c80429ceSEric Joyner 			ipcnfg |= E1000_IPCNFG_EEE_100M_AN;
2956c80429ceSEric Joyner 		else
2957c80429ceSEric Joyner 			ipcnfg &= ~E1000_IPCNFG_EEE_100M_AN;
2958c80429ceSEric Joyner 
2959c80429ceSEric Joyner 		if (adv1G)
2960c80429ceSEric Joyner 			ipcnfg |= E1000_IPCNFG_EEE_1G_AN;
2961c80429ceSEric Joyner 		else
2962c80429ceSEric Joyner 			ipcnfg &= ~E1000_IPCNFG_EEE_1G_AN;
2963c80429ceSEric Joyner 
29644dab5c37SJack F Vogel 		eeer |= (E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
2965f0ecc46dSJack F Vogel 			 E1000_EEER_LPI_FC);
2966f0ecc46dSJack F Vogel 
29676ab6bfe3SJack F Vogel 		/* This bit should not be set in normal operation. */
29686ab6bfe3SJack F Vogel 		if (eee_su & E1000_EEE_SU_LPI_CLK_STP)
29696ab6bfe3SJack F Vogel 			DEBUGOUT("LPI Clock Stop Bit should not be set!\n");
2970f0ecc46dSJack F Vogel 	} else {
29714dab5c37SJack F Vogel 		ipcnfg &= ~(E1000_IPCNFG_EEE_1G_AN | E1000_IPCNFG_EEE_100M_AN);
29724dab5c37SJack F Vogel 		eeer &= ~(E1000_EEER_TX_LPI_EN | E1000_EEER_RX_LPI_EN |
2973f0ecc46dSJack F Vogel 			  E1000_EEER_LPI_FC);
2974f0ecc46dSJack F Vogel 	}
2975f0ecc46dSJack F Vogel 	E1000_WRITE_REG(hw, E1000_IPCNFG, ipcnfg);
2976f0ecc46dSJack F Vogel 	E1000_WRITE_REG(hw, E1000_EEER, eeer);
2977f0ecc46dSJack F Vogel 	E1000_READ_REG(hw, E1000_IPCNFG);
2978f0ecc46dSJack F Vogel 	E1000_READ_REG(hw, E1000_EEER);
2979f0ecc46dSJack F Vogel out:
2980f0ecc46dSJack F Vogel 
29818cc64f1eSJack F Vogel 	return E1000_SUCCESS;
2982f0ecc46dSJack F Vogel }
29834dab5c37SJack F Vogel 
29847609433eSJack F Vogel /**
29857609433eSJack F Vogel  *  e1000_set_eee_i354 - Enable/disable EEE support
29867609433eSJack F Vogel  *  @hw: pointer to the HW structure
2987*5b426b3eSGuinan Sun  *  @adv1G: boolean flag enabling 1G EEE advertisement
2988*5b426b3eSGuinan Sun  *  @adv100M: boolean flag enabling 100M EEE advertisement
29897609433eSJack F Vogel  *
29907609433eSJack F Vogel  *  Enable/disable EEE legacy mode based on setting in dev_spec structure.
29917609433eSJack F Vogel  *
29927609433eSJack F Vogel  **/
2993c80429ceSEric Joyner s32 e1000_set_eee_i354(struct e1000_hw *hw, bool adv1G, bool adv100M)
29947609433eSJack F Vogel {
29957609433eSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
29967609433eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
29977609433eSJack F Vogel 	u16 phy_data;
29987609433eSJack F Vogel 
29997609433eSJack F Vogel 	DEBUGFUNC("e1000_set_eee_i354");
30007609433eSJack F Vogel 
30017609433eSJack F Vogel 	if ((hw->phy.media_type != e1000_media_type_copper) ||
30027609433eSJack F Vogel 	    ((phy->id != M88E1543_E_PHY_ID) &&
30037609433eSJack F Vogel 	    (phy->id != M88E1512_E_PHY_ID)))
30047609433eSJack F Vogel 		goto out;
30057609433eSJack F Vogel 
30067609433eSJack F Vogel 	if (!hw->dev_spec._82575.eee_disable) {
30077609433eSJack F Vogel 		/* Switch to PHY page 18. */
30087609433eSJack F Vogel 		ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 18);
30097609433eSJack F Vogel 		if (ret_val)
30107609433eSJack F Vogel 			goto out;
30117609433eSJack F Vogel 
30127609433eSJack F Vogel 		ret_val = phy->ops.read_reg(hw, E1000_M88E1543_EEE_CTRL_1,
30137609433eSJack F Vogel 					    &phy_data);
30147609433eSJack F Vogel 		if (ret_val)
30157609433eSJack F Vogel 			goto out;
30167609433eSJack F Vogel 
30177609433eSJack F Vogel 		phy_data |= E1000_M88E1543_EEE_CTRL_1_MS;
30187609433eSJack F Vogel 		ret_val = phy->ops.write_reg(hw, E1000_M88E1543_EEE_CTRL_1,
30197609433eSJack F Vogel 					     phy_data);
30207609433eSJack F Vogel 		if (ret_val)
30217609433eSJack F Vogel 			goto out;
30227609433eSJack F Vogel 
30237609433eSJack F Vogel 		/* Return the PHY to page 0. */
30247609433eSJack F Vogel 		ret_val = phy->ops.write_reg(hw, E1000_M88E1543_PAGE_ADDR, 0);
30257609433eSJack F Vogel 		if (ret_val)
30267609433eSJack F Vogel 			goto out;
30277609433eSJack F Vogel 
30287609433eSJack F Vogel 		/* Turn on EEE advertisement. */
30297609433eSJack F Vogel 		ret_val = e1000_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
30307609433eSJack F Vogel 					       E1000_EEE_ADV_DEV_I354,
30317609433eSJack F Vogel 					       &phy_data);
30327609433eSJack F Vogel 		if (ret_val)
30337609433eSJack F Vogel 			goto out;
30347609433eSJack F Vogel 
3035c80429ceSEric Joyner 		if (adv100M)
3036c80429ceSEric Joyner 			phy_data |= E1000_EEE_ADV_100_SUPPORTED;
3037c80429ceSEric Joyner 		else
3038c80429ceSEric Joyner 			phy_data &= ~E1000_EEE_ADV_100_SUPPORTED;
3039c80429ceSEric Joyner 
3040c80429ceSEric Joyner 		if (adv1G)
3041c80429ceSEric Joyner 			phy_data |= E1000_EEE_ADV_1000_SUPPORTED;
3042c80429ceSEric Joyner 		else
3043c80429ceSEric Joyner 			phy_data &= ~E1000_EEE_ADV_1000_SUPPORTED;
3044c80429ceSEric Joyner 
30457609433eSJack F Vogel 		ret_val = e1000_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
30467609433eSJack F Vogel 						E1000_EEE_ADV_DEV_I354,
30477609433eSJack F Vogel 						phy_data);
30487609433eSJack F Vogel 	} else {
30497609433eSJack F Vogel 		/* Turn off EEE advertisement. */
30507609433eSJack F Vogel 		ret_val = e1000_read_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
30517609433eSJack F Vogel 					       E1000_EEE_ADV_DEV_I354,
30527609433eSJack F Vogel 					       &phy_data);
30537609433eSJack F Vogel 		if (ret_val)
30547609433eSJack F Vogel 			goto out;
30557609433eSJack F Vogel 
30567609433eSJack F Vogel 		phy_data &= ~(E1000_EEE_ADV_100_SUPPORTED |
30577609433eSJack F Vogel 			      E1000_EEE_ADV_1000_SUPPORTED);
30587609433eSJack F Vogel 		ret_val = e1000_write_xmdio_reg(hw, E1000_EEE_ADV_ADDR_I354,
30597609433eSJack F Vogel 						E1000_EEE_ADV_DEV_I354,
30607609433eSJack F Vogel 						phy_data);
30617609433eSJack F Vogel 	}
30627609433eSJack F Vogel 
30637609433eSJack F Vogel out:
30647609433eSJack F Vogel 	return ret_val;
30657609433eSJack F Vogel }
30667609433eSJack F Vogel 
30677609433eSJack F Vogel /**
30687609433eSJack F Vogel  *  e1000_get_eee_status_i354 - Get EEE status
30697609433eSJack F Vogel  *  @hw: pointer to the HW structure
30707609433eSJack F Vogel  *  @status: EEE status
30717609433eSJack F Vogel  *
30727609433eSJack F Vogel  *  Get EEE status by guessing based on whether Tx or Rx LPI indications have
30737609433eSJack F Vogel  *  been received.
30747609433eSJack F Vogel  **/
30757609433eSJack F Vogel s32 e1000_get_eee_status_i354(struct e1000_hw *hw, bool *status)
30767609433eSJack F Vogel {
30777609433eSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
30787609433eSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30797609433eSJack F Vogel 	u16 phy_data;
30807609433eSJack F Vogel 
30817609433eSJack F Vogel 	DEBUGFUNC("e1000_get_eee_status_i354");
30827609433eSJack F Vogel 
30837609433eSJack F Vogel 	/* Check if EEE is supported on this device. */
30847609433eSJack F Vogel 	if ((hw->phy.media_type != e1000_media_type_copper) ||
30857609433eSJack F Vogel 	    ((phy->id != M88E1543_E_PHY_ID) &&
30867609433eSJack F Vogel 	    (phy->id != M88E1512_E_PHY_ID)))
30877609433eSJack F Vogel 		goto out;
30887609433eSJack F Vogel 
30897609433eSJack F Vogel 	ret_val = e1000_read_xmdio_reg(hw, E1000_PCS_STATUS_ADDR_I354,
30907609433eSJack F Vogel 				       E1000_PCS_STATUS_DEV_I354,
30917609433eSJack F Vogel 				       &phy_data);
30927609433eSJack F Vogel 	if (ret_val)
30937609433eSJack F Vogel 		goto out;
30947609433eSJack F Vogel 
30957609433eSJack F Vogel 	*status = phy_data & (E1000_PCS_STATUS_TX_LPI_RCVD |
30967609433eSJack F Vogel 			      E1000_PCS_STATUS_RX_LPI_RCVD) ? TRUE : FALSE;
30977609433eSJack F Vogel 
30987609433eSJack F Vogel out:
30997609433eSJack F Vogel 	return ret_val;
31007609433eSJack F Vogel }
31017609433eSJack F Vogel 
31024dab5c37SJack F Vogel /* Due to a hw errata, if the host tries to  configure the VFTA register
31034dab5c37SJack F Vogel  * while performing queries from the BMC or DMA, then the VFTA in some
31044dab5c37SJack F Vogel  * cases won't be written.
31054dab5c37SJack F Vogel  */
31064dab5c37SJack F Vogel 
31074dab5c37SJack F Vogel /**
31084dab5c37SJack F Vogel  *  e1000_clear_vfta_i350 - Clear VLAN filter table
31094dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
31104dab5c37SJack F Vogel  *
31114dab5c37SJack F Vogel  *  Clears the register array which contains the VLAN filter table by
31124dab5c37SJack F Vogel  *  setting all the values to 0.
31134dab5c37SJack F Vogel  **/
31144dab5c37SJack F Vogel void e1000_clear_vfta_i350(struct e1000_hw *hw)
31154dab5c37SJack F Vogel {
31164dab5c37SJack F Vogel 	u32 offset;
31174dab5c37SJack F Vogel 	int i;
31184dab5c37SJack F Vogel 
31194dab5c37SJack F Vogel 	DEBUGFUNC("e1000_clear_vfta_350");
31204dab5c37SJack F Vogel 
31214dab5c37SJack F Vogel 	for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
31224dab5c37SJack F Vogel 		for (i = 0; i < 10; i++)
31234dab5c37SJack F Vogel 			E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, 0);
31244dab5c37SJack F Vogel 
31254dab5c37SJack F Vogel 		E1000_WRITE_FLUSH(hw);
31264dab5c37SJack F Vogel 	}
31274dab5c37SJack F Vogel }
31284dab5c37SJack F Vogel 
31294dab5c37SJack F Vogel /**
31304dab5c37SJack F Vogel  *  e1000_write_vfta_i350 - Write value to VLAN filter table
31314dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
31324dab5c37SJack F Vogel  *  @offset: register offset in VLAN filter table
31334dab5c37SJack F Vogel  *  @value: register value written to VLAN filter table
31344dab5c37SJack F Vogel  *
31354dab5c37SJack F Vogel  *  Writes value at the given offset in the register array which stores
31364dab5c37SJack F Vogel  *  the VLAN filter table.
31374dab5c37SJack F Vogel  **/
31384dab5c37SJack F Vogel void e1000_write_vfta_i350(struct e1000_hw *hw, u32 offset, u32 value)
31394dab5c37SJack F Vogel {
31404dab5c37SJack F Vogel 	int i;
31414dab5c37SJack F Vogel 
31424dab5c37SJack F Vogel 	DEBUGFUNC("e1000_write_vfta_350");
31434dab5c37SJack F Vogel 
31444dab5c37SJack F Vogel 	for (i = 0; i < 10; i++)
31454dab5c37SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_VFTA, offset, value);
31464dab5c37SJack F Vogel 
31474dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
31484dab5c37SJack F Vogel }
31494dab5c37SJack F Vogel 
31504dab5c37SJack F Vogel 
31514dab5c37SJack F Vogel /**
31524dab5c37SJack F Vogel  *  e1000_set_i2c_bb - Enable I2C bit-bang
31534dab5c37SJack F Vogel  *  @hw: pointer to the HW structure
31544dab5c37SJack F Vogel  *
31554dab5c37SJack F Vogel  *  Enable I2C bit-bang interface
31564dab5c37SJack F Vogel  *
31574dab5c37SJack F Vogel  **/
31584dab5c37SJack F Vogel s32 e1000_set_i2c_bb(struct e1000_hw *hw)
31594dab5c37SJack F Vogel {
31604dab5c37SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
31614dab5c37SJack F Vogel 	u32 ctrl_ext, i2cparams;
31624dab5c37SJack F Vogel 
31634dab5c37SJack F Vogel 	DEBUGFUNC("e1000_set_i2c_bb");
31644dab5c37SJack F Vogel 
31654dab5c37SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
31664dab5c37SJack F Vogel 	ctrl_ext |= E1000_CTRL_I2C_ENA;
31674dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
31684dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
31694dab5c37SJack F Vogel 
31704dab5c37SJack F Vogel 	i2cparams = E1000_READ_REG(hw, E1000_I2CPARAMS);
31714dab5c37SJack F Vogel 	i2cparams |= E1000_I2CBB_EN;
31724dab5c37SJack F Vogel 	i2cparams |= E1000_I2C_DATA_OE_N;
31734dab5c37SJack F Vogel 	i2cparams |= E1000_I2C_CLK_OE_N;
31744dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_I2CPARAMS, i2cparams);
31754dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
31764dab5c37SJack F Vogel 
31774dab5c37SJack F Vogel 	return ret_val;
31784dab5c37SJack F Vogel }
31794dab5c37SJack F Vogel 
31804dab5c37SJack F Vogel /**
31814dab5c37SJack F Vogel  *  e1000_read_i2c_byte_generic - Reads 8 bit word over I2C
31824dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
31834dab5c37SJack F Vogel  *  @byte_offset: byte offset to read
3184ab5d0362SJack F Vogel  *  @dev_addr: device address
31854dab5c37SJack F Vogel  *  @data: value read
31864dab5c37SJack F Vogel  *
31874dab5c37SJack F Vogel  *  Performs byte read operation over I2C interface at
31884dab5c37SJack F Vogel  *  a specified device address.
31894dab5c37SJack F Vogel  **/
31904dab5c37SJack F Vogel s32 e1000_read_i2c_byte_generic(struct e1000_hw *hw, u8 byte_offset,
31914dab5c37SJack F Vogel 				u8 dev_addr, u8 *data)
31924dab5c37SJack F Vogel {
31934dab5c37SJack F Vogel 	s32 status = E1000_SUCCESS;
31944dab5c37SJack F Vogel 	u32 max_retry = 10;
31954dab5c37SJack F Vogel 	u32 retry = 1;
31964dab5c37SJack F Vogel 	u16 swfw_mask = 0;
31974dab5c37SJack F Vogel 
3198ab5d0362SJack F Vogel 	bool nack = TRUE;
31994dab5c37SJack F Vogel 
32004dab5c37SJack F Vogel 	DEBUGFUNC("e1000_read_i2c_byte_generic");
32014dab5c37SJack F Vogel 
32024dab5c37SJack F Vogel 	swfw_mask = E1000_SWFW_PHY0_SM;
32034dab5c37SJack F Vogel 
32044dab5c37SJack F Vogel 	do {
3205ab5d0362SJack F Vogel 		if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask)
32064dab5c37SJack F Vogel 		    != E1000_SUCCESS) {
32074dab5c37SJack F Vogel 			status = E1000_ERR_SWFW_SYNC;
32084dab5c37SJack F Vogel 			goto read_byte_out;
32094dab5c37SJack F Vogel 		}
32104dab5c37SJack F Vogel 
32114dab5c37SJack F Vogel 		e1000_i2c_start(hw);
32124dab5c37SJack F Vogel 
32134dab5c37SJack F Vogel 		/* Device Address and write indication */
32144dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, dev_addr);
32154dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32164dab5c37SJack F Vogel 			goto fail;
32174dab5c37SJack F Vogel 
32184dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
32194dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32204dab5c37SJack F Vogel 			goto fail;
32214dab5c37SJack F Vogel 
32224dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, byte_offset);
32234dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32244dab5c37SJack F Vogel 			goto fail;
32254dab5c37SJack F Vogel 
32264dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
32274dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32284dab5c37SJack F Vogel 			goto fail;
32294dab5c37SJack F Vogel 
32304dab5c37SJack F Vogel 		e1000_i2c_start(hw);
32314dab5c37SJack F Vogel 
32324dab5c37SJack F Vogel 		/* Device Address and read indication */
32334dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, (dev_addr | 0x1));
32344dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32354dab5c37SJack F Vogel 			goto fail;
32364dab5c37SJack F Vogel 
32374dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
32384dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32394dab5c37SJack F Vogel 			goto fail;
32404dab5c37SJack F Vogel 
32414dab5c37SJack F Vogel 		status = e1000_clock_in_i2c_byte(hw, data);
32424dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32434dab5c37SJack F Vogel 			goto fail;
32444dab5c37SJack F Vogel 
32454dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_bit(hw, nack);
32464dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
32474dab5c37SJack F Vogel 			goto fail;
32484dab5c37SJack F Vogel 
32494dab5c37SJack F Vogel 		e1000_i2c_stop(hw);
32504dab5c37SJack F Vogel 		break;
32514dab5c37SJack F Vogel 
32524dab5c37SJack F Vogel fail:
3253ab5d0362SJack F Vogel 		hw->mac.ops.release_swfw_sync(hw, swfw_mask);
32544dab5c37SJack F Vogel 		msec_delay(100);
32554dab5c37SJack F Vogel 		e1000_i2c_bus_clear(hw);
32564dab5c37SJack F Vogel 		retry++;
32574dab5c37SJack F Vogel 		if (retry < max_retry)
32584dab5c37SJack F Vogel 			DEBUGOUT("I2C byte read error - Retrying.\n");
32594dab5c37SJack F Vogel 		else
32604dab5c37SJack F Vogel 			DEBUGOUT("I2C byte read error.\n");
32614dab5c37SJack F Vogel 
32624dab5c37SJack F Vogel 	} while (retry < max_retry);
32634dab5c37SJack F Vogel 
3264ab5d0362SJack F Vogel 	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
32654dab5c37SJack F Vogel 
32664dab5c37SJack F Vogel read_byte_out:
32674dab5c37SJack F Vogel 
32684dab5c37SJack F Vogel 	return status;
32694dab5c37SJack F Vogel }
32704dab5c37SJack F Vogel 
32714dab5c37SJack F Vogel /**
32724dab5c37SJack F Vogel  *  e1000_write_i2c_byte_generic - Writes 8 bit word over I2C
32734dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
32744dab5c37SJack F Vogel  *  @byte_offset: byte offset to write
3275ab5d0362SJack F Vogel  *  @dev_addr: device address
32764dab5c37SJack F Vogel  *  @data: value to write
32774dab5c37SJack F Vogel  *
32784dab5c37SJack F Vogel  *  Performs byte write operation over I2C interface at
32794dab5c37SJack F Vogel  *  a specified device address.
32804dab5c37SJack F Vogel  **/
32814dab5c37SJack F Vogel s32 e1000_write_i2c_byte_generic(struct e1000_hw *hw, u8 byte_offset,
32824dab5c37SJack F Vogel 				 u8 dev_addr, u8 data)
32834dab5c37SJack F Vogel {
32844dab5c37SJack F Vogel 	s32 status = E1000_SUCCESS;
32854dab5c37SJack F Vogel 	u32 max_retry = 1;
32864dab5c37SJack F Vogel 	u32 retry = 0;
32874dab5c37SJack F Vogel 	u16 swfw_mask = 0;
32884dab5c37SJack F Vogel 
32894dab5c37SJack F Vogel 	DEBUGFUNC("e1000_write_i2c_byte_generic");
32904dab5c37SJack F Vogel 
32914dab5c37SJack F Vogel 	swfw_mask = E1000_SWFW_PHY0_SM;
32924dab5c37SJack F Vogel 
3293ab5d0362SJack F Vogel 	if (hw->mac.ops.acquire_swfw_sync(hw, swfw_mask) != E1000_SUCCESS) {
32944dab5c37SJack F Vogel 		status = E1000_ERR_SWFW_SYNC;
32954dab5c37SJack F Vogel 		goto write_byte_out;
32964dab5c37SJack F Vogel 	}
32974dab5c37SJack F Vogel 
32984dab5c37SJack F Vogel 	do {
32994dab5c37SJack F Vogel 		e1000_i2c_start(hw);
33004dab5c37SJack F Vogel 
33014dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, dev_addr);
33024dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33034dab5c37SJack F Vogel 			goto fail;
33044dab5c37SJack F Vogel 
33054dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
33064dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33074dab5c37SJack F Vogel 			goto fail;
33084dab5c37SJack F Vogel 
33094dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, byte_offset);
33104dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33114dab5c37SJack F Vogel 			goto fail;
33124dab5c37SJack F Vogel 
33134dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
33144dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33154dab5c37SJack F Vogel 			goto fail;
33164dab5c37SJack F Vogel 
33174dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_byte(hw, data);
33184dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33194dab5c37SJack F Vogel 			goto fail;
33204dab5c37SJack F Vogel 
33214dab5c37SJack F Vogel 		status = e1000_get_i2c_ack(hw);
33224dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
33234dab5c37SJack F Vogel 			goto fail;
33244dab5c37SJack F Vogel 
33254dab5c37SJack F Vogel 		e1000_i2c_stop(hw);
33264dab5c37SJack F Vogel 		break;
33274dab5c37SJack F Vogel 
33284dab5c37SJack F Vogel fail:
33294dab5c37SJack F Vogel 		e1000_i2c_bus_clear(hw);
33304dab5c37SJack F Vogel 		retry++;
33314dab5c37SJack F Vogel 		if (retry < max_retry)
33324dab5c37SJack F Vogel 			DEBUGOUT("I2C byte write error - Retrying.\n");
33334dab5c37SJack F Vogel 		else
33344dab5c37SJack F Vogel 			DEBUGOUT("I2C byte write error.\n");
33354dab5c37SJack F Vogel 	} while (retry < max_retry);
33364dab5c37SJack F Vogel 
3337ab5d0362SJack F Vogel 	hw->mac.ops.release_swfw_sync(hw, swfw_mask);
33384dab5c37SJack F Vogel 
33394dab5c37SJack F Vogel write_byte_out:
33404dab5c37SJack F Vogel 
33414dab5c37SJack F Vogel 	return status;
33424dab5c37SJack F Vogel }
33434dab5c37SJack F Vogel 
33444dab5c37SJack F Vogel /**
33454dab5c37SJack F Vogel  *  e1000_i2c_start - Sets I2C start condition
33464dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
33474dab5c37SJack F Vogel  *
33484dab5c37SJack F Vogel  *  Sets I2C start condition (High -> Low on SDA while SCL is High)
33494dab5c37SJack F Vogel  **/
33504dab5c37SJack F Vogel static void e1000_i2c_start(struct e1000_hw *hw)
33514dab5c37SJack F Vogel {
33524dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
33534dab5c37SJack F Vogel 
33544dab5c37SJack F Vogel 	DEBUGFUNC("e1000_i2c_start");
33554dab5c37SJack F Vogel 
33564dab5c37SJack F Vogel 	/* Start condition must begin with data and clock high */
33574dab5c37SJack F Vogel 	e1000_set_i2c_data(hw, &i2cctl, 1);
33584dab5c37SJack F Vogel 	e1000_raise_i2c_clk(hw, &i2cctl);
33594dab5c37SJack F Vogel 
33604dab5c37SJack F Vogel 	/* Setup time for start condition (4.7us) */
33614dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_SU_STA);
33624dab5c37SJack F Vogel 
33634dab5c37SJack F Vogel 	e1000_set_i2c_data(hw, &i2cctl, 0);
33644dab5c37SJack F Vogel 
33654dab5c37SJack F Vogel 	/* Hold time for start condition (4us) */
33664dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_HD_STA);
33674dab5c37SJack F Vogel 
33684dab5c37SJack F Vogel 	e1000_lower_i2c_clk(hw, &i2cctl);
33694dab5c37SJack F Vogel 
33704dab5c37SJack F Vogel 	/* Minimum low period of clock is 4.7 us */
33714dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_LOW);
33724dab5c37SJack F Vogel 
33734dab5c37SJack F Vogel }
33744dab5c37SJack F Vogel 
33754dab5c37SJack F Vogel /**
33764dab5c37SJack F Vogel  *  e1000_i2c_stop - Sets I2C stop condition
33774dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
33784dab5c37SJack F Vogel  *
33794dab5c37SJack F Vogel  *  Sets I2C stop condition (Low -> High on SDA while SCL is High)
33804dab5c37SJack F Vogel  **/
33814dab5c37SJack F Vogel static void e1000_i2c_stop(struct e1000_hw *hw)
33824dab5c37SJack F Vogel {
33834dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
33844dab5c37SJack F Vogel 
33854dab5c37SJack F Vogel 	DEBUGFUNC("e1000_i2c_stop");
33864dab5c37SJack F Vogel 
33874dab5c37SJack F Vogel 	/* Stop condition must begin with data low and clock high */
33884dab5c37SJack F Vogel 	e1000_set_i2c_data(hw, &i2cctl, 0);
33894dab5c37SJack F Vogel 	e1000_raise_i2c_clk(hw, &i2cctl);
33904dab5c37SJack F Vogel 
33914dab5c37SJack F Vogel 	/* Setup time for stop condition (4us) */
33924dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_SU_STO);
33934dab5c37SJack F Vogel 
33944dab5c37SJack F Vogel 	e1000_set_i2c_data(hw, &i2cctl, 1);
33954dab5c37SJack F Vogel 
33964dab5c37SJack F Vogel 	/* bus free time between stop and start (4.7us)*/
33974dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_BUF);
33984dab5c37SJack F Vogel }
33994dab5c37SJack F Vogel 
34004dab5c37SJack F Vogel /**
34014dab5c37SJack F Vogel  *  e1000_clock_in_i2c_byte - Clocks in one byte via I2C
34024dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
34034dab5c37SJack F Vogel  *  @data: data byte to clock in
34044dab5c37SJack F Vogel  *
34054dab5c37SJack F Vogel  *  Clocks in one byte data via I2C data/clock
34064dab5c37SJack F Vogel  **/
34074dab5c37SJack F Vogel static s32 e1000_clock_in_i2c_byte(struct e1000_hw *hw, u8 *data)
34084dab5c37SJack F Vogel {
34094dab5c37SJack F Vogel 	s32 i;
34104dab5c37SJack F Vogel 	bool bit = 0;
34114dab5c37SJack F Vogel 
34124dab5c37SJack F Vogel 	DEBUGFUNC("e1000_clock_in_i2c_byte");
34134dab5c37SJack F Vogel 
34144dab5c37SJack F Vogel 	*data = 0;
34154dab5c37SJack F Vogel 	for (i = 7; i >= 0; i--) {
34164dab5c37SJack F Vogel 		e1000_clock_in_i2c_bit(hw, &bit);
34174dab5c37SJack F Vogel 		*data |= bit << i;
34184dab5c37SJack F Vogel 	}
34194dab5c37SJack F Vogel 
34204dab5c37SJack F Vogel 	return E1000_SUCCESS;
34214dab5c37SJack F Vogel }
34224dab5c37SJack F Vogel 
34234dab5c37SJack F Vogel /**
34244dab5c37SJack F Vogel  *  e1000_clock_out_i2c_byte - Clocks out one byte via I2C
34254dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
34264dab5c37SJack F Vogel  *  @data: data byte clocked out
34274dab5c37SJack F Vogel  *
34284dab5c37SJack F Vogel  *  Clocks out one byte data via I2C data/clock
34294dab5c37SJack F Vogel  **/
34304dab5c37SJack F Vogel static s32 e1000_clock_out_i2c_byte(struct e1000_hw *hw, u8 data)
34314dab5c37SJack F Vogel {
34324dab5c37SJack F Vogel 	s32 status = E1000_SUCCESS;
34334dab5c37SJack F Vogel 	s32 i;
34344dab5c37SJack F Vogel 	u32 i2cctl;
34354dab5c37SJack F Vogel 	bool bit = 0;
34364dab5c37SJack F Vogel 
34374dab5c37SJack F Vogel 	DEBUGFUNC("e1000_clock_out_i2c_byte");
34384dab5c37SJack F Vogel 
34394dab5c37SJack F Vogel 	for (i = 7; i >= 0; i--) {
34404dab5c37SJack F Vogel 		bit = (data >> i) & 0x1;
34414dab5c37SJack F Vogel 		status = e1000_clock_out_i2c_bit(hw, bit);
34424dab5c37SJack F Vogel 
34434dab5c37SJack F Vogel 		if (status != E1000_SUCCESS)
34444dab5c37SJack F Vogel 			break;
34454dab5c37SJack F Vogel 	}
34464dab5c37SJack F Vogel 
34474dab5c37SJack F Vogel 	/* Release SDA line (set high) */
34484dab5c37SJack F Vogel 	i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
34494dab5c37SJack F Vogel 
34504dab5c37SJack F Vogel 	i2cctl |= E1000_I2C_DATA_OE_N;
34514dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_I2CPARAMS, i2cctl);
34524dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
34534dab5c37SJack F Vogel 
34544dab5c37SJack F Vogel 	return status;
34554dab5c37SJack F Vogel }
34564dab5c37SJack F Vogel 
34574dab5c37SJack F Vogel /**
34584dab5c37SJack F Vogel  *  e1000_get_i2c_ack - Polls for I2C ACK
34594dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
34604dab5c37SJack F Vogel  *
34614dab5c37SJack F Vogel  *  Clocks in/out one bit via I2C data/clock
34624dab5c37SJack F Vogel  **/
34634dab5c37SJack F Vogel static s32 e1000_get_i2c_ack(struct e1000_hw *hw)
34644dab5c37SJack F Vogel {
34654dab5c37SJack F Vogel 	s32 status = E1000_SUCCESS;
34664dab5c37SJack F Vogel 	u32 i = 0;
34674dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
34684dab5c37SJack F Vogel 	u32 timeout = 10;
3469ab5d0362SJack F Vogel 	bool ack = TRUE;
34704dab5c37SJack F Vogel 
34714dab5c37SJack F Vogel 	DEBUGFUNC("e1000_get_i2c_ack");
34724dab5c37SJack F Vogel 
34734dab5c37SJack F Vogel 	e1000_raise_i2c_clk(hw, &i2cctl);
34744dab5c37SJack F Vogel 
34754dab5c37SJack F Vogel 	/* Minimum high period of clock is 4us */
34764dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_HIGH);
34774dab5c37SJack F Vogel 
34784dab5c37SJack F Vogel 	/* Wait until SCL returns high */
34794dab5c37SJack F Vogel 	for (i = 0; i < timeout; i++) {
34804dab5c37SJack F Vogel 		usec_delay(1);
34814dab5c37SJack F Vogel 		i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
34824dab5c37SJack F Vogel 		if (i2cctl & E1000_I2C_CLK_IN)
34834dab5c37SJack F Vogel 			break;
34844dab5c37SJack F Vogel 	}
34854dab5c37SJack F Vogel 	if (!(i2cctl & E1000_I2C_CLK_IN))
34864dab5c37SJack F Vogel 		return E1000_ERR_I2C;
34874dab5c37SJack F Vogel 
34884dab5c37SJack F Vogel 	ack = e1000_get_i2c_data(&i2cctl);
3489ab5d0362SJack F Vogel 	if (ack) {
34904dab5c37SJack F Vogel 		DEBUGOUT("I2C ack was not received.\n");
34914dab5c37SJack F Vogel 		status = E1000_ERR_I2C;
34924dab5c37SJack F Vogel 	}
34934dab5c37SJack F Vogel 
34944dab5c37SJack F Vogel 	e1000_lower_i2c_clk(hw, &i2cctl);
34954dab5c37SJack F Vogel 
34964dab5c37SJack F Vogel 	/* Minimum low period of clock is 4.7 us */
34974dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_LOW);
34984dab5c37SJack F Vogel 
34994dab5c37SJack F Vogel 	return status;
35004dab5c37SJack F Vogel }
35014dab5c37SJack F Vogel 
35024dab5c37SJack F Vogel /**
35034dab5c37SJack F Vogel  *  e1000_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
35044dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
35054dab5c37SJack F Vogel  *  @data: read data value
35064dab5c37SJack F Vogel  *
35074dab5c37SJack F Vogel  *  Clocks in one bit via I2C data/clock
35084dab5c37SJack F Vogel  **/
35094dab5c37SJack F Vogel static s32 e1000_clock_in_i2c_bit(struct e1000_hw *hw, bool *data)
35104dab5c37SJack F Vogel {
35114dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
35124dab5c37SJack F Vogel 
35134dab5c37SJack F Vogel 	DEBUGFUNC("e1000_clock_in_i2c_bit");
35144dab5c37SJack F Vogel 
35154dab5c37SJack F Vogel 	e1000_raise_i2c_clk(hw, &i2cctl);
35164dab5c37SJack F Vogel 
35174dab5c37SJack F Vogel 	/* Minimum high period of clock is 4us */
35184dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_HIGH);
35194dab5c37SJack F Vogel 
35204dab5c37SJack F Vogel 	i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
35214dab5c37SJack F Vogel 	*data = e1000_get_i2c_data(&i2cctl);
35224dab5c37SJack F Vogel 
35234dab5c37SJack F Vogel 	e1000_lower_i2c_clk(hw, &i2cctl);
35244dab5c37SJack F Vogel 
35254dab5c37SJack F Vogel 	/* Minimum low period of clock is 4.7 us */
35264dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_LOW);
35274dab5c37SJack F Vogel 
35284dab5c37SJack F Vogel 	return E1000_SUCCESS;
35294dab5c37SJack F Vogel }
35304dab5c37SJack F Vogel 
35314dab5c37SJack F Vogel /**
35324dab5c37SJack F Vogel  *  e1000_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
35334dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
35344dab5c37SJack F Vogel  *  @data: data value to write
35354dab5c37SJack F Vogel  *
35364dab5c37SJack F Vogel  *  Clocks out one bit via I2C data/clock
35374dab5c37SJack F Vogel  **/
35384dab5c37SJack F Vogel static s32 e1000_clock_out_i2c_bit(struct e1000_hw *hw, bool data)
35394dab5c37SJack F Vogel {
35404dab5c37SJack F Vogel 	s32 status;
35414dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
35424dab5c37SJack F Vogel 
35434dab5c37SJack F Vogel 	DEBUGFUNC("e1000_clock_out_i2c_bit");
35444dab5c37SJack F Vogel 
35454dab5c37SJack F Vogel 	status = e1000_set_i2c_data(hw, &i2cctl, data);
35464dab5c37SJack F Vogel 	if (status == E1000_SUCCESS) {
35474dab5c37SJack F Vogel 		e1000_raise_i2c_clk(hw, &i2cctl);
35484dab5c37SJack F Vogel 
35494dab5c37SJack F Vogel 		/* Minimum high period of clock is 4us */
35504dab5c37SJack F Vogel 		usec_delay(E1000_I2C_T_HIGH);
35514dab5c37SJack F Vogel 
35524dab5c37SJack F Vogel 		e1000_lower_i2c_clk(hw, &i2cctl);
35534dab5c37SJack F Vogel 
35544dab5c37SJack F Vogel 		/* Minimum low period of clock is 4.7 us.
35554dab5c37SJack F Vogel 		 * This also takes care of the data hold time.
35564dab5c37SJack F Vogel 		 */
35574dab5c37SJack F Vogel 		usec_delay(E1000_I2C_T_LOW);
35584dab5c37SJack F Vogel 	} else {
35594dab5c37SJack F Vogel 		status = E1000_ERR_I2C;
35604dab5c37SJack F Vogel 		DEBUGOUT1("I2C data was not set to %X\n", data);
35614dab5c37SJack F Vogel 	}
35624dab5c37SJack F Vogel 
35634dab5c37SJack F Vogel 	return status;
35644dab5c37SJack F Vogel }
35654dab5c37SJack F Vogel /**
35664dab5c37SJack F Vogel  *  e1000_raise_i2c_clk - Raises the I2C SCL clock
35674dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
35684dab5c37SJack F Vogel  *  @i2cctl: Current value of I2CCTL register
35694dab5c37SJack F Vogel  *
35704dab5c37SJack F Vogel  *  Raises the I2C clock line '0'->'1'
35714dab5c37SJack F Vogel  **/
35724dab5c37SJack F Vogel static void e1000_raise_i2c_clk(struct e1000_hw *hw, u32 *i2cctl)
35734dab5c37SJack F Vogel {
35744dab5c37SJack F Vogel 	DEBUGFUNC("e1000_raise_i2c_clk");
35754dab5c37SJack F Vogel 
35764dab5c37SJack F Vogel 	*i2cctl |= E1000_I2C_CLK_OUT;
35774dab5c37SJack F Vogel 	*i2cctl &= ~E1000_I2C_CLK_OE_N;
35784dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_I2CPARAMS, *i2cctl);
35794dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
35804dab5c37SJack F Vogel 
35814dab5c37SJack F Vogel 	/* SCL rise time (1000ns) */
35824dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_RISE);
35834dab5c37SJack F Vogel }
35844dab5c37SJack F Vogel 
35854dab5c37SJack F Vogel /**
35864dab5c37SJack F Vogel  *  e1000_lower_i2c_clk - Lowers the I2C SCL clock
35874dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
35884dab5c37SJack F Vogel  *  @i2cctl: Current value of I2CCTL register
35894dab5c37SJack F Vogel  *
35904dab5c37SJack F Vogel  *  Lowers the I2C clock line '1'->'0'
35914dab5c37SJack F Vogel  **/
35924dab5c37SJack F Vogel static void e1000_lower_i2c_clk(struct e1000_hw *hw, u32 *i2cctl)
35934dab5c37SJack F Vogel {
35944dab5c37SJack F Vogel 
35954dab5c37SJack F Vogel 	DEBUGFUNC("e1000_lower_i2c_clk");
35964dab5c37SJack F Vogel 
35974dab5c37SJack F Vogel 	*i2cctl &= ~E1000_I2C_CLK_OUT;
35984dab5c37SJack F Vogel 	*i2cctl &= ~E1000_I2C_CLK_OE_N;
35994dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_I2CPARAMS, *i2cctl);
36004dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
36014dab5c37SJack F Vogel 
36024dab5c37SJack F Vogel 	/* SCL fall time (300ns) */
36034dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_FALL);
36044dab5c37SJack F Vogel }
36054dab5c37SJack F Vogel 
36064dab5c37SJack F Vogel /**
36074dab5c37SJack F Vogel  *  e1000_set_i2c_data - Sets the I2C data bit
36084dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
36094dab5c37SJack F Vogel  *  @i2cctl: Current value of I2CCTL register
36104dab5c37SJack F Vogel  *  @data: I2C data value (0 or 1) to set
36114dab5c37SJack F Vogel  *
36124dab5c37SJack F Vogel  *  Sets the I2C data bit
36134dab5c37SJack F Vogel  **/
36144dab5c37SJack F Vogel static s32 e1000_set_i2c_data(struct e1000_hw *hw, u32 *i2cctl, bool data)
36154dab5c37SJack F Vogel {
36164dab5c37SJack F Vogel 	s32 status = E1000_SUCCESS;
36174dab5c37SJack F Vogel 
36184dab5c37SJack F Vogel 	DEBUGFUNC("e1000_set_i2c_data");
36194dab5c37SJack F Vogel 
36204dab5c37SJack F Vogel 	if (data)
36214dab5c37SJack F Vogel 		*i2cctl |= E1000_I2C_DATA_OUT;
36224dab5c37SJack F Vogel 	else
36234dab5c37SJack F Vogel 		*i2cctl &= ~E1000_I2C_DATA_OUT;
36244dab5c37SJack F Vogel 
36254dab5c37SJack F Vogel 	*i2cctl &= ~E1000_I2C_DATA_OE_N;
36264dab5c37SJack F Vogel 	*i2cctl |= E1000_I2C_CLK_OE_N;
36274dab5c37SJack F Vogel 	E1000_WRITE_REG(hw, E1000_I2CPARAMS, *i2cctl);
36284dab5c37SJack F Vogel 	E1000_WRITE_FLUSH(hw);
36294dab5c37SJack F Vogel 
36304dab5c37SJack F Vogel 	/* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
36314dab5c37SJack F Vogel 	usec_delay(E1000_I2C_T_RISE + E1000_I2C_T_FALL + E1000_I2C_T_SU_DATA);
36324dab5c37SJack F Vogel 
36334dab5c37SJack F Vogel 	*i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
36344dab5c37SJack F Vogel 	if (data != e1000_get_i2c_data(i2cctl)) {
36354dab5c37SJack F Vogel 		status = E1000_ERR_I2C;
36364dab5c37SJack F Vogel 		DEBUGOUT1("Error - I2C data was not set to %X.\n", data);
36374dab5c37SJack F Vogel 	}
36384dab5c37SJack F Vogel 
36394dab5c37SJack F Vogel 	return status;
36404dab5c37SJack F Vogel }
36414dab5c37SJack F Vogel 
36424dab5c37SJack F Vogel /**
36434dab5c37SJack F Vogel  *  e1000_get_i2c_data - Reads the I2C SDA data bit
36444dab5c37SJack F Vogel  *  @i2cctl: Current value of I2CCTL register
36454dab5c37SJack F Vogel  *
36464dab5c37SJack F Vogel  *  Returns the I2C data bit value
36474dab5c37SJack F Vogel  **/
36484dab5c37SJack F Vogel static bool e1000_get_i2c_data(u32 *i2cctl)
36494dab5c37SJack F Vogel {
36504dab5c37SJack F Vogel 	bool data;
36514dab5c37SJack F Vogel 
36524dab5c37SJack F Vogel 	DEBUGFUNC("e1000_get_i2c_data");
36534dab5c37SJack F Vogel 
36544dab5c37SJack F Vogel 	if (*i2cctl & E1000_I2C_DATA_IN)
36554dab5c37SJack F Vogel 		data = 1;
36564dab5c37SJack F Vogel 	else
36574dab5c37SJack F Vogel 		data = 0;
36584dab5c37SJack F Vogel 
36594dab5c37SJack F Vogel 	return data;
36604dab5c37SJack F Vogel }
36614dab5c37SJack F Vogel 
36624dab5c37SJack F Vogel /**
36634dab5c37SJack F Vogel  *  e1000_i2c_bus_clear - Clears the I2C bus
36644dab5c37SJack F Vogel  *  @hw: pointer to hardware structure
36654dab5c37SJack F Vogel  *
36664dab5c37SJack F Vogel  *  Clears the I2C bus by sending nine clock pulses.
36674dab5c37SJack F Vogel  *  Used when data line is stuck low.
36684dab5c37SJack F Vogel  **/
36694dab5c37SJack F Vogel void e1000_i2c_bus_clear(struct e1000_hw *hw)
36704dab5c37SJack F Vogel {
36714dab5c37SJack F Vogel 	u32 i2cctl = E1000_READ_REG(hw, E1000_I2CPARAMS);
36724dab5c37SJack F Vogel 	u32 i;
36734dab5c37SJack F Vogel 
36744dab5c37SJack F Vogel 	DEBUGFUNC("e1000_i2c_bus_clear");
36754dab5c37SJack F Vogel 
36764dab5c37SJack F Vogel 	e1000_i2c_start(hw);
36774dab5c37SJack F Vogel 
36784dab5c37SJack F Vogel 	e1000_set_i2c_data(hw, &i2cctl, 1);
36794dab5c37SJack F Vogel 
36804dab5c37SJack F Vogel 	for (i = 0; i < 9; i++) {
36814dab5c37SJack F Vogel 		e1000_raise_i2c_clk(hw, &i2cctl);
36824dab5c37SJack F Vogel 
36834dab5c37SJack F Vogel 		/* Min high period of clock is 4us */
36844dab5c37SJack F Vogel 		usec_delay(E1000_I2C_T_HIGH);
36854dab5c37SJack F Vogel 
36864dab5c37SJack F Vogel 		e1000_lower_i2c_clk(hw, &i2cctl);
36874dab5c37SJack F Vogel 
36884dab5c37SJack F Vogel 		/* Min low period of clock is 4.7us*/
36894dab5c37SJack F Vogel 		usec_delay(E1000_I2C_T_LOW);
36904dab5c37SJack F Vogel 	}
36914dab5c37SJack F Vogel 
36924dab5c37SJack F Vogel 	e1000_i2c_start(hw);
36934dab5c37SJack F Vogel 
36944dab5c37SJack F Vogel 	/* Put the i2c bus back to default state */
36954dab5c37SJack F Vogel 	e1000_i2c_stop(hw);
36964dab5c37SJack F Vogel }
36974dab5c37SJack F Vogel 
3698