xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000_82541.c (revision 11143:f855b68211a7)
14919Sxy150489 /*
24919Sxy150489  * This file is provided under a CDDLv1 license.  When using or
34919Sxy150489  * redistributing this file, you may do so under this license.
44919Sxy150489  * In redistributing this file this license must be included
54919Sxy150489  * and no other modification of this header file is permitted.
64919Sxy150489  *
74919Sxy150489  * CDDL LICENSE SUMMARY
84919Sxy150489  *
98479SChenlu.Chen@Sun.COM  * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
104919Sxy150489  *
114919Sxy150489  * The contents of this file are subject to the terms of Version
124919Sxy150489  * 1.0 of the Common Development and Distribution License (the "License").
134919Sxy150489  *
144919Sxy150489  * You should have received a copy of the License with this software.
154919Sxy150489  * You can obtain a copy of the License at
164919Sxy150489  *	http://www.opensolaris.org/os/licensing.
174919Sxy150489  * See the License for the specific language governing permissions
184919Sxy150489  * and limitations under the License.
194919Sxy150489  */
204919Sxy150489 
214919Sxy150489 /*
228479SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234919Sxy150489  * Use is subject to license terms of the CDDLv1.
244919Sxy150489  */
254919Sxy150489 
264919Sxy150489 /*
2711020SMin.Xu@Sun.COM  * IntelVersion: 1.68 v3-1-10-1_2009-9-18_Release14-6
284919Sxy150489  */
296735Scc210113 
304919Sxy150489 /*
318479SChenlu.Chen@Sun.COM  * 82541EI Gigabit Ethernet Controller
328479SChenlu.Chen@Sun.COM  * 82541ER Gigabit Ethernet Controller
338479SChenlu.Chen@Sun.COM  * 82541GI Gigabit Ethernet Controller
348479SChenlu.Chen@Sun.COM  * 82541PI Gigabit Ethernet Controller
358479SChenlu.Chen@Sun.COM  * 82547EI Gigabit Ethernet Controller
368479SChenlu.Chen@Sun.COM  * 82547GI Gigabit Ethernet Controller
374919Sxy150489  */
384919Sxy150489 
394919Sxy150489 #include "e1000_api.h"
404919Sxy150489 
414919Sxy150489 static s32 e1000_init_phy_params_82541(struct e1000_hw *hw);
424919Sxy150489 static s32 e1000_init_nvm_params_82541(struct e1000_hw *hw);
434919Sxy150489 static s32 e1000_init_mac_params_82541(struct e1000_hw *hw);
444919Sxy150489 static s32 e1000_reset_hw_82541(struct e1000_hw *hw);
454919Sxy150489 static s32 e1000_init_hw_82541(struct e1000_hw *hw);
464919Sxy150489 static s32 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed,
474919Sxy150489     u16 *duplex);
484919Sxy150489 static s32 e1000_phy_hw_reset_82541(struct e1000_hw *hw);
494919Sxy150489 static s32 e1000_setup_copper_link_82541(struct e1000_hw *hw);
504919Sxy150489 static s32 e1000_check_for_link_82541(struct e1000_hw *hw);
514919Sxy150489 static s32 e1000_get_cable_length_igp_82541(struct e1000_hw *hw);
524919Sxy150489 static s32 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw,
536735Scc210113     bool active);
544919Sxy150489 static s32 e1000_setup_led_82541(struct e1000_hw *hw);
554919Sxy150489 static s32 e1000_cleanup_led_82541(struct e1000_hw *hw);
564919Sxy150489 static void e1000_clear_hw_cntrs_82541(struct e1000_hw *hw);
574919Sxy150489 static s32 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
586735Scc210113     bool link_up);
594919Sxy150489 static s32 e1000_phy_init_script_82541(struct e1000_hw *hw);
606735Scc210113 static void e1000_power_down_phy_copper_82541(struct e1000_hw *hw);
614919Sxy150489 
624919Sxy150489 static const u16 e1000_igp_cable_length_table[] =
634919Sxy150489 {5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
644919Sxy150489 5, 10, 10, 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 25, 25, 25,
654919Sxy150489 25, 25, 25, 25, 30, 30, 30, 30, 40, 40, 40, 40, 40, 40, 40, 40,
664919Sxy150489 40, 50, 50, 50, 50, 50, 50, 50, 60, 60, 60, 60, 60, 60, 60, 60,
674919Sxy150489 60, 70, 70, 70, 70, 70, 70, 80, 80, 80, 80, 80, 80, 90, 90, 90,
684919Sxy150489 90, 90, 90, 90, 90, 90, 100, 100, 100, 100, 100, 100, 100, 100, 100, 100,
694919Sxy150489 100, 100, 100, 100, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
704919Sxy150489 110, 110, 110, 110, 110, 110, 120, 120, 120, 120, 120, 120, 120, 120, 120, 120};
714919Sxy150489 
724919Sxy150489 #define	IGP01E1000_AGC_LENGTH_TABLE_SIZE \
734919Sxy150489 	(sizeof (e1000_igp_cable_length_table) / \
744919Sxy150489 	sizeof (e1000_igp_cable_length_table[0]))
754919Sxy150489 
764919Sxy150489 /*
774919Sxy150489  * e1000_init_phy_params_82541 - Init PHY func ptrs.
784919Sxy150489  * @hw: pointer to the HW structure
794919Sxy150489  */
804919Sxy150489 static s32
e1000_init_phy_params_82541(struct e1000_hw * hw)814919Sxy150489 e1000_init_phy_params_82541(struct e1000_hw *hw)
824919Sxy150489 {
834919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
844919Sxy150489 	s32 ret_val = E1000_SUCCESS;
854919Sxy150489 
864919Sxy150489 	DEBUGFUNC("e1000_init_phy_params_82541");
874919Sxy150489 
884919Sxy150489 	phy->addr = 1;
894919Sxy150489 	phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
904919Sxy150489 	phy->reset_delay_us = 10000;
914919Sxy150489 	phy->type = e1000_phy_igp;
924919Sxy150489 
934919Sxy150489 	/* Function Pointers */
946735Scc210113 	phy->ops.check_polarity = e1000_check_polarity_igp;
956735Scc210113 	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_igp;
966735Scc210113 	phy->ops.get_cable_length = e1000_get_cable_length_igp_82541;
976735Scc210113 	phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
986735Scc210113 	phy->ops.get_info = e1000_get_phy_info_igp;
996735Scc210113 	phy->ops.read_reg = e1000_read_phy_reg_igp;
1006735Scc210113 	phy->ops.reset = e1000_phy_hw_reset_82541;
1016735Scc210113 	phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_82541;
1026735Scc210113 	phy->ops.write_reg = e1000_write_phy_reg_igp;
1036735Scc210113 	phy->ops.power_up = e1000_power_up_phy_copper;
1046735Scc210113 	phy->ops.power_down = e1000_power_down_phy_copper_82541;
1054919Sxy150489 
1064919Sxy150489 	ret_val = e1000_get_phy_id(hw);
1074919Sxy150489 	if (ret_val)
1084919Sxy150489 		goto out;
1094919Sxy150489 
1104919Sxy150489 	/* Verify phy id */
1114919Sxy150489 	if (phy->id != IGP01E1000_I_PHY_ID) {
1124919Sxy150489 		ret_val = -E1000_ERR_PHY;
1134919Sxy150489 		goto out;
1144919Sxy150489 	}
11510680SMin.Xu@Sun.COM 
1164919Sxy150489 out:
1174919Sxy150489 	return (ret_val);
1184919Sxy150489 }
1194919Sxy150489 
1204919Sxy150489 /*
1214919Sxy150489  * e1000_init_nvm_params_82541 - Init NVM func ptrs.
1224919Sxy150489  * @hw: pointer to the HW structure
1234919Sxy150489  */
1244919Sxy150489 static s32
e1000_init_nvm_params_82541(struct e1000_hw * hw)1254919Sxy150489 e1000_init_nvm_params_82541(struct e1000_hw *hw)
1264919Sxy150489 {
1274919Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
1284919Sxy150489 	s32 ret_val = E1000_SUCCESS;
1294919Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1304919Sxy150489 	u16 size;
1314919Sxy150489 
1324919Sxy150489 	DEBUGFUNC("e1000_init_nvm_params_82541");
1334919Sxy150489 
1344919Sxy150489 	switch (nvm->override) {
1354919Sxy150489 	case e1000_nvm_override_spi_large:
1364919Sxy150489 		nvm->type = e1000_nvm_eeprom_spi;
1374919Sxy150489 		eecd |= E1000_EECD_ADDR_BITS;
1384919Sxy150489 		break;
1394919Sxy150489 	case e1000_nvm_override_spi_small:
1404919Sxy150489 		nvm->type = e1000_nvm_eeprom_spi;
1414919Sxy150489 		eecd &= ~E1000_EECD_ADDR_BITS;
1424919Sxy150489 		break;
1434919Sxy150489 	case e1000_nvm_override_microwire_large:
1444919Sxy150489 		nvm->type = e1000_nvm_eeprom_microwire;
1454919Sxy150489 		eecd |= E1000_EECD_SIZE;
1464919Sxy150489 		break;
1474919Sxy150489 	case e1000_nvm_override_microwire_small:
1484919Sxy150489 		nvm->type = e1000_nvm_eeprom_microwire;
1494919Sxy150489 		eecd &= ~E1000_EECD_SIZE;
1504919Sxy150489 		break;
1514919Sxy150489 	default:
1524919Sxy150489 		nvm->type = eecd & E1000_EECD_TYPE
1534919Sxy150489 		    ? e1000_nvm_eeprom_spi
1544919Sxy150489 		    : e1000_nvm_eeprom_microwire;
1554919Sxy150489 		break;
1564919Sxy150489 	}
1574919Sxy150489 
1584919Sxy150489 	if (nvm->type == e1000_nvm_eeprom_spi) {
1594919Sxy150489 		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
1604919Sxy150489 		    ? 16 : 8;
1614919Sxy150489 		nvm->delay_usec = 1;
1624919Sxy150489 		nvm->opcode_bits = 8;
1634919Sxy150489 		nvm->page_size = (eecd & E1000_EECD_ADDR_BITS)
1644919Sxy150489 		    ? 32 : 8;
1654919Sxy150489 
1664919Sxy150489 		/* Function Pointers */
1676735Scc210113 		nvm->ops.acquire = e1000_acquire_nvm_generic;
1686735Scc210113 		nvm->ops.read = e1000_read_nvm_spi;
1696735Scc210113 		nvm->ops.release = e1000_release_nvm_generic;
1706735Scc210113 		nvm->ops.update = e1000_update_nvm_checksum_generic;
1716735Scc210113 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1726735Scc210113 		nvm->ops.validate = e1000_validate_nvm_checksum_generic;
1736735Scc210113 		nvm->ops.write = e1000_write_nvm_spi;
1744919Sxy150489 
1754919Sxy150489 		/*
1764919Sxy150489 		 * nvm->word_size must be discovered after the pointers
1774919Sxy150489 		 * are set so we can verify the size from the nvm image
1784919Sxy150489 		 * itself. Temporarily set it to a dummy value so the
1794919Sxy150489 		 * read will work.
1804919Sxy150489 		 */
1814919Sxy150489 		nvm->word_size = 64;
1826735Scc210113 		ret_val = nvm->ops.read(hw, NVM_CFG, 1, &size);
1834919Sxy150489 		if (ret_val)
1844919Sxy150489 			goto out;
1854919Sxy150489 		size = (size & NVM_SIZE_MASK) >> NVM_SIZE_SHIFT;
1864919Sxy150489 		/*
1874919Sxy150489 		 * if size != 0, it can be added to a constant and become
1884919Sxy150489 		 * the left-shift value to set the word_size.  Otherwise,
1894919Sxy150489 		 * word_size stays at 64.
1904919Sxy150489 		 */
1914919Sxy150489 		if (size) {
1924919Sxy150489 			size += NVM_WORD_SIZE_BASE_SHIFT_82541;
1934919Sxy150489 			nvm->word_size = 1 << size;
1944919Sxy150489 		}
1954919Sxy150489 	} else {
1964919Sxy150489 		nvm->address_bits = (eecd & E1000_EECD_ADDR_BITS)
1974919Sxy150489 		    ? 8 : 6;
1984919Sxy150489 		nvm->delay_usec = 50;
1994919Sxy150489 		nvm->opcode_bits = 3;
2004919Sxy150489 		nvm->word_size = (eecd & E1000_EECD_ADDR_BITS)
2014919Sxy150489 		    ? 256 : 64;
2024919Sxy150489 
2034919Sxy150489 		/* Function Pointers */
2046735Scc210113 		nvm->ops.acquire = e1000_acquire_nvm_generic;
2056735Scc210113 		nvm->ops.read = e1000_read_nvm_microwire;
2066735Scc210113 		nvm->ops.release = e1000_release_nvm_generic;
2076735Scc210113 		nvm->ops.update = e1000_update_nvm_checksum_generic;
2086735Scc210113 		nvm->ops.valid_led_default = e1000_valid_led_default_generic;
2096735Scc210113 		nvm->ops.validate = e1000_validate_nvm_checksum_generic;
2106735Scc210113 		nvm->ops.write = e1000_write_nvm_microwire;
2114919Sxy150489 	}
2124919Sxy150489 
2134919Sxy150489 out:
2144919Sxy150489 	return (ret_val);
2154919Sxy150489 }
2164919Sxy150489 
2174919Sxy150489 /*
2184919Sxy150489  * e1000_init_mac_params_82541 - Init MAC func ptrs.
2194919Sxy150489  * @hw: pointer to the HW structure
2204919Sxy150489  */
2214919Sxy150489 static s32
e1000_init_mac_params_82541(struct e1000_hw * hw)2224919Sxy150489 e1000_init_mac_params_82541(struct e1000_hw *hw)
2234919Sxy150489 {
2244919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
2254919Sxy150489 
2264919Sxy150489 	DEBUGFUNC("e1000_init_mac_params_82541");
2274919Sxy150489 
2284919Sxy150489 	/* Set media type */
2296735Scc210113 	hw->phy.media_type = e1000_media_type_copper;
2304919Sxy150489 	/* Set mta register count */
2314919Sxy150489 	mac->mta_reg_count = 128;
2324919Sxy150489 	/* Set rar entry count */
2334919Sxy150489 	mac->rar_entry_count = E1000_RAR_ENTRIES;
2344919Sxy150489 	/* Set if part includes ASF firmware */
2357607STed.You@Sun.COM 	mac->asf_firmware_present = true;
2364919Sxy150489 
2374919Sxy150489 	/* Function Pointers */
2384919Sxy150489 
2394919Sxy150489 	/* bus type/speed/width */
2406735Scc210113 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
24110680SMin.Xu@Sun.COM 	/* function id */
24210680SMin.Xu@Sun.COM 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
2434919Sxy150489 	/* reset */
2446735Scc210113 	mac->ops.reset_hw = e1000_reset_hw_82541;
2454919Sxy150489 	/* hw initialization */
2466735Scc210113 	mac->ops.init_hw = e1000_init_hw_82541;
2474919Sxy150489 	/* link setup */
2486735Scc210113 	mac->ops.setup_link = e1000_setup_link_generic;
2494919Sxy150489 	/* physical interface link setup */
2506735Scc210113 	mac->ops.setup_physical_interface = e1000_setup_copper_link_82541;
2514919Sxy150489 	/* check for link */
2526735Scc210113 	mac->ops.check_for_link = e1000_check_for_link_82541;
2534919Sxy150489 	/* link info */
2546735Scc210113 	mac->ops.get_link_up_info = e1000_get_link_up_info_82541;
2554919Sxy150489 	/* multicast address update */
2566735Scc210113 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2574919Sxy150489 	/* writing VFTA */
2586735Scc210113 	mac->ops.write_vfta = e1000_write_vfta_generic;
2594919Sxy150489 	/* clearing VFTA */
2606735Scc210113 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
2614919Sxy150489 	/* setting MTA */
2626735Scc210113 	mac->ops.mta_set = e1000_mta_set_generic;
26310680SMin.Xu@Sun.COM 	/* ID LED init */
26410680SMin.Xu@Sun.COM 	mac->ops.id_led_init = e1000_id_led_init_generic;
2654919Sxy150489 	/* setup LED */
2666735Scc210113 	mac->ops.setup_led = e1000_setup_led_82541;
2674919Sxy150489 	/* cleanup LED */
2686735Scc210113 	mac->ops.cleanup_led = e1000_cleanup_led_82541;
2694919Sxy150489 	/* turn on/off LED */
2706735Scc210113 	mac->ops.led_on = e1000_led_on_generic;
2716735Scc210113 	mac->ops.led_off = e1000_led_off_generic;
2724919Sxy150489 	/* clear hardware counters */
2736735Scc210113 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82541;
2744919Sxy150489 
2758479SChenlu.Chen@Sun.COM 	return (E1000_SUCCESS);
2764919Sxy150489 }
2774919Sxy150489 
2784919Sxy150489 /*
2794919Sxy150489  * e1000_init_function_pointers_82541 - Init func ptrs.
2804919Sxy150489  * @hw: pointer to the HW structure
2814919Sxy150489  *
2828479SChenlu.Chen@Sun.COM  * Called to initialize all function pointers and parameters.
2834919Sxy150489  */
2844919Sxy150489 void
e1000_init_function_pointers_82541(struct e1000_hw * hw)2854919Sxy150489 e1000_init_function_pointers_82541(struct e1000_hw *hw)
2864919Sxy150489 {
2874919Sxy150489 	DEBUGFUNC("e1000_init_function_pointers_82541");
2884919Sxy150489 
2896735Scc210113 	hw->mac.ops.init_params = e1000_init_mac_params_82541;
2906735Scc210113 	hw->nvm.ops.init_params = e1000_init_nvm_params_82541;
2916735Scc210113 	hw->phy.ops.init_params = e1000_init_phy_params_82541;
2924919Sxy150489 }
2934919Sxy150489 
2944919Sxy150489 /*
2954919Sxy150489  * e1000_reset_hw_82541 - Reset hardware
2964919Sxy150489  * @hw: pointer to the HW structure
2974919Sxy150489  *
2988479SChenlu.Chen@Sun.COM  * This resets the hardware into a known state.
2994919Sxy150489  */
3004919Sxy150489 static s32
e1000_reset_hw_82541(struct e1000_hw * hw)3014919Sxy150489 e1000_reset_hw_82541(struct e1000_hw *hw)
3024919Sxy150489 {
3038479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
3047426SChenliang.Xu@Sun.COM 	u32 ledctl, ctrl, manc;
3054919Sxy150489 
3064919Sxy150489 	DEBUGFUNC("e1000_reset_hw_82541");
3074919Sxy150489 
3084919Sxy150489 	DEBUGOUT("Masking off all interrupts\n");
3094919Sxy150489 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3104919Sxy150489 
3114919Sxy150489 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
3124919Sxy150489 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
3134919Sxy150489 	E1000_WRITE_FLUSH(hw);
3144919Sxy150489 
3154919Sxy150489 	dev_spec->tx_fifo_head = 0;
3164919Sxy150489 
3174919Sxy150489 	/*
3184919Sxy150489 	 * Delay to allow any outstanding PCI transactions to complete
3194919Sxy150489 	 * before resetting the device.
3204919Sxy150489 	 */
3214919Sxy150489 	msec_delay(10);
3224919Sxy150489 
3234919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
3244919Sxy150489 
3254919Sxy150489 	/* Must reset the Phy before resetting the MAC */
3264919Sxy150489 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3274919Sxy150489 		E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_PHY_RST));
3284919Sxy150489 		msec_delay(5);
3294919Sxy150489 	}
3304919Sxy150489 
3314919Sxy150489 	DEBUGOUT("Issuing a global reset to 82541/82547 MAC\n");
3324919Sxy150489 	switch (hw->mac.type) {
3334919Sxy150489 	case e1000_82541:
3344919Sxy150489 	case e1000_82541_rev_2:
3354919Sxy150489 		/*
3364919Sxy150489 		 * These controllers can't ack the 64-bit write when
3374919Sxy150489 		 * issuing the reset, so we use IO-mapping as a
3384919Sxy150489 		 * workaround to issue the reset.
3394919Sxy150489 		 */
3404919Sxy150489 		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3414919Sxy150489 		break;
3424919Sxy150489 	default:
3434919Sxy150489 		E1000_WRITE_REG(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
3444919Sxy150489 		break;
3454919Sxy150489 	}
3464919Sxy150489 
3474919Sxy150489 	/* Wait for NVM reload */
3484919Sxy150489 	msec_delay(20);
3494919Sxy150489 
3504919Sxy150489 	/* Disable HW ARPs on ASF enabled adapters */
3514919Sxy150489 	manc = E1000_READ_REG(hw, E1000_MANC);
3524919Sxy150489 	manc &= ~E1000_MANC_ARP_EN;
3534919Sxy150489 	E1000_WRITE_REG(hw, E1000_MANC, manc);
3544919Sxy150489 
3554919Sxy150489 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
3567426SChenliang.Xu@Sun.COM 		(void) e1000_phy_init_script_82541(hw);
3574919Sxy150489 
3584919Sxy150489 		/* Configure activity LED after Phy reset */
3594919Sxy150489 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
3604919Sxy150489 		ledctl &= IGP_ACTIVITY_LED_MASK;
3614919Sxy150489 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
3624919Sxy150489 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
3634919Sxy150489 	}
3644919Sxy150489 
3654919Sxy150489 	/* Once again, mask the interrupts */
3664919Sxy150489 	DEBUGOUT("Masking off all interrupts\n");
3674919Sxy150489 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
3684919Sxy150489 
3694919Sxy150489 	/* Clear any pending interrupt events. */
3707426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_ICR);
3714919Sxy150489 
3724919Sxy150489 	return (E1000_SUCCESS);
3734919Sxy150489 }
3744919Sxy150489 
3754919Sxy150489 /*
3764919Sxy150489  * e1000_init_hw_82541 - Initialize hardware
3774919Sxy150489  * @hw: pointer to the HW structure
3784919Sxy150489  *
3798479SChenlu.Chen@Sun.COM  * This inits the hardware readying it for operation.
3804919Sxy150489  */
3814919Sxy150489 static s32
e1000_init_hw_82541(struct e1000_hw * hw)3824919Sxy150489 e1000_init_hw_82541(struct e1000_hw *hw)
3834919Sxy150489 {
3844919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
3858479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
3864919Sxy150489 	u32 pba;
3874919Sxy150489 	u32 i, txdctl;
3884919Sxy150489 	s32 ret_val;
3894919Sxy150489 
3904919Sxy150489 	DEBUGFUNC("e1000_init_hw_82541");
3914919Sxy150489 
3924919Sxy150489 	/* Initialize identification LED */
39310680SMin.Xu@Sun.COM 	ret_val = mac->ops.id_led_init(hw);
3944919Sxy150489 	if (ret_val) {
395*11143SGuoqing.Zhu@Sun.COM 		/* EMPTY */
3964919Sxy150489 		DEBUGOUT("Error initializing identification LED\n");
3976735Scc210113 		/* This is not fatal and we should not stop init due to this */
3984919Sxy150489 	}
3994919Sxy150489 
40010680SMin.Xu@Sun.COM 	/* Storing the Speed Power Down  value for later use */
40110680SMin.Xu@Sun.COM 	ret_val = hw->phy.ops.read_reg(hw,
40210680SMin.Xu@Sun.COM 	    IGP01E1000_GMII_FIFO,
40310680SMin.Xu@Sun.COM 	    &dev_spec->spd_default);
40410680SMin.Xu@Sun.COM 	if (ret_val)
40510605SMin.Xu@Sun.COM 		goto out;
40610605SMin.Xu@Sun.COM 
4074919Sxy150489 	pba = E1000_READ_REG(hw, E1000_PBA);
4084919Sxy150489 	dev_spec->tx_fifo_start = (pba & 0x0000FFFF) * E1000_FIFO_MULTIPLIER;
4094919Sxy150489 	dev_spec->tx_fifo_size = (pba & 0xFFFF0000) >> 6;
4104919Sxy150489 
4114919Sxy150489 	/* Disabling VLAN filtering */
4124919Sxy150489 	DEBUGOUT("Initializing the IEEE VLAN\n");
4136735Scc210113 	mac->ops.clear_vfta(hw);
4144919Sxy150489 
4154919Sxy150489 	/* Setup the receive address. */
4164919Sxy150489 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
4174919Sxy150489 
4184919Sxy150489 	/* Zero out the Multicast HASH table */
4194919Sxy150489 	DEBUGOUT("Zeroing the MTA\n");
4204919Sxy150489 	for (i = 0; i < mac->mta_reg_count; i++) {
4214919Sxy150489 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
4224919Sxy150489 		/*
4234919Sxy150489 		 * Avoid back to back register writes by adding the register
4244919Sxy150489 		 * read (flush).  This is to protect against some strange
4254919Sxy150489 		 * bridge configurations that may issue Memory Write Block
4264919Sxy150489 		 * (MWB) to our register space.
4274919Sxy150489 		 */
4284919Sxy150489 		E1000_WRITE_FLUSH(hw);
4294919Sxy150489 	}
4304919Sxy150489 
4314919Sxy150489 	/* Setup link and flow control */
4326735Scc210113 	ret_val = mac->ops.setup_link(hw);
4334919Sxy150489 
4346735Scc210113 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
4354919Sxy150489 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
4364919Sxy150489 	    E1000_TXDCTL_FULL_TX_DESC_WB;
4376735Scc210113 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
4384919Sxy150489 
4394919Sxy150489 	/*
4404919Sxy150489 	 * Clear all of the statistics registers (clear on read).  It is
4414919Sxy150489 	 * important that we do this after we have tried to establish link
4424919Sxy150489 	 * because the symbol error count will increment wildly if there
4434919Sxy150489 	 * is no link.
4444919Sxy150489 	 */
4454919Sxy150489 	e1000_clear_hw_cntrs_82541(hw);
4464919Sxy150489 
44710605SMin.Xu@Sun.COM out:
4484919Sxy150489 	return (ret_val);
4494919Sxy150489 }
4504919Sxy150489 
4514919Sxy150489 /*
4524919Sxy150489  * e1000_get_link_up_info_82541 - Report speed and duplex
4534919Sxy150489  * @hw: pointer to the HW structure
4544919Sxy150489  * @speed: pointer to speed buffer
4554919Sxy150489  * @duplex: pointer to duplex buffer
4564919Sxy150489  *
4574919Sxy150489  * Retrieve the current speed and duplex configuration.
4584919Sxy150489  */
4594919Sxy150489 static s32
e1000_get_link_up_info_82541(struct e1000_hw * hw,u16 * speed,u16 * duplex)4604919Sxy150489 e1000_get_link_up_info_82541(struct e1000_hw *hw, u16 *speed, u16 *duplex)
4614919Sxy150489 {
4624919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
4634919Sxy150489 	s32 ret_val;
4644919Sxy150489 	u16 data;
4654919Sxy150489 
4664919Sxy150489 	DEBUGFUNC("e1000_get_link_up_info_82541");
4674919Sxy150489 
4684919Sxy150489 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
4694919Sxy150489 	if (ret_val)
4704919Sxy150489 		goto out;
4714919Sxy150489 
4724919Sxy150489 	if (!phy->speed_downgraded)
4734919Sxy150489 		goto out;
4744919Sxy150489 
4754919Sxy150489 	/*
4764919Sxy150489 	 * IGP01 PHY may advertise full duplex operation after speed
4774919Sxy150489 	 * downgrade even if it is operating at half duplex.
4784919Sxy150489 	 * Here we set the duplex settings to match the duplex in the
4794919Sxy150489 	 * link partner's capabilities.
4804919Sxy150489 	 */
4816735Scc210113 	ret_val = phy->ops.read_reg(hw, PHY_AUTONEG_EXP, &data);
4824919Sxy150489 	if (ret_val)
4834919Sxy150489 		goto out;
4844919Sxy150489 
4854919Sxy150489 	if (!(data & NWAY_ER_LP_NWAY_CAPS)) {
4864919Sxy150489 		*duplex = HALF_DUPLEX;
4874919Sxy150489 	} else {
4886735Scc210113 		ret_val = phy->ops.read_reg(hw, PHY_LP_ABILITY, &data);
4894919Sxy150489 		if (ret_val)
4904919Sxy150489 			goto out;
4914919Sxy150489 
4924919Sxy150489 		if (*speed == SPEED_100) {
4934919Sxy150489 			if (!(data & NWAY_LPAR_100TX_FD_CAPS))
4944919Sxy150489 				*duplex = HALF_DUPLEX;
4954919Sxy150489 		} else if (*speed == SPEED_10) {
4964919Sxy150489 			if (!(data & NWAY_LPAR_10T_FD_CAPS))
4974919Sxy150489 				*duplex = HALF_DUPLEX;
4984919Sxy150489 		}
4994919Sxy150489 	}
5004919Sxy150489 
5014919Sxy150489 out:
5024919Sxy150489 	return (ret_val);
5034919Sxy150489 }
5044919Sxy150489 
5054919Sxy150489 /*
5064919Sxy150489  * e1000_phy_hw_reset_82541 - PHY hardware reset
5074919Sxy150489  * @hw: pointer to the HW structure
5084919Sxy150489  *
5094919Sxy150489  * Verify the reset block is not blocking us from resetting.  Acquire
5104919Sxy150489  * semaphore (if necessary) and read/set/write the device control reset
5114919Sxy150489  * bit in the PHY.  Wait the appropriate delay time for the device to
5126735Scc210113  * reset and release the semaphore (if necessary).
5134919Sxy150489  */
5144919Sxy150489 static s32
e1000_phy_hw_reset_82541(struct e1000_hw * hw)5154919Sxy150489 e1000_phy_hw_reset_82541(struct e1000_hw *hw)
5164919Sxy150489 {
5174919Sxy150489 	s32 ret_val;
5184919Sxy150489 	u32 ledctl;
5194919Sxy150489 
5204919Sxy150489 	DEBUGFUNC("e1000_phy_hw_reset_82541");
5214919Sxy150489 
5224919Sxy150489 	ret_val = e1000_phy_hw_reset_generic(hw);
5234919Sxy150489 	if (ret_val)
5244919Sxy150489 		goto out;
5254919Sxy150489 
5267426SChenliang.Xu@Sun.COM 	(void) e1000_phy_init_script_82541(hw);
5274919Sxy150489 
5284919Sxy150489 	if ((hw->mac.type == e1000_82541) || (hw->mac.type == e1000_82547)) {
5294919Sxy150489 		/* Configure activity LED after PHY reset */
5304919Sxy150489 		ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5314919Sxy150489 		ledctl &= IGP_ACTIVITY_LED_MASK;
5324919Sxy150489 		ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5334919Sxy150489 		E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5344919Sxy150489 	}
5354919Sxy150489 
5364919Sxy150489 out:
5374919Sxy150489 	return (ret_val);
5384919Sxy150489 }
5394919Sxy150489 
5404919Sxy150489 /*
5414919Sxy150489  * e1000_setup_copper_link_82541 - Configure copper link settings
5424919Sxy150489  * @hw: pointer to the HW structure
5434919Sxy150489  *
5444919Sxy150489  * Calls the appropriate function to configure the link for auto-neg or forced
5454919Sxy150489  * speed and duplex.  Then we check for link, once link is established calls
5464919Sxy150489  * to configure collision distance and flow control are called.  If link is
5478479SChenlu.Chen@Sun.COM  * not established, we return -E1000_ERR_PHY (-2).
5484919Sxy150489  */
5494919Sxy150489 static s32
e1000_setup_copper_link_82541(struct e1000_hw * hw)5504919Sxy150489 e1000_setup_copper_link_82541(struct e1000_hw *hw)
5514919Sxy150489 {
5524919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
5538479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
5544919Sxy150489 	s32 ret_val;
5554919Sxy150489 	u32 ctrl, ledctl;
5564919Sxy150489 
5574919Sxy150489 	DEBUGFUNC("e1000_setup_copper_link_82541");
5584919Sxy150489 
5594919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
5604919Sxy150489 	ctrl |= E1000_CTRL_SLU;
5614919Sxy150489 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
5624919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
5634919Sxy150489 
5647607STed.You@Sun.COM 	hw->phy.reset_disable = false;
5654919Sxy150489 
5664919Sxy150489 	/* Earlier revs of the IGP phy require us to force MDI. */
5674919Sxy150489 	if (hw->mac.type == e1000_82541 || hw->mac.type == e1000_82547) {
5684919Sxy150489 		dev_spec->dsp_config = e1000_dsp_config_disabled;
5694919Sxy150489 		phy->mdix = 1;
5704919Sxy150489 	} else {
5714919Sxy150489 		dev_spec->dsp_config = e1000_dsp_config_enabled;
5724919Sxy150489 	}
5734919Sxy150489 
5744919Sxy150489 	ret_val = e1000_copper_link_setup_igp(hw);
5754919Sxy150489 	if (ret_val)
5764919Sxy150489 		goto out;
5774919Sxy150489 
5784919Sxy150489 	if (hw->mac.autoneg) {
5794919Sxy150489 		if (dev_spec->ffe_config == e1000_ffe_config_active)
5804919Sxy150489 			dev_spec->ffe_config = e1000_ffe_config_enabled;
5814919Sxy150489 	}
5824919Sxy150489 
5834919Sxy150489 	/* Configure activity LED after Phy reset */
5844919Sxy150489 	ledctl = E1000_READ_REG(hw, E1000_LEDCTL);
5854919Sxy150489 	ledctl &= IGP_ACTIVITY_LED_MASK;
5864919Sxy150489 	ledctl |= (IGP_ACTIVITY_LED_ENABLE | IGP_LED3_MODE);
5874919Sxy150489 	E1000_WRITE_REG(hw, E1000_LEDCTL, ledctl);
5884919Sxy150489 
5894919Sxy150489 	ret_val = e1000_setup_copper_link_generic(hw);
5904919Sxy150489 
5914919Sxy150489 out:
5924919Sxy150489 	return (ret_val);
5934919Sxy150489 }
5944919Sxy150489 
5954919Sxy150489 /*
5964919Sxy150489  * e1000_check_for_link_82541 - Check/Store link connection
5974919Sxy150489  * @hw: pointer to the HW structure
5984919Sxy150489  *
5994919Sxy150489  * This checks the link condition of the adapter and stores the
6008479SChenlu.Chen@Sun.COM  * results in the hw->mac structure.
6014919Sxy150489  */
6024919Sxy150489 static s32
e1000_check_for_link_82541(struct e1000_hw * hw)6034919Sxy150489 e1000_check_for_link_82541(struct e1000_hw *hw)
6044919Sxy150489 {
6054919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
6064919Sxy150489 	s32 ret_val;
6076735Scc210113 	bool link;
6084919Sxy150489 
6094919Sxy150489 	DEBUGFUNC("e1000_check_for_link_82541");
6104919Sxy150489 
6114919Sxy150489 	/*
6124919Sxy150489 	 * We only want to go out to the PHY registers to see if Auto-Neg
6134919Sxy150489 	 * has completed and/or if our link status has changed.  The
6144919Sxy150489 	 * get_link_status flag is set upon receiving a Link Status
6154919Sxy150489 	 * Change or Rx Sequence Error interrupt.
6164919Sxy150489 	 */
6174919Sxy150489 	if (!mac->get_link_status) {
6184919Sxy150489 		ret_val = E1000_SUCCESS;
6194919Sxy150489 		goto out;
6204919Sxy150489 	}
6214919Sxy150489 
6224919Sxy150489 	/*
6234919Sxy150489 	 * First we want to see if the MII Status Register reports
6244919Sxy150489 	 * link.  If so, then we want to get the current speed/duplex
6254919Sxy150489 	 * of the PHY.
6264919Sxy150489 	 */
6274919Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
6284919Sxy150489 	if (ret_val)
6294919Sxy150489 		goto out;
6304919Sxy150489 
6314919Sxy150489 	if (!link) {
6327607STed.You@Sun.COM 		ret_val = e1000_config_dsp_after_link_change_82541(hw, false);
6334919Sxy150489 		goto out;	/* No link detected */
6344919Sxy150489 	}
6354919Sxy150489 
6367607STed.You@Sun.COM 	mac->get_link_status = false;
6374919Sxy150489 
6384919Sxy150489 	/*
6394919Sxy150489 	 * Check if there was DownShift, must be checked
6404919Sxy150489 	 * immediately after link-up
6414919Sxy150489 	 */
6427426SChenliang.Xu@Sun.COM 	(void) e1000_check_downshift_generic(hw);
6434919Sxy150489 
6444919Sxy150489 	/*
6454919Sxy150489 	 * If we are forcing speed/duplex, then we simply return since
6464919Sxy150489 	 * we have already determined whether we have link or not.
6474919Sxy150489 	 */
6484919Sxy150489 	if (!mac->autoneg) {
6494919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
6504919Sxy150489 		goto out;
6514919Sxy150489 	}
6524919Sxy150489 
6537607STed.You@Sun.COM 	ret_val = e1000_config_dsp_after_link_change_82541(hw, true);
6544919Sxy150489 
6554919Sxy150489 	/*
6564919Sxy150489 	 * Auto-Neg is enabled.  Auto Speed Detection takes care
6574919Sxy150489 	 * of MAC speed/duplex configuration.  So we only need to
6584919Sxy150489 	 * configure Collision Distance in the MAC.
6594919Sxy150489 	 */
6604919Sxy150489 	e1000_config_collision_dist_generic(hw);
6614919Sxy150489 
6624919Sxy150489 	/*
6634919Sxy150489 	 * Configure Flow Control now that Auto-Neg has completed.
6644919Sxy150489 	 * First, we need to restore the desired flow control
6654919Sxy150489 	 * settings because we may have had to re-autoneg with a
6664919Sxy150489 	 * different link partner.
6674919Sxy150489 	 */
6684919Sxy150489 	ret_val = e1000_config_fc_after_link_up_generic(hw);
6694919Sxy150489 	if (ret_val) {
670*11143SGuoqing.Zhu@Sun.COM 		/* EMPTY */
6714919Sxy150489 		DEBUGOUT("Error configuring flow control\n");
6724919Sxy150489 	}
6734919Sxy150489 
6744919Sxy150489 out:
6754919Sxy150489 	return (ret_val);
6764919Sxy150489 }
6774919Sxy150489 
6784919Sxy150489 /*
6794919Sxy150489  * e1000_config_dsp_after_link_change_82541 - Config DSP after link
6804919Sxy150489  * @hw: pointer to the HW structure
6814919Sxy150489  * @link_up: boolean flag for link up status
6824919Sxy150489  *
6834919Sxy150489  * Return E1000_ERR_PHY when failing to read/write the PHY, else E1000_SUCCESS
6844919Sxy150489  * at any other case.
6854919Sxy150489  *
6864919Sxy150489  * 82541_rev_2 & 82547_rev_2 have the capability to configure the DSP when a
6874919Sxy150489  * gigabit link is achieved to improve link quality.
6884919Sxy150489  */
6894919Sxy150489 static s32
e1000_config_dsp_after_link_change_82541(struct e1000_hw * hw,bool link_up)6904919Sxy150489 e1000_config_dsp_after_link_change_82541(struct e1000_hw *hw,
6916735Scc210113     bool link_up)
6924919Sxy150489 {
6934919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
6948479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
6954919Sxy150489 	s32 ret_val;
6964919Sxy150489 	u32 idle_errs = 0;
6974919Sxy150489 	u16 phy_data, phy_saved_data, speed, duplex, i;
6984919Sxy150489 	u16 ffe_idle_err_timeout = FFE_IDLE_ERR_COUNT_TIMEOUT_20;
6994919Sxy150489 	u16 dsp_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
7004919Sxy150489 	{IGP01E1000_PHY_AGC_PARAM_A,
7014919Sxy150489 		IGP01E1000_PHY_AGC_PARAM_B,
7024919Sxy150489 		IGP01E1000_PHY_AGC_PARAM_C,
7034919Sxy150489 	IGP01E1000_PHY_AGC_PARAM_D};
7044919Sxy150489 
7054919Sxy150489 	DEBUGFUNC("e1000_config_dsp_after_link_change_82541");
7064919Sxy150489 
7074919Sxy150489 	if (link_up) {
7086735Scc210113 		ret_val = hw->mac.ops.get_link_up_info(hw, &speed, &duplex);
7094919Sxy150489 		if (ret_val) {
7104919Sxy150489 			DEBUGOUT("Error getting link speed and duplex\n");
7114919Sxy150489 			goto out;
7124919Sxy150489 		}
7134919Sxy150489 
7144919Sxy150489 		if (speed != SPEED_1000) {
7154919Sxy150489 			ret_val = E1000_SUCCESS;
7164919Sxy150489 			goto out;
7174919Sxy150489 		}
7184919Sxy150489 
7196735Scc210113 		ret_val = phy->ops.get_cable_length(hw);
7204919Sxy150489 		if (ret_val)
7214919Sxy150489 			goto out;
7224919Sxy150489 
7234919Sxy150489 		if ((dev_spec->dsp_config == e1000_dsp_config_enabled) &&
7244919Sxy150489 		    phy->min_cable_length >= 50) {
7254919Sxy150489 
7264919Sxy150489 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
7276735Scc210113 				ret_val = phy->ops.read_reg(hw,
7284919Sxy150489 				    dsp_reg_array[i],
7294919Sxy150489 				    &phy_data);
7304919Sxy150489 				if (ret_val)
7314919Sxy150489 					goto out;
7324919Sxy150489 
7334919Sxy150489 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
7344919Sxy150489 
7356735Scc210113 				ret_val = phy->ops.write_reg(hw,
7364919Sxy150489 				    dsp_reg_array[i],
7374919Sxy150489 				    phy_data);
7384919Sxy150489 				if (ret_val)
7394919Sxy150489 					goto out;
7404919Sxy150489 			}
7414919Sxy150489 			dev_spec->dsp_config = e1000_dsp_config_activated;
7424919Sxy150489 		}
7434919Sxy150489 
7444919Sxy150489 		if ((dev_spec->ffe_config != e1000_ffe_config_enabled) ||
7454919Sxy150489 		    (phy->min_cable_length >= 50)) {
7464919Sxy150489 			ret_val = E1000_SUCCESS;
7474919Sxy150489 			goto out;
7484919Sxy150489 		}
7494919Sxy150489 
7504919Sxy150489 		/* clear previous idle error counts */
7516735Scc210113 		ret_val = phy->ops.read_reg(hw, PHY_1000T_STATUS, &phy_data);
7524919Sxy150489 		if (ret_val)
7534919Sxy150489 			goto out;
7544919Sxy150489 
7554919Sxy150489 		for (i = 0; i < ffe_idle_err_timeout; i++) {
7564919Sxy150489 			usec_delay(1000);
7576735Scc210113 			ret_val = phy->ops.read_reg(hw,
7584919Sxy150489 			    PHY_1000T_STATUS,
7594919Sxy150489 			    &phy_data);
7604919Sxy150489 			if (ret_val)
7614919Sxy150489 				goto out;
7624919Sxy150489 
7634919Sxy150489 			idle_errs += (phy_data & SR_1000T_IDLE_ERROR_CNT);
7644919Sxy150489 			if (idle_errs > SR_1000T_PHY_EXCESSIVE_IDLE_ERR_COUNT) {
7654919Sxy150489 				dev_spec->ffe_config = e1000_ffe_config_active;
7664919Sxy150489 
7676735Scc210113 				ret_val = phy->ops.write_reg(hw,
7684919Sxy150489 				    IGP01E1000_PHY_DSP_FFE,
7694919Sxy150489 				    IGP01E1000_PHY_DSP_FFE_CM_CP);
7704919Sxy150489 				if (ret_val)
7714919Sxy150489 					goto out;
7724919Sxy150489 				break;
7734919Sxy150489 			}
7744919Sxy150489 
7754919Sxy150489 			if (idle_errs)
7764919Sxy150489 				ffe_idle_err_timeout =
7774919Sxy150489 				    FFE_IDLE_ERR_COUNT_TIMEOUT_100;
7784919Sxy150489 		}
7794919Sxy150489 	} else {
7804919Sxy150489 		if (dev_spec->dsp_config == e1000_dsp_config_activated) {
7814919Sxy150489 			/*
7824919Sxy150489 			 * Save off the current value of register 0x2F5B
7834919Sxy150489 			 * to be restored at the end of the routines.
7844919Sxy150489 			 */
7856735Scc210113 			ret_val = phy->ops.read_reg(hw,
7864919Sxy150489 			    0x2F5B,
7874919Sxy150489 			    &phy_saved_data);
7884919Sxy150489 			if (ret_val)
7894919Sxy150489 				goto out;
7904919Sxy150489 
7914919Sxy150489 			/* Disable the PHY transmitter */
7926735Scc210113 			ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
7934919Sxy150489 			if (ret_val)
7944919Sxy150489 				goto out;
7954919Sxy150489 
7964919Sxy150489 			msec_delay_irq(20);
7974919Sxy150489 
7986735Scc210113 			ret_val = phy->ops.write_reg(hw,
7994919Sxy150489 			    0x0000,
8004919Sxy150489 			    IGP01E1000_IEEE_FORCE_GIG);
8014919Sxy150489 			if (ret_val)
8024919Sxy150489 				goto out;
8034919Sxy150489 			for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
8046735Scc210113 				ret_val = phy->ops.read_reg(hw,
8054919Sxy150489 				    dsp_reg_array[i],
8064919Sxy150489 				    &phy_data);
8074919Sxy150489 				if (ret_val)
8084919Sxy150489 					goto out;
8094919Sxy150489 
8104919Sxy150489 				phy_data &= ~IGP01E1000_PHY_EDAC_MU_INDEX;
8114919Sxy150489 				phy_data |= IGP01E1000_PHY_EDAC_SIGN_EXT_9_BITS;
8124919Sxy150489 
8136735Scc210113 				ret_val = phy->ops.write_reg(hw,
8144919Sxy150489 				    dsp_reg_array[i],
8154919Sxy150489 				    phy_data);
8164919Sxy150489 				if (ret_val)
8174919Sxy150489 					goto out;
8184919Sxy150489 			}
8194919Sxy150489 
8206735Scc210113 			ret_val = phy->ops.write_reg(hw,
8214919Sxy150489 			    0x0000,
8224919Sxy150489 			    IGP01E1000_IEEE_RESTART_AUTONEG);
8234919Sxy150489 			if (ret_val)
8244919Sxy150489 				goto out;
8254919Sxy150489 
8264919Sxy150489 			msec_delay_irq(20);
8274919Sxy150489 
8284919Sxy150489 			/* Now enable the transmitter */
8296735Scc210113 			ret_val = phy->ops.write_reg(hw,
8304919Sxy150489 			    0x2F5B,
8314919Sxy150489 			    phy_saved_data);
8324919Sxy150489 			if (ret_val)
8334919Sxy150489 				goto out;
8344919Sxy150489 
8354919Sxy150489 			dev_spec->dsp_config = e1000_dsp_config_enabled;
8364919Sxy150489 		}
8374919Sxy150489 
8384919Sxy150489 		if (dev_spec->ffe_config != e1000_ffe_config_active) {
8394919Sxy150489 			ret_val = E1000_SUCCESS;
8404919Sxy150489 			goto out;
8414919Sxy150489 		}
8424919Sxy150489 
8434919Sxy150489 		/*
8444919Sxy150489 		 * Save off the current value of register 0x2F5B
8454919Sxy150489 		 * to be restored at the end of the routines.
8464919Sxy150489 		 */
8476735Scc210113 		ret_val = phy->ops.read_reg(hw, 0x2F5B, &phy_saved_data);
8484919Sxy150489 		if (ret_val)
8494919Sxy150489 			goto out;
8504919Sxy150489 
8514919Sxy150489 		/* Disable the PHY transmitter */
8526735Scc210113 		ret_val = phy->ops.write_reg(hw, 0x2F5B, 0x0003);
8534919Sxy150489 		if (ret_val)
8544919Sxy150489 			goto out;
8554919Sxy150489 
8564919Sxy150489 		msec_delay_irq(20);
8574919Sxy150489 
8586735Scc210113 		ret_val = phy->ops.write_reg(hw,
8594919Sxy150489 		    0x0000,
8604919Sxy150489 		    IGP01E1000_IEEE_FORCE_GIG);
8614919Sxy150489 		if (ret_val)
8624919Sxy150489 			goto out;
8634919Sxy150489 
8646735Scc210113 		ret_val = phy->ops.write_reg(hw,
8654919Sxy150489 		    IGP01E1000_PHY_DSP_FFE,
8664919Sxy150489 		    IGP01E1000_PHY_DSP_FFE_DEFAULT);
8674919Sxy150489 		if (ret_val)
8684919Sxy150489 			goto out;
8694919Sxy150489 
8706735Scc210113 		ret_val = phy->ops.write_reg(hw,
8714919Sxy150489 		    0x0000,
8724919Sxy150489 		    IGP01E1000_IEEE_RESTART_AUTONEG);
8734919Sxy150489 		if (ret_val)
8744919Sxy150489 			goto out;
8754919Sxy150489 
8764919Sxy150489 		msec_delay_irq(20);
8774919Sxy150489 
8784919Sxy150489 		/* Now enable the transmitter */
8796735Scc210113 		ret_val = phy->ops.write_reg(hw, 0x2F5B, phy_saved_data);
8804919Sxy150489 
8814919Sxy150489 		if (ret_val)
8824919Sxy150489 			goto out;
8834919Sxy150489 
8844919Sxy150489 		dev_spec->ffe_config = e1000_ffe_config_enabled;
8854919Sxy150489 	}
8864919Sxy150489 
8874919Sxy150489 out:
8884919Sxy150489 	return (ret_val);
8894919Sxy150489 }
8904919Sxy150489 
8914919Sxy150489 /*
8924919Sxy150489  * e1000_get_cable_length_igp_82541 - Determine cable length for igp PHY
8934919Sxy150489  * @hw: pointer to the HW structure
8944919Sxy150489  *
8954919Sxy150489  * The automatic gain control (agc) normalizes the amplitude of the
8964919Sxy150489  * received signal, adjusting for the attenuation produced by the
8976735Scc210113  * cable.  By reading the AGC registers, which represent the
8986735Scc210113  * combination of coarse and fine gain value, the value can be put
8994919Sxy150489  * into a lookup table to obtain the approximate cable length
9008479SChenlu.Chen@Sun.COM  * for each channel.
9014919Sxy150489  */
9024919Sxy150489 static s32
e1000_get_cable_length_igp_82541(struct e1000_hw * hw)9034919Sxy150489 e1000_get_cable_length_igp_82541(struct e1000_hw *hw)
9044919Sxy150489 {
9054919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
9064919Sxy150489 	s32 ret_val = E1000_SUCCESS;
9074919Sxy150489 	u16 i, data;
9084919Sxy150489 	u16 cur_agc_value, agc_value = 0;
9094919Sxy150489 	u16 min_agc_value = IGP01E1000_AGC_LENGTH_TABLE_SIZE;
9104919Sxy150489 	u16 agc_reg_array[IGP01E1000_PHY_CHANNEL_NUM] =
9114919Sxy150489 	{IGP01E1000_PHY_AGC_A,
9124919Sxy150489 		IGP01E1000_PHY_AGC_B,
9134919Sxy150489 		IGP01E1000_PHY_AGC_C,
9144919Sxy150489 	IGP01E1000_PHY_AGC_D};
9154919Sxy150489 
9164919Sxy150489 	DEBUGFUNC("e1000_get_cable_length_igp_82541");
9174919Sxy150489 
9184919Sxy150489 	/* Read the AGC registers for all channels */
9194919Sxy150489 	for (i = 0; i < IGP01E1000_PHY_CHANNEL_NUM; i++) {
9206735Scc210113 		ret_val = phy->ops.read_reg(hw, agc_reg_array[i], &data);
9214919Sxy150489 		if (ret_val)
9224919Sxy150489 			goto out;
9234919Sxy150489 
9244919Sxy150489 		cur_agc_value = data >> IGP01E1000_AGC_LENGTH_SHIFT;
9254919Sxy150489 
9264919Sxy150489 		/* Bounds checking */
9274919Sxy150489 		if ((cur_agc_value >= IGP01E1000_AGC_LENGTH_TABLE_SIZE - 1) ||
9284919Sxy150489 		    (cur_agc_value == 0)) {
9294919Sxy150489 			ret_val = -E1000_ERR_PHY;
9304919Sxy150489 			goto out;
9314919Sxy150489 		}
9324919Sxy150489 
9334919Sxy150489 		agc_value += cur_agc_value;
9344919Sxy150489 
9354919Sxy150489 		if (min_agc_value > cur_agc_value)
9364919Sxy150489 			min_agc_value = cur_agc_value;
9374919Sxy150489 	}
9384919Sxy150489 
9394919Sxy150489 	/* Remove the minimal AGC result for length < 50m */
9404919Sxy150489 	if (agc_value < IGP01E1000_PHY_CHANNEL_NUM * 50) {
9414919Sxy150489 		agc_value -= min_agc_value;
9424919Sxy150489 		/* Average the three remaining channels for the length. */
9434919Sxy150489 		agc_value /= (IGP01E1000_PHY_CHANNEL_NUM - 1);
9444919Sxy150489 	} else {
9454919Sxy150489 		/* Average the channels for the length. */
9464919Sxy150489 		agc_value /= IGP01E1000_PHY_CHANNEL_NUM;
9474919Sxy150489 	}
9484919Sxy150489 
9494919Sxy150489 	phy->min_cable_length = (e1000_igp_cable_length_table[agc_value] >
9504919Sxy150489 	    IGP01E1000_AGC_RANGE)
9514919Sxy150489 	    ? (e1000_igp_cable_length_table[agc_value] -
9524919Sxy150489 	    IGP01E1000_AGC_RANGE)
9534919Sxy150489 	    : 0;
9544919Sxy150489 	phy->max_cable_length = e1000_igp_cable_length_table[agc_value] +
9554919Sxy150489 	    IGP01E1000_AGC_RANGE;
9564919Sxy150489 
9574919Sxy150489 	phy->cable_length = (phy->min_cable_length + phy->max_cable_length) / 2;
9584919Sxy150489 
9594919Sxy150489 out:
9604919Sxy150489 	return (ret_val);
9614919Sxy150489 }
9624919Sxy150489 
9634919Sxy150489 /*
9644919Sxy150489  * e1000_set_d3_lplu_state_82541 - Sets low power link up state for D3
9654919Sxy150489  * @hw: pointer to the HW structure
9664919Sxy150489  * @active: boolean used to enable/disable lplu
9674919Sxy150489  *
9684919Sxy150489  * Success returns 0, Failure returns 1
9694919Sxy150489  *
9704919Sxy150489  * The low power link up (lplu) state is set to the power management level D3
9714919Sxy150489  * and SmartSpeed is disabled when active is true, else clear lplu for D3
9724919Sxy150489  * and enable Smartspeed.  LPLU and Smartspeed are mutually exclusive.  LPLU
9734919Sxy150489  * is used during Dx states where the power conservation is most important.
9744919Sxy150489  * During driver activity, SmartSpeed should be enabled so performance is
9758479SChenlu.Chen@Sun.COM  * maintained.
9764919Sxy150489  */
9774919Sxy150489 static s32
e1000_set_d3_lplu_state_82541(struct e1000_hw * hw,bool active)9786735Scc210113 e1000_set_d3_lplu_state_82541(struct e1000_hw *hw, bool active)
9794919Sxy150489 {
9804919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
9814919Sxy150489 	s32 ret_val;
9824919Sxy150489 	u16 data;
9834919Sxy150489 
9844919Sxy150489 	DEBUGFUNC("e1000_set_d3_lplu_state_82541");
9854919Sxy150489 
9864919Sxy150489 	switch (hw->mac.type) {
9874919Sxy150489 	case e1000_82541_rev_2:
9884919Sxy150489 	case e1000_82547_rev_2:
9894919Sxy150489 		break;
9904919Sxy150489 	default:
9914919Sxy150489 		ret_val = e1000_set_d3_lplu_state_generic(hw, active);
9924919Sxy150489 		goto out;
9934919Sxy150489 	}
9944919Sxy150489 
9956735Scc210113 	ret_val = phy->ops.read_reg(hw, IGP01E1000_GMII_FIFO, &data);
9964919Sxy150489 	if (ret_val)
9974919Sxy150489 		goto out;
9984919Sxy150489 
9994919Sxy150489 	if (!active) {
10004919Sxy150489 		data &= ~IGP01E1000_GMII_FLEX_SPD;
10016735Scc210113 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10024919Sxy150489 		if (ret_val)
10034919Sxy150489 			goto out;
10044919Sxy150489 
10054919Sxy150489 		/*
10064919Sxy150489 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
10074919Sxy150489 		 * during Dx states where the power conservation is most
10084919Sxy150489 		 * important.  During driver activity we should enable
10094919Sxy150489 		 * SmartSpeed, so performance is maintained.
10104919Sxy150489 		 */
10114919Sxy150489 		if (phy->smart_speed == e1000_smart_speed_on) {
10126735Scc210113 			ret_val = phy->ops.read_reg(hw,
10134919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
10144919Sxy150489 			    &data);
10154919Sxy150489 			if (ret_val)
10164919Sxy150489 				goto out;
10174919Sxy150489 
10184919Sxy150489 			data |= IGP01E1000_PSCFR_SMART_SPEED;
10196735Scc210113 			ret_val = phy->ops.write_reg(hw,
10204919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
10214919Sxy150489 			    data);
10224919Sxy150489 			if (ret_val)
10234919Sxy150489 				goto out;
10244919Sxy150489 		} else if (phy->smart_speed == e1000_smart_speed_off) {
10256735Scc210113 			ret_val = phy->ops.read_reg(hw,
10264919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
10274919Sxy150489 			    &data);
10284919Sxy150489 			if (ret_val)
10294919Sxy150489 				goto out;
10304919Sxy150489 
10314919Sxy150489 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10326735Scc210113 			ret_val = phy->ops.write_reg(hw,
10334919Sxy150489 			    IGP01E1000_PHY_PORT_CONFIG,
10344919Sxy150489 			    data);
10354919Sxy150489 			if (ret_val)
10364919Sxy150489 				goto out;
10374919Sxy150489 		}
10384919Sxy150489 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
10394919Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
10404919Sxy150489 	    (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
10414919Sxy150489 		data |= IGP01E1000_GMII_FLEX_SPD;
10426735Scc210113 		ret_val = phy->ops.write_reg(hw, IGP01E1000_GMII_FIFO, data);
10434919Sxy150489 		if (ret_val)
10444919Sxy150489 			goto out;
10454919Sxy150489 
10464919Sxy150489 		/* When LPLU is enabled, we should disable SmartSpeed */
10476735Scc210113 		ret_val = phy->ops.read_reg(hw,
10484919Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
10494919Sxy150489 		    &data);
10504919Sxy150489 		if (ret_val)
10514919Sxy150489 			goto out;
10524919Sxy150489 
10534919Sxy150489 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10546735Scc210113 		ret_val = phy->ops.write_reg(hw,
10554919Sxy150489 		    IGP01E1000_PHY_PORT_CONFIG,
10564919Sxy150489 		    data);
10574919Sxy150489 	}
10584919Sxy150489 
10594919Sxy150489 out:
10604919Sxy150489 	return (ret_val);
10614919Sxy150489 }
10624919Sxy150489 
10634919Sxy150489 /*
10644919Sxy150489  * e1000_setup_led_82541 - Configures SW controllable LED
10654919Sxy150489  * @hw: pointer to the HW structure
10664919Sxy150489  *
10674919Sxy150489  * This prepares the SW controllable LED for use and saves the current state
10688479SChenlu.Chen@Sun.COM  * of the LED so it can be later restored.
10694919Sxy150489  */
10704919Sxy150489 static s32
e1000_setup_led_82541(struct e1000_hw * hw)10714919Sxy150489 e1000_setup_led_82541(struct e1000_hw *hw)
10724919Sxy150489 {
10738479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
10744919Sxy150489 	s32 ret_val;
10754919Sxy150489 
10764919Sxy150489 	DEBUGFUNC("e1000_setup_led_82541");
10774919Sxy150489 
10786735Scc210113 	ret_val = hw->phy.ops.read_reg(hw,
10794919Sxy150489 	    IGP01E1000_GMII_FIFO,
10804919Sxy150489 	    &dev_spec->spd_default);
10814919Sxy150489 	if (ret_val)
10824919Sxy150489 		goto out;
10834919Sxy150489 
10846735Scc210113 	ret_val = hw->phy.ops.write_reg(hw,
10854919Sxy150489 	    IGP01E1000_GMII_FIFO,
10864919Sxy150489 	    (u16)(dev_spec->spd_default &
10874919Sxy150489 	    ~IGP01E1000_GMII_SPD));
10884919Sxy150489 	if (ret_val)
10894919Sxy150489 		goto out;
10904919Sxy150489 
10914919Sxy150489 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
10924919Sxy150489 
10934919Sxy150489 out:
10944919Sxy150489 	return (ret_val);
10954919Sxy150489 }
10964919Sxy150489 
10974919Sxy150489 /*
10984919Sxy150489  * e1000_cleanup_led_82541 - Set LED config to default operation
10994919Sxy150489  * @hw: pointer to the HW structure
11004919Sxy150489  *
11014919Sxy150489  * Remove the current LED configuration and set the LED configuration
11028479SChenlu.Chen@Sun.COM  * to the default value, saved from the EEPROM.
11034919Sxy150489  */
11044919Sxy150489 static s32
e1000_cleanup_led_82541(struct e1000_hw * hw)11054919Sxy150489 e1000_cleanup_led_82541(struct e1000_hw *hw)
11064919Sxy150489 {
11078479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
11084919Sxy150489 	s32 ret_val;
11094919Sxy150489 
11104919Sxy150489 	DEBUGFUNC("e1000_cleanup_led_82541");
11114919Sxy150489 
11126735Scc210113 	ret_val = hw->phy.ops.write_reg(hw,
11134919Sxy150489 	    IGP01E1000_GMII_FIFO,
11144919Sxy150489 	    dev_spec->spd_default);
11154919Sxy150489 	if (ret_val)
11164919Sxy150489 		goto out;
11174919Sxy150489 
11184919Sxy150489 	E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
11194919Sxy150489 
11204919Sxy150489 out:
11214919Sxy150489 	return (ret_val);
11224919Sxy150489 }
11234919Sxy150489 
11244919Sxy150489 /*
11254919Sxy150489  * e1000_phy_init_script_82541 - Initialize GbE PHY
11264919Sxy150489  * @hw: pointer to the HW structure
11274919Sxy150489  *
11284919Sxy150489  * Initializes the IGP PHY.
11294919Sxy150489  */
11304919Sxy150489 static s32
e1000_phy_init_script_82541(struct e1000_hw * hw)11314919Sxy150489 e1000_phy_init_script_82541(struct e1000_hw *hw)
11324919Sxy150489 {
11338479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
11344919Sxy150489 	u32 ret_val;
11354919Sxy150489 	u16 phy_saved_data;
11364919Sxy150489 
11374919Sxy150489 	DEBUGFUNC("e1000_phy_init_script_82541");
11384919Sxy150489 
11394919Sxy150489 	if (!dev_spec->phy_init_script) {
11404919Sxy150489 		ret_val = E1000_SUCCESS;
11414919Sxy150489 		goto out;
11424919Sxy150489 	}
11434919Sxy150489 
11444919Sxy150489 	/* Delay after phy reset to enable NVM configuration to load */
11454919Sxy150489 	msec_delay(20);
11464919Sxy150489 
11474919Sxy150489 	/*
11484919Sxy150489 	 * Save off the current value of register 0x2F5B to be restored at
11494919Sxy150489 	 * the end of this routine.
11504919Sxy150489 	 */
11516735Scc210113 	ret_val = hw->phy.ops.read_reg(hw, 0x2F5B, &phy_saved_data);
11524919Sxy150489 
11534919Sxy150489 	/* Disabled the PHY transmitter */
11546735Scc210113 	hw->phy.ops.write_reg(hw, 0x2F5B, 0x0003);
11554919Sxy150489 
11564919Sxy150489 	msec_delay(20);
11574919Sxy150489 
11586735Scc210113 	hw->phy.ops.write_reg(hw, 0x0000, 0x0140);
11594919Sxy150489 
11604919Sxy150489 	msec_delay(5);
11614919Sxy150489 
11624919Sxy150489 	switch (hw->mac.type) {
11634919Sxy150489 	case e1000_82541:
11644919Sxy150489 	case e1000_82547:
11656735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F95, 0x0001);
11664919Sxy150489 
11676735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F71, 0xBD21);
11684919Sxy150489 
11696735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F79, 0x0018);
11704919Sxy150489 
11716735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F30, 0x1600);
11724919Sxy150489 
11736735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F31, 0x0014);
11744919Sxy150489 
11756735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F32, 0x161C);
11764919Sxy150489 
11776735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F94, 0x0003);
11784919Sxy150489 
11796735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F96, 0x003F);
11804919Sxy150489 
11816735Scc210113 		hw->phy.ops.write_reg(hw, 0x2010, 0x0008);
11824919Sxy150489 		break;
11834919Sxy150489 	case e1000_82541_rev_2:
11844919Sxy150489 	case e1000_82547_rev_2:
11856735Scc210113 		hw->phy.ops.write_reg(hw, 0x1F73, 0x0099);
11864919Sxy150489 		break;
11874919Sxy150489 	default:
11884919Sxy150489 		break;
11894919Sxy150489 	}
11904919Sxy150489 
11916735Scc210113 	hw->phy.ops.write_reg(hw, 0x0000, 0x3300);
11924919Sxy150489 
11934919Sxy150489 	msec_delay(20);
11944919Sxy150489 
11954919Sxy150489 	/* Now enable the transmitter */
11966735Scc210113 	hw->phy.ops.write_reg(hw, 0x2F5B, phy_saved_data);
11974919Sxy150489 
11984919Sxy150489 	if (hw->mac.type == e1000_82547) {
11994919Sxy150489 		u16 fused, fine, coarse;
12004919Sxy150489 
12014919Sxy150489 		/* Move to analog registers page */
12026735Scc210113 		hw->phy.ops.read_reg(hw,
12034919Sxy150489 		    IGP01E1000_ANALOG_SPARE_FUSE_STATUS,
12044919Sxy150489 		    &fused);
12054919Sxy150489 
12064919Sxy150489 		if (!(fused & IGP01E1000_ANALOG_SPARE_FUSE_ENABLED)) {
12076735Scc210113 			hw->phy.ops.read_reg(hw,
12084919Sxy150489 			    IGP01E1000_ANALOG_FUSE_STATUS,
12094919Sxy150489 			    &fused);
12104919Sxy150489 
12114919Sxy150489 			fine = fused & IGP01E1000_ANALOG_FUSE_FINE_MASK;
12124919Sxy150489 			coarse = fused & IGP01E1000_ANALOG_FUSE_COARSE_MASK;
12134919Sxy150489 
12144919Sxy150489 			if (coarse > IGP01E1000_ANALOG_FUSE_COARSE_THRESH) {
12154919Sxy150489 				coarse -= IGP01E1000_ANALOG_FUSE_COARSE_10;
12164919Sxy150489 				fine -= IGP01E1000_ANALOG_FUSE_FINE_1;
12174919Sxy150489 			} else if (coarse ==
12184919Sxy150489 			    IGP01E1000_ANALOG_FUSE_COARSE_THRESH)
12194919Sxy150489 				fine -= IGP01E1000_ANALOG_FUSE_FINE_10;
12204919Sxy150489 
12214919Sxy150489 			fused = (fused & IGP01E1000_ANALOG_FUSE_POLY_MASK) |
12224919Sxy150489 			    (fine & IGP01E1000_ANALOG_FUSE_FINE_MASK) |
12234919Sxy150489 			    (coarse & IGP01E1000_ANALOG_FUSE_COARSE_MASK);
12244919Sxy150489 
12256735Scc210113 			hw->phy.ops.write_reg(hw,
12264919Sxy150489 			    IGP01E1000_ANALOG_FUSE_CONTROL,
12274919Sxy150489 			    fused);
12286735Scc210113 			hw->phy.ops.write_reg(hw,
12294919Sxy150489 			    IGP01E1000_ANALOG_FUSE_BYPASS,
12304919Sxy150489 			    IGP01E1000_ANALOG_FUSE_ENABLE_SW_CONTROL);
12314919Sxy150489 		}
12324919Sxy150489 	}
12334919Sxy150489 
12344919Sxy150489 out:
12354919Sxy150489 	return (ret_val);
12364919Sxy150489 }
12374919Sxy150489 
12384919Sxy150489 /*
12394919Sxy150489  * e1000_init_script_state_82541 - Enable/Disable PHY init script
12404919Sxy150489  * @hw: pointer to the HW structure
12414919Sxy150489  * @state: boolean value used to enable/disable PHY init script
12424919Sxy150489  *
12434919Sxy150489  * Allows the driver to enable/disable the PHY init script, if the PHY is an
12448479SChenlu.Chen@Sun.COM  * IGP PHY.
12454919Sxy150489  */
12464919Sxy150489 void
e1000_init_script_state_82541(struct e1000_hw * hw,bool state)12476735Scc210113 e1000_init_script_state_82541(struct e1000_hw *hw, bool state)
12484919Sxy150489 {
12498479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
12504919Sxy150489 
12514919Sxy150489 	DEBUGFUNC("e1000_init_script_state_82541");
12524919Sxy150489 
12534919Sxy150489 	if (hw->phy.type != e1000_phy_igp) {
12544919Sxy150489 		DEBUGOUT("Initialization script not necessary.\n");
12554919Sxy150489 		return;
12564919Sxy150489 	}
12574919Sxy150489 
12584919Sxy150489 	dev_spec->phy_init_script = state;
12594919Sxy150489 }
12604919Sxy150489 
12614919Sxy150489 /*
12626735Scc210113  * e1000_fifo_workaround_82547 - Workaround for Tx fifo failure
12634919Sxy150489  * @hw: pointer to the HW structure
12644919Sxy150489  * @length: length of next outgoing frame
12654919Sxy150489  *
12664919Sxy150489  * Returns: E1000_ERR_FIFO_WRAP if the next packet cannot be transmitted yet
12676735Scc210113  *	E1000_SUCCESS if the next packet can be transmitted
12684919Sxy150489  *
12696735Scc210113  * Workaround for the 82547 Tx fifo failure.
12704919Sxy150489  */
12714919Sxy150489 s32
e1000_fifo_workaround_82547(struct e1000_hw * hw,u16 length)12724919Sxy150489 e1000_fifo_workaround_82547(struct e1000_hw *hw, u16 length)
12734919Sxy150489 {
12748479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
12754919Sxy150489 	u32 tctl;
12764919Sxy150489 	s32 ret_val = E1000_SUCCESS;
12774919Sxy150489 	u16 fifo_pkt_len;
12784919Sxy150489 
12794919Sxy150489 	DEBUGFUNC("e1000_fifo_workaround_82547");
12804919Sxy150489 
12814919Sxy150489 	if (hw->mac.type != e1000_82547)
12824919Sxy150489 		goto out;
12834919Sxy150489 
12844919Sxy150489 	/*
12854919Sxy150489 	 * Get the length as seen by the FIFO of the next real
12864919Sxy150489 	 * packet to be transmitted.
12874919Sxy150489 	 */
12884919Sxy150489 	fifo_pkt_len = E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
12894919Sxy150489 	    E1000_FIFO_GRANULARITY);
12904919Sxy150489 
12914919Sxy150489 	if (fifo_pkt_len <= (E1000_FIFO_PAD_82547 + E1000_FIFO_HDR_SIZE))
12924919Sxy150489 		goto out;
12934919Sxy150489 
12944919Sxy150489 	if ((dev_spec->tx_fifo_head + fifo_pkt_len) <
12954919Sxy150489 	    (dev_spec->tx_fifo_size + E1000_FIFO_PAD_82547))
12964919Sxy150489 		goto out;
12974919Sxy150489 
12986735Scc210113 	if (E1000_READ_REG(hw, E1000_TDT(0)) !=
12996735Scc210113 	    E1000_READ_REG(hw, E1000_TDH(0))) {
13004919Sxy150489 		ret_val = -E1000_ERR_FIFO_WRAP;
13014919Sxy150489 		goto out;
13024919Sxy150489 	}
13034919Sxy150489 
13044919Sxy150489 	if (E1000_READ_REG(hw, E1000_TDFT) != E1000_READ_REG(hw, E1000_TDFH)) {
13054919Sxy150489 		ret_val = -E1000_ERR_FIFO_WRAP;
13064919Sxy150489 		goto out;
13074919Sxy150489 	}
13084919Sxy150489 
13094919Sxy150489 	if (E1000_READ_REG(hw, E1000_TDFTS) !=
13104919Sxy150489 	    E1000_READ_REG(hw, E1000_TDFHS)) {
13114919Sxy150489 		ret_val = -E1000_ERR_FIFO_WRAP;
13124919Sxy150489 		goto out;
13134919Sxy150489 	}
13144919Sxy150489 
13154919Sxy150489 	/* Disable the tx unit to avoid further pointer movement */
13164919Sxy150489 	tctl = E1000_READ_REG(hw, E1000_TCTL);
13174919Sxy150489 	E1000_WRITE_REG(hw, E1000_TCTL, tctl & ~E1000_TCTL_EN);
13184919Sxy150489 
13194919Sxy150489 	/* Reset the fifo pointers. */
13204919Sxy150489 	E1000_WRITE_REG(hw, E1000_TDFT, dev_spec->tx_fifo_start);
13214919Sxy150489 	E1000_WRITE_REG(hw, E1000_TDFH, dev_spec->tx_fifo_start);
13224919Sxy150489 	E1000_WRITE_REG(hw, E1000_TDFTS, dev_spec->tx_fifo_start);
13234919Sxy150489 	E1000_WRITE_REG(hw, E1000_TDFHS, dev_spec->tx_fifo_start);
13244919Sxy150489 
13254919Sxy150489 	/* Re-enabling tx unit */
13264919Sxy150489 	E1000_WRITE_REG(hw, E1000_TCTL, tctl);
13274919Sxy150489 	E1000_WRITE_FLUSH(hw);
13284919Sxy150489 
13294919Sxy150489 	dev_spec->tx_fifo_head = 0;
13304919Sxy150489 
13314919Sxy150489 out:
13324919Sxy150489 	return (ret_val);
13334919Sxy150489 }
13344919Sxy150489 
13354919Sxy150489 /*
13366735Scc210113  * e1000_update_tx_fifo_head - Update Tx fifo head pointer
13374919Sxy150489  * @hw: pointer to the HW structure
13384919Sxy150489  * @length: length of next outgoing frame
13394919Sxy150489  *
13406735Scc210113  * Updates the SW calculated Tx FIFO head pointer.
13414919Sxy150489  */
13424919Sxy150489 void
e1000_update_tx_fifo_head_82547(struct e1000_hw * hw,u32 length)13434919Sxy150489 e1000_update_tx_fifo_head_82547(struct e1000_hw *hw, u32 length)
13444919Sxy150489 {
13458479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13464919Sxy150489 
13474919Sxy150489 	DEBUGFUNC("e1000_update_tx_fifo_head_82547");
13484919Sxy150489 
13494919Sxy150489 	if (hw->mac.type != e1000_82547)
13504919Sxy150489 		return;
13514919Sxy150489 
13524919Sxy150489 	dev_spec->tx_fifo_head += E1000_ROUNDUP(length + E1000_FIFO_HDR_SIZE,
13534919Sxy150489 	    E1000_FIFO_GRANULARITY);
13544919Sxy150489 
13554919Sxy150489 	if (dev_spec->tx_fifo_head > dev_spec->tx_fifo_size)
13564919Sxy150489 		dev_spec->tx_fifo_head -= dev_spec->tx_fifo_size;
13574919Sxy150489 }
13584919Sxy150489 
13594919Sxy150489 /*
13604919Sxy150489  * e1000_set_ttl_workaround_state_82541 - Enable/Disables TTL workaround
13614919Sxy150489  * @hw: pointer to the HW structure
13624919Sxy150489  * @state: boolean to enable/disable TTL workaround
13634919Sxy150489  *
13644919Sxy150489  * For 82541 or 82547 only silicon, allows the driver to enable/disable the
13654919Sxy150489  * TTL workaround.
13664919Sxy150489  */
13674919Sxy150489 void
e1000_set_ttl_workaround_state_82541(struct e1000_hw * hw,bool state)13686735Scc210113 e1000_set_ttl_workaround_state_82541(struct e1000_hw *hw, bool state)
13694919Sxy150489 {
13708479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13714919Sxy150489 
13724919Sxy150489 	DEBUGFUNC("e1000_set_ttl_workaround_state_82541");
13734919Sxy150489 
13744919Sxy150489 	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
13754919Sxy150489 		return;
13764919Sxy150489 
13774919Sxy150489 	dev_spec->ttl_workaround = state;
13784919Sxy150489 }
13794919Sxy150489 
13804919Sxy150489 /*
13814919Sxy150489  * e1000_ttl_workaround_enabled_82541 - Returns current TTL workaround status
13824919Sxy150489  * @hw: pointer to the HW structure
13834919Sxy150489  *
13844919Sxy150489  * Returns the current status of the TTL workaround, as to whether the
13854919Sxy150489  * workaround is enabled or disabled.
13864919Sxy150489  */
13876735Scc210113 bool
e1000_ttl_workaround_enabled_82541(struct e1000_hw * hw)13884919Sxy150489 e1000_ttl_workaround_enabled_82541(struct e1000_hw *hw)
13894919Sxy150489 {
13908479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
13917607STed.You@Sun.COM 	bool state = false;
13924919Sxy150489 
13934919Sxy150489 	DEBUGFUNC("e1000_ttl_workaround_enabled_82541");
13944919Sxy150489 
13954919Sxy150489 	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
13964919Sxy150489 		goto out;
13974919Sxy150489 
13984919Sxy150489 	state = dev_spec->ttl_workaround;
13994919Sxy150489 
14004919Sxy150489 out:
14014919Sxy150489 	return (state);
14024919Sxy150489 }
14034919Sxy150489 
14044919Sxy150489 /*
14054919Sxy150489  * e1000_igp_ttl_workaround_82547 - Workaround for long TTL on 100HD hubs
14064919Sxy150489  * @hw: pointer to the HW structure
14074919Sxy150489  *
14084919Sxy150489  * Returns: E1000_ERR_PHY if fail to read/write the PHY
14094919Sxy150489  *          E1000_SUCCESS in any other case
14104919Sxy150489  *
14114919Sxy150489  * This function, specific to 82547 hardware only, needs to be called every
14124919Sxy150489  * second.  It checks if a parallel detect fault has occurred.  If a fault
14134919Sxy150489  * occurred, disable/enable the DSP reset mechanism up to 5 times (once per
14144919Sxy150489  * second).  If link is established, stop the workaround and ensure the DSP
14154919Sxy150489  * reset is enabled.
14164919Sxy150489  */
14174919Sxy150489 s32
e1000_igp_ttl_workaround_82547(struct e1000_hw * hw)14184919Sxy150489 e1000_igp_ttl_workaround_82547(struct e1000_hw *hw)
14194919Sxy150489 {
14208479SChenlu.Chen@Sun.COM 	struct e1000_dev_spec_82541 *dev_spec = &hw->dev_spec._82541;
14214919Sxy150489 	s32 ret_val = E1000_SUCCESS;
14224919Sxy150489 	u16 phy_data = 0;
14234919Sxy150489 	u16 dsp_value = DSP_RESET_ENABLE;
14246735Scc210113 	bool link;
14254919Sxy150489 
14264919Sxy150489 	DEBUGFUNC("e1000_igp_ttl_workaround_82547");
14274919Sxy150489 
14284919Sxy150489 	/* The workaround needed only for B-0 silicon HW */
14294919Sxy150489 	if ((hw->mac.type != e1000_82541) && (hw->mac.type != e1000_82547))
14304919Sxy150489 		goto out;
14314919Sxy150489 
14324919Sxy150489 	if (!(e1000_ttl_workaround_enabled_82541(hw)))
14334919Sxy150489 		goto out;
14344919Sxy150489 
14354919Sxy150489 	/* Check for link first */
14364919Sxy150489 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
14374919Sxy150489 	if (ret_val)
14384919Sxy150489 		goto out;
14394919Sxy150489 
14404919Sxy150489 	if (link) {
14414919Sxy150489 		/*
14424919Sxy150489 		 * If link is established during the workaround,
14434919Sxy150489 		 * the DSP mechanism must be enabled.
14444919Sxy150489 		 */
14454919Sxy150489 		if (dev_spec->dsp_reset_counter) {
14464919Sxy150489 			dev_spec->dsp_reset_counter = 0;
14474919Sxy150489 			dsp_value = DSP_RESET_ENABLE;
14484919Sxy150489 		} else {
14494919Sxy150489 			ret_val = E1000_SUCCESS;
14504919Sxy150489 			goto out;
14514919Sxy150489 		}
14524919Sxy150489 	} else {
14534919Sxy150489 		if (dev_spec->dsp_reset_counter == 0) {
14544919Sxy150489 			/*
14554919Sxy150489 			 * Workaround not activated,
14564919Sxy150489 			 * check if it needs activation
14574919Sxy150489 			 */
14586735Scc210113 			ret_val = hw->phy.ops.read_reg(hw,
14594919Sxy150489 			    PHY_AUTONEG_EXP,
14604919Sxy150489 			    &phy_data);
14614919Sxy150489 			if (ret_val)
14624919Sxy150489 				goto out;
14634919Sxy150489 			/*
14644919Sxy150489 			 * Activate the workaround if there was a
14654919Sxy150489 			 * parallel detect fault
14664919Sxy150489 			 */
14674919Sxy150489 			if (phy_data & NWAY_ER_PAR_DETECT_FAULT) {
14684919Sxy150489 				dev_spec->dsp_reset_counter++;
14694919Sxy150489 			} else {
14704919Sxy150489 				ret_val = E1000_SUCCESS;
14714919Sxy150489 				goto out;
14724919Sxy150489 			}
14734919Sxy150489 		}
14744919Sxy150489 
14754919Sxy150489 		/* After 5 times, stop the workaround */
14764919Sxy150489 		if (dev_spec->dsp_reset_counter > E1000_MAX_DSP_RESETS) {
14774919Sxy150489 			dev_spec->dsp_reset_counter = 0;
14784919Sxy150489 			dsp_value = DSP_RESET_ENABLE;
14794919Sxy150489 		} else {
14804919Sxy150489 			if (dev_spec->dsp_reset_counter) {
14814919Sxy150489 				dsp_value = (dev_spec->dsp_reset_counter & 1)
14824919Sxy150489 				    ? DSP_RESET_DISABLE
14834919Sxy150489 				    : DSP_RESET_ENABLE;
14844919Sxy150489 				dev_spec->dsp_reset_counter++;
14854919Sxy150489 			}
14864919Sxy150489 		}
14874919Sxy150489 	}
14884919Sxy150489 
14896735Scc210113 	ret_val =
14906735Scc210113 	    hw->phy.ops.write_reg(hw, IGP01E1000_PHY_DSP_RESET, dsp_value);
14914919Sxy150489 
14924919Sxy150489 out:
14934919Sxy150489 	return (ret_val);
14944919Sxy150489 }
14954919Sxy150489 
14964919Sxy150489 /*
14976735Scc210113  * e1000_power_down_phy_copper_82541 - Remove link in case of PHY power down
14986735Scc210113  * @hw: pointer to the HW structure
14996735Scc210113  *
15006735Scc210113  * In the case of a PHY power down to save power, or to turn off link during a
15016735Scc210113  * driver unload, or wake on lan is not enabled, remove the link.
15026735Scc210113  */
15036735Scc210113 static void
e1000_power_down_phy_copper_82541(struct e1000_hw * hw)15046735Scc210113 e1000_power_down_phy_copper_82541(struct e1000_hw *hw)
15056735Scc210113 {
15066735Scc210113 	/* If the management interface is not enabled, then power down */
15076735Scc210113 	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
15086735Scc210113 		e1000_power_down_phy_copper(hw);
15096735Scc210113 }
15106735Scc210113 
15116735Scc210113 /*
15124919Sxy150489  * e1000_clear_hw_cntrs_82541 - Clear device specific hardware counters
15134919Sxy150489  * @hw: pointer to the HW structure
15144919Sxy150489  *
15154919Sxy150489  * Clears the hardware counters by reading the counter registers.
15164919Sxy150489  */
15174919Sxy150489 static void
e1000_clear_hw_cntrs_82541(struct e1000_hw * hw)15184919Sxy150489 e1000_clear_hw_cntrs_82541(struct e1000_hw *hw)
15194919Sxy150489 {
15204919Sxy150489 	DEBUGFUNC("e1000_clear_hw_cntrs_82541");
15214919Sxy150489 
15224919Sxy150489 	e1000_clear_hw_cntrs_base_generic(hw);
15234919Sxy150489 
15247426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC64);
15257426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC127);
15267426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC255);
15277426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC511);
15287426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC1023);
15297426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC1522);
15307426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC64);
15317426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC127);
15327426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC255);
15337426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC511);
15347426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC1023);
15357426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC1522);
15364919Sxy150489 
15377426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_ALGNERRC);
15387426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_RXERRC);
15397426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TNCRS);
15407426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_CEXTERR);
15417426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TSCTC);
15427426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TSCTFC);
15434919Sxy150489 
15447426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPRC);
15457426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPDC);
15467426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPTC);
15474919Sxy150489 }
1548