xref: /onnv-gate/usr/src/uts/common/io/e1000g/e1000_82540.c (revision 8479:ad81b6a87fd7)
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  *
9*8479SChenlu.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
166735Scc210113  *      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 /*
22*8479SChenlu.Chen@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
234919Sxy150489  * Use is subject to license terms of the CDDLv1.
244919Sxy150489  */
254919Sxy150489 
264919Sxy150489 /*
27*8479SChenlu.Chen@Sun.COM  * IntelVersion: 1.54 sol_anvik_patch
284919Sxy150489  */
296735Scc210113 
304919Sxy150489 /*
31*8479SChenlu.Chen@Sun.COM  * 82540EM Gigabit Ethernet Controller
32*8479SChenlu.Chen@Sun.COM  * 82540EP Gigabit Ethernet Controller
33*8479SChenlu.Chen@Sun.COM  * 82545EM Gigabit Ethernet Controller (Copper)
34*8479SChenlu.Chen@Sun.COM  * 82545EM Gigabit Ethernet Controller (Fiber)
35*8479SChenlu.Chen@Sun.COM  * 82545GM Gigabit Ethernet Controller
36*8479SChenlu.Chen@Sun.COM  * 82546EB Gigabit Ethernet Controller (Copper)
37*8479SChenlu.Chen@Sun.COM  * 82546EB Gigabit Ethernet Controller (Fiber)
38*8479SChenlu.Chen@Sun.COM  * 82546GB Gigabit Ethernet Controller
394919Sxy150489  */
404919Sxy150489 
414919Sxy150489 #include "e1000_api.h"
424919Sxy150489 
434919Sxy150489 static s32 e1000_init_phy_params_82540(struct e1000_hw *hw);
444919Sxy150489 static s32 e1000_init_nvm_params_82540(struct e1000_hw *hw);
454919Sxy150489 static s32 e1000_init_mac_params_82540(struct e1000_hw *hw);
464919Sxy150489 static s32 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw);
474919Sxy150489 static void e1000_clear_hw_cntrs_82540(struct e1000_hw *hw);
484919Sxy150489 static s32 e1000_init_hw_82540(struct e1000_hw *hw);
494919Sxy150489 static s32 e1000_reset_hw_82540(struct e1000_hw *hw);
504919Sxy150489 static s32 e1000_set_phy_mode_82540(struct e1000_hw *hw);
514919Sxy150489 static s32 e1000_set_vco_speed_82540(struct e1000_hw *hw);
524919Sxy150489 static s32 e1000_setup_copper_link_82540(struct e1000_hw *hw);
534919Sxy150489 static s32 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw);
546735Scc210113 static void e1000_power_down_phy_copper_82540(struct e1000_hw *hw);
554919Sxy150489 
564919Sxy150489 /*
574919Sxy150489  * e1000_init_phy_params_82540 - Init PHY func ptrs.
584919Sxy150489  * @hw: pointer to the HW structure
594919Sxy150489  */
604919Sxy150489 static s32
614919Sxy150489 e1000_init_phy_params_82540(struct e1000_hw *hw)
624919Sxy150489 {
634919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
644919Sxy150489 	s32 ret_val = E1000_SUCCESS;
654919Sxy150489 
664919Sxy150489 	phy->addr = 1;
674919Sxy150489 	phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
684919Sxy150489 	phy->reset_delay_us = 10000;
694919Sxy150489 	phy->type = e1000_phy_m88;
704919Sxy150489 
714919Sxy150489 	/* Function Pointers */
726735Scc210113 	phy->ops.check_polarity = e1000_check_polarity_m88;
736735Scc210113 	phy->ops.commit = e1000_phy_sw_reset_generic;
746735Scc210113 	phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_m88;
756735Scc210113 	phy->ops.get_cable_length = e1000_get_cable_length_m88;
766735Scc210113 	phy->ops.get_cfg_done = e1000_get_cfg_done_generic;
776735Scc210113 	phy->ops.read_reg = e1000_read_phy_reg_m88;
786735Scc210113 	phy->ops.reset = e1000_phy_hw_reset_generic;
796735Scc210113 	phy->ops.write_reg = e1000_write_phy_reg_m88;
806735Scc210113 	phy->ops.get_info = e1000_get_phy_info_m88;
816735Scc210113 	phy->ops.power_up = e1000_power_up_phy_copper;
826735Scc210113 	phy->ops.power_down = e1000_power_down_phy_copper_82540;
834919Sxy150489 
844919Sxy150489 	ret_val = e1000_get_phy_id(hw);
854919Sxy150489 	if (ret_val)
864919Sxy150489 		goto out;
874919Sxy150489 
884919Sxy150489 	/* Verify phy id */
894919Sxy150489 	switch (hw->mac.type) {
904919Sxy150489 	case e1000_82540:
914919Sxy150489 	case e1000_82545:
924919Sxy150489 	case e1000_82545_rev_3:
934919Sxy150489 	case e1000_82546:
944919Sxy150489 	case e1000_82546_rev_3:
954919Sxy150489 		if (phy->id == M88E1011_I_PHY_ID)
964919Sxy150489 			break;
974919Sxy150489 		/* Fall Through */
984919Sxy150489 	default:
994919Sxy150489 		ret_val = -E1000_ERR_PHY;
1004919Sxy150489 		goto out;
1014919Sxy150489 	}
1024919Sxy150489 
1034919Sxy150489 out:
1044919Sxy150489 	return (ret_val);
1054919Sxy150489 }
1064919Sxy150489 
1074919Sxy150489 /*
1084919Sxy150489  * e1000_init_nvm_params_82540 - Init NVM func ptrs.
1094919Sxy150489  * @hw: pointer to the HW structure
1104919Sxy150489  */
1114919Sxy150489 static s32
1124919Sxy150489 e1000_init_nvm_params_82540(struct e1000_hw *hw)
1134919Sxy150489 {
1144919Sxy150489 	struct e1000_nvm_info *nvm = &hw->nvm;
1154919Sxy150489 	u32 eecd = E1000_READ_REG(hw, E1000_EECD);
1164919Sxy150489 
1174919Sxy150489 	DEBUGFUNC("e1000_init_nvm_params_82540");
1184919Sxy150489 
1194919Sxy150489 	nvm->type = e1000_nvm_eeprom_microwire;
1204919Sxy150489 	nvm->delay_usec = 50;
1214919Sxy150489 	nvm->opcode_bits = 3;
1224919Sxy150489 	switch (nvm->override) {
1234919Sxy150489 	case e1000_nvm_override_microwire_large:
1244919Sxy150489 		nvm->address_bits = 8;
1254919Sxy150489 		nvm->word_size = 256;
1264919Sxy150489 		break;
1274919Sxy150489 	case e1000_nvm_override_microwire_small:
1284919Sxy150489 		nvm->address_bits = 6;
1294919Sxy150489 		nvm->word_size = 64;
1304919Sxy150489 		break;
1314919Sxy150489 	default:
1324919Sxy150489 		nvm->address_bits = eecd & E1000_EECD_SIZE ? 8 : 6;
1334919Sxy150489 		nvm->word_size = eecd & E1000_EECD_SIZE ? 256 : 64;
1344919Sxy150489 		break;
1354919Sxy150489 	}
1364919Sxy150489 
1374919Sxy150489 	/* Function Pointers */
1386735Scc210113 	nvm->ops.acquire = e1000_acquire_nvm_generic;
1396735Scc210113 	nvm->ops.read = e1000_read_nvm_microwire;
1406735Scc210113 	nvm->ops.release = e1000_release_nvm_generic;
1416735Scc210113 	nvm->ops.update = e1000_update_nvm_checksum_generic;
1426735Scc210113 	nvm->ops.valid_led_default = e1000_valid_led_default_generic;
1436735Scc210113 	nvm->ops.validate = e1000_validate_nvm_checksum_generic;
1446735Scc210113 	nvm->ops.write = e1000_write_nvm_microwire;
1454919Sxy150489 
1464919Sxy150489 	return (E1000_SUCCESS);
1474919Sxy150489 }
1484919Sxy150489 
1494919Sxy150489 /*
1504919Sxy150489  * e1000_init_mac_params_82540 - Init MAC func ptrs.
1514919Sxy150489  * @hw: pointer to the HW structure
1524919Sxy150489  */
1534919Sxy150489 static s32
1544919Sxy150489 e1000_init_mac_params_82540(struct e1000_hw *hw)
1554919Sxy150489 {
1564919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
1574919Sxy150489 	s32 ret_val = E1000_SUCCESS;
1584919Sxy150489 
1594919Sxy150489 	DEBUGFUNC("e1000_init_mac_params_82540");
1604919Sxy150489 
1614919Sxy150489 	/* Set media type */
1624919Sxy150489 	switch (hw->device_id) {
1634919Sxy150489 	case E1000_DEV_ID_82545EM_FIBER:
1644919Sxy150489 	case E1000_DEV_ID_82545GM_FIBER:
1654919Sxy150489 	case E1000_DEV_ID_82546EB_FIBER:
1664919Sxy150489 	case E1000_DEV_ID_82546GB_FIBER:
1676735Scc210113 		hw->phy.media_type = e1000_media_type_fiber;
1684919Sxy150489 		break;
1694919Sxy150489 	case E1000_DEV_ID_82545GM_SERDES:
1704919Sxy150489 	case E1000_DEV_ID_82546GB_SERDES:
1716735Scc210113 		hw->phy.media_type = e1000_media_type_internal_serdes;
1724919Sxy150489 		break;
1734919Sxy150489 	default:
1746735Scc210113 		hw->phy.media_type = e1000_media_type_copper;
1754919Sxy150489 		break;
1764919Sxy150489 	}
1774919Sxy150489 
1784919Sxy150489 	/* Set mta register count */
1794919Sxy150489 	mac->mta_reg_count = 128;
1804919Sxy150489 	/* Set rar entry count */
1814919Sxy150489 	mac->rar_entry_count = E1000_RAR_ENTRIES;
1824919Sxy150489 
1834919Sxy150489 	/* Function pointers */
1844919Sxy150489 
1854919Sxy150489 	/* bus type/speed/width */
1866735Scc210113 	mac->ops.get_bus_info = e1000_get_bus_info_pci_generic;
1874919Sxy150489 	/* reset */
1886735Scc210113 	mac->ops.reset_hw = e1000_reset_hw_82540;
1894919Sxy150489 	/* hw initialization */
1906735Scc210113 	mac->ops.init_hw = e1000_init_hw_82540;
1914919Sxy150489 	/* link setup */
1926735Scc210113 	mac->ops.setup_link = e1000_setup_link_generic;
1934919Sxy150489 	/* physical interface setup */
1946735Scc210113 	mac->ops.setup_physical_interface =
1956735Scc210113 	    (hw->phy.media_type == e1000_media_type_copper)
1964919Sxy150489 	    ? e1000_setup_copper_link_82540
1974919Sxy150489 	    : e1000_setup_fiber_serdes_link_82540;
1984919Sxy150489 	/* check for link */
1996735Scc210113 	switch (hw->phy.media_type) {
2004919Sxy150489 	case e1000_media_type_copper:
2016735Scc210113 		mac->ops.check_for_link = e1000_check_for_copper_link_generic;
2024919Sxy150489 		break;
2034919Sxy150489 	case e1000_media_type_fiber:
2046735Scc210113 		mac->ops.check_for_link = e1000_check_for_fiber_link_generic;
2054919Sxy150489 		break;
2064919Sxy150489 	case e1000_media_type_internal_serdes:
2076735Scc210113 		mac->ops.check_for_link = e1000_check_for_serdes_link_generic;
2084919Sxy150489 		break;
2094919Sxy150489 	default:
2104919Sxy150489 		ret_val = -E1000_ERR_CONFIG;
2114919Sxy150489 		goto out;
2124919Sxy150489 	}
2134919Sxy150489 	/* link info */
2146735Scc210113 	mac->ops.get_link_up_info =
2156735Scc210113 	    (hw->phy.media_type == e1000_media_type_copper)
2164919Sxy150489 	    ? e1000_get_speed_and_duplex_copper_generic
2174919Sxy150489 	    : e1000_get_speed_and_duplex_fiber_serdes_generic;
2184919Sxy150489 	/* multicast address update */
2196735Scc210113 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
2204919Sxy150489 	/* writing VFTA */
2216735Scc210113 	mac->ops.write_vfta = e1000_write_vfta_generic;
2224919Sxy150489 	/* clearing VFTA */
2236735Scc210113 	mac->ops.clear_vfta = e1000_clear_vfta_generic;
2244919Sxy150489 	/* setting MTA */
2256735Scc210113 	mac->ops.mta_set = e1000_mta_set_generic;
2264919Sxy150489 	/* setup LED */
2276735Scc210113 	mac->ops.setup_led = e1000_setup_led_generic;
2284919Sxy150489 	/* cleanup LED */
2296735Scc210113 	mac->ops.cleanup_led = e1000_cleanup_led_generic;
2304919Sxy150489 	/* turn on/off LED */
2316735Scc210113 	mac->ops.led_on = e1000_led_on_generic;
2326735Scc210113 	mac->ops.led_off = e1000_led_off_generic;
2334919Sxy150489 	/* clear hardware counters */
2346735Scc210113 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_82540;
2354919Sxy150489 
2364919Sxy150489 out:
2374919Sxy150489 	return (ret_val);
2384919Sxy150489 }
2394919Sxy150489 
2404919Sxy150489 /*
2414919Sxy150489  * e1000_init_function_pointers_82540 - Init func ptrs.
2424919Sxy150489  * @hw: pointer to the HW structure
2434919Sxy150489  *
244*8479SChenlu.Chen@Sun.COM  * Called to initialize all function pointers and parameters.
2454919Sxy150489  */
2464919Sxy150489 void
2474919Sxy150489 e1000_init_function_pointers_82540(struct e1000_hw *hw)
2484919Sxy150489 {
2494919Sxy150489 	DEBUGFUNC("e1000_init_function_pointers_82540");
2504919Sxy150489 
2516735Scc210113 	hw->mac.ops.init_params = e1000_init_mac_params_82540;
2526735Scc210113 	hw->nvm.ops.init_params = e1000_init_nvm_params_82540;
2536735Scc210113 	hw->phy.ops.init_params = e1000_init_phy_params_82540;
2544919Sxy150489 }
2554919Sxy150489 
2564919Sxy150489 /*
2576735Scc210113  *  e1000_reset_hw_82540 - Reset hardware
2586735Scc210113  *  @hw: pointer to the HW structure
2594919Sxy150489  *
260*8479SChenlu.Chen@Sun.COM  *  This resets the hardware into a known state.
2614919Sxy150489  */
2624919Sxy150489 static s32
2634919Sxy150489 e1000_reset_hw_82540(struct e1000_hw *hw)
2644919Sxy150489 {
2657426SChenliang.Xu@Sun.COM 	u32 ctrl, manc;
2664919Sxy150489 	s32 ret_val = E1000_SUCCESS;
2674919Sxy150489 
2684919Sxy150489 	DEBUGFUNC("e1000_reset_hw_82540");
2694919Sxy150489 
2704919Sxy150489 	DEBUGOUT("Masking off all interrupts\n");
2714919Sxy150489 	E1000_WRITE_REG(hw, E1000_IMC, 0xFFFFFFFF);
2724919Sxy150489 
2734919Sxy150489 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
2744919Sxy150489 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
2754919Sxy150489 	E1000_WRITE_FLUSH(hw);
2764919Sxy150489 
2774919Sxy150489 	/*
2784919Sxy150489 	 * Delay to allow any outstanding PCI transactions to complete
2794919Sxy150489 	 * before resetting the device.
2804919Sxy150489 	 */
2814919Sxy150489 	msec_delay(10);
2824919Sxy150489 
2834919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
2844919Sxy150489 
2854919Sxy150489 	DEBUGOUT("Issuing a global reset to 82540/82545/82546 MAC\n");
2864919Sxy150489 	switch (hw->mac.type) {
2874919Sxy150489 	case e1000_82545_rev_3:
2884919Sxy150489 	case e1000_82546_rev_3:
2894919Sxy150489 		E1000_WRITE_REG(hw, E1000_CTRL_DUP, ctrl | E1000_CTRL_RST);
2904919Sxy150489 		break;
2914919Sxy150489 	default:
2924919Sxy150489 		/*
2934919Sxy150489 		 * These controllers can't ack the 64-bit write when
2944919Sxy150489 		 * issuing the reset, so we use IO-mapping as a
2954919Sxy150489 		 * workaround to issue the reset.
2964919Sxy150489 		 */
2974919Sxy150489 		E1000_WRITE_REG_IO(hw, E1000_CTRL, ctrl | E1000_CTRL_RST);
2984919Sxy150489 		break;
2994919Sxy150489 	}
3004919Sxy150489 
3014919Sxy150489 	/* Wait for EEPROM reload */
3024919Sxy150489 	msec_delay(5);
3034919Sxy150489 
3044919Sxy150489 	/* Disable HW ARPs on ASF enabled adapters */
3054919Sxy150489 	manc = E1000_READ_REG(hw, E1000_MANC);
3064919Sxy150489 	manc &= ~E1000_MANC_ARP_EN;
3074919Sxy150489 	E1000_WRITE_REG(hw, E1000_MANC, manc);
3084919Sxy150489 
3094919Sxy150489 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
3107426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_ICR);
3114919Sxy150489 
3124919Sxy150489 	return (ret_val);
3134919Sxy150489 }
3144919Sxy150489 
3154919Sxy150489 /*
3166735Scc210113  *  e1000_init_hw_82540 - Initialize hardware
3176735Scc210113  *  @hw: pointer to the HW structure
3184919Sxy150489  *
319*8479SChenlu.Chen@Sun.COM  *  This inits the hardware readying it for operation.
3204919Sxy150489  */
3214919Sxy150489 static s32
3224919Sxy150489 e1000_init_hw_82540(struct e1000_hw *hw)
3234919Sxy150489 {
3244919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
3254919Sxy150489 	u32 txdctl, ctrl_ext;
3264919Sxy150489 	s32 ret_val = E1000_SUCCESS;
3274919Sxy150489 	u16 i;
3284919Sxy150489 
3294919Sxy150489 	DEBUGFUNC("e1000_init_hw_82540");
3304919Sxy150489 
3314919Sxy150489 	/* Initialize identification LED */
3324919Sxy150489 	ret_val = e1000_id_led_init_generic(hw);
3334919Sxy150489 	if (ret_val) {
3344919Sxy150489 		DEBUGOUT("Error initializing identification LED\n");
3356735Scc210113 		/* This is not fatal and we should not stop init due to this */
3364919Sxy150489 	}
3374919Sxy150489 
3384919Sxy150489 	/* Disabling VLAN filtering */
3394919Sxy150489 	DEBUGOUT("Initializing the IEEE VLAN\n");
3404919Sxy150489 	if (mac->type < e1000_82545_rev_3)
3414919Sxy150489 		E1000_WRITE_REG(hw, E1000_VET, 0);
3424919Sxy150489 
3436735Scc210113 	mac->ops.clear_vfta(hw);
3444919Sxy150489 
3454919Sxy150489 	/* Setup the receive address. */
3464919Sxy150489 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
3474919Sxy150489 
3484919Sxy150489 	/* Zero out the Multicast HASH table */
3494919Sxy150489 	DEBUGOUT("Zeroing the MTA\n");
3504919Sxy150489 	for (i = 0; i < mac->mta_reg_count; i++) {
3514919Sxy150489 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
3524919Sxy150489 		/*
3534919Sxy150489 		 * Avoid back to back register writes by adding the register
3544919Sxy150489 		 * read (flush).  This is to protect against some strange
3554919Sxy150489 		 * bridge configurations that may issue Memory Write Block
3564919Sxy150489 		 * (MWB) to our register space.  The *_rev_3 hardware at
3574919Sxy150489 		 * least doesn't respond correctly to every other dword in an
3584919Sxy150489 		 * MWB to our register space.
3594919Sxy150489 		 */
3604919Sxy150489 		E1000_WRITE_FLUSH(hw);
3614919Sxy150489 	}
3624919Sxy150489 
3634919Sxy150489 	if (mac->type < e1000_82545_rev_3)
3644919Sxy150489 		e1000_pcix_mmrbc_workaround_generic(hw);
3654919Sxy150489 
3664919Sxy150489 	/* Setup link and flow control */
3676735Scc210113 	ret_val = mac->ops.setup_link(hw);
3684919Sxy150489 
3696735Scc210113 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
3704919Sxy150489 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
3714919Sxy150489 	    E1000_TXDCTL_FULL_TX_DESC_WB;
3726735Scc210113 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
3734919Sxy150489 
3744919Sxy150489 	/*
3754919Sxy150489 	 * Clear all of the statistics registers (clear on read).  It is
3764919Sxy150489 	 * important that we do this after we have tried to establish link
3774919Sxy150489 	 * because the symbol error count will increment wildly if there
3784919Sxy150489 	 * is no link.
3794919Sxy150489 	 */
3804919Sxy150489 	e1000_clear_hw_cntrs_82540(hw);
3814919Sxy150489 
3824919Sxy150489 	if ((hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER) ||
3834919Sxy150489 	    (hw->device_id == E1000_DEV_ID_82546GB_QUAD_COPPER_KSP3)) {
3844919Sxy150489 		ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
3854919Sxy150489 		/*
3864919Sxy150489 		 * Relaxed ordering must be disabled to avoid a parity
3874919Sxy150489 		 * error crash in a PCI slot.
3884919Sxy150489 		 */
3894919Sxy150489 		ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
3904919Sxy150489 		E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
3914919Sxy150489 	}
3924919Sxy150489 	return (ret_val);
3934919Sxy150489 }
3944919Sxy150489 
3954919Sxy150489 /*
3966735Scc210113  *  e1000_setup_copper_link_82540 - Configure copper link settings
3976735Scc210113  *  @hw: pointer to the HW structure
3984919Sxy150489  *
3996735Scc210113  *  Calls the appropriate function to configure the link for auto-neg or forced
4006735Scc210113  *  speed and duplex.  Then we check for link, once link is established calls
4016735Scc210113  *  to configure collision distance and flow control are called.  If link is
402*8479SChenlu.Chen@Sun.COM  *  not established, we return -E1000_ERR_PHY (-2).
4034919Sxy150489  */
4044919Sxy150489 static s32
4054919Sxy150489 e1000_setup_copper_link_82540(struct e1000_hw *hw)
4064919Sxy150489 {
4074919Sxy150489 	u32 ctrl;
4084919Sxy150489 	s32 ret_val = E1000_SUCCESS;
4094919Sxy150489 	u16 data;
4104919Sxy150489 
4114919Sxy150489 	DEBUGFUNC("e1000_setup_copper_link_82540");
4124919Sxy150489 
4134919Sxy150489 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
4144919Sxy150489 	ctrl |= E1000_CTRL_SLU;
4154919Sxy150489 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
4164919Sxy150489 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
4174919Sxy150489 
4184919Sxy150489 	ret_val = e1000_set_phy_mode_82540(hw);
4194919Sxy150489 	if (ret_val)
4204919Sxy150489 		goto out;
4214919Sxy150489 
4224919Sxy150489 	if (hw->mac.type == e1000_82545_rev_3 ||
4234919Sxy150489 	    hw->mac.type == e1000_82546_rev_3) {
4246735Scc210113 		ret_val =
4256735Scc210113 		    hw->phy.ops.read_reg(hw, M88E1000_PHY_SPEC_CTRL, &data);
4264919Sxy150489 		if (ret_val)
4274919Sxy150489 			goto out;
4284919Sxy150489 		data |= 0x00000008;
4296735Scc210113 		ret_val =
4306735Scc210113 		    hw->phy.ops.write_reg(hw, M88E1000_PHY_SPEC_CTRL, data);
4314919Sxy150489 		if (ret_val)
4324919Sxy150489 			goto out;
4334919Sxy150489 	}
4344919Sxy150489 	ret_val = e1000_copper_link_setup_m88(hw);
4354919Sxy150489 	if (ret_val)
4364919Sxy150489 		goto out;
4374919Sxy150489 
4384919Sxy150489 	ret_val = e1000_setup_copper_link_generic(hw);
4394919Sxy150489 
4404919Sxy150489 out:
4414919Sxy150489 	return (ret_val);
4424919Sxy150489 }
4434919Sxy150489 
4444919Sxy150489 /*
4456735Scc210113  *  e1000_setup_fiber_serdes_link_82540 - Setup link for fiber/serdes
4466735Scc210113  *  @hw: pointer to the HW structure
4474919Sxy150489  *
4486735Scc210113  *  Set the output amplitude to the value in the EEPROM and adjust the VCO
4496735Scc210113  *  speed to improve Bit Error Rate (BER) performance.  Configures collision
4506735Scc210113  *  distance and flow control for fiber and serdes links.  Upon successful
451*8479SChenlu.Chen@Sun.COM  *  setup, poll for link.
4524919Sxy150489  */
4534919Sxy150489 static s32
4544919Sxy150489 e1000_setup_fiber_serdes_link_82540(struct e1000_hw *hw)
4554919Sxy150489 {
4564919Sxy150489 	struct e1000_mac_info *mac = &hw->mac;
4574919Sxy150489 	s32 ret_val = E1000_SUCCESS;
4584919Sxy150489 
4594919Sxy150489 	DEBUGFUNC("e1000_setup_fiber_serdes_link_82540");
4604919Sxy150489 
4614919Sxy150489 	switch (mac->type) {
4624919Sxy150489 	case e1000_82545_rev_3:
4634919Sxy150489 	case e1000_82546_rev_3:
4646735Scc210113 		if (hw->phy.media_type == e1000_media_type_internal_serdes) {
4654919Sxy150489 			/*
4664919Sxy150489 			 * If we're on serdes media, adjust the output
4674919Sxy150489 			 * amplitude to value set in the EEPROM.
4684919Sxy150489 			 */
4694919Sxy150489 			ret_val = e1000_adjust_serdes_amplitude_82540(hw);
4704919Sxy150489 			if (ret_val)
4714919Sxy150489 				goto out;
4724919Sxy150489 		}
4734919Sxy150489 		/* Adjust VCO speed to improve BER performance */
4744919Sxy150489 		ret_val = e1000_set_vco_speed_82540(hw);
4754919Sxy150489 		if (ret_val)
4764919Sxy150489 			goto out;
4774919Sxy150489 	default:
4784919Sxy150489 		break;
4794919Sxy150489 	}
4804919Sxy150489 
4814919Sxy150489 	ret_val = e1000_setup_fiber_serdes_link_generic(hw);
4824919Sxy150489 
4834919Sxy150489 out:
4844919Sxy150489 	return (ret_val);
4854919Sxy150489 }
4864919Sxy150489 
4874919Sxy150489 /*
4886735Scc210113  *  e1000_adjust_serdes_amplitude_82540 - Adjust amplitude based on EEPROM
4896735Scc210113  *  @hw: pointer to the HW structure
4904919Sxy150489  *
4916735Scc210113  *  Adjust the SERDES output amplitude based on the EEPROM settings.
4924919Sxy150489  */
4934919Sxy150489 static s32
4944919Sxy150489 e1000_adjust_serdes_amplitude_82540(struct e1000_hw *hw)
4954919Sxy150489 {
4964919Sxy150489 	s32 ret_val = E1000_SUCCESS;
4974919Sxy150489 	u16 nvm_data;
4984919Sxy150489 
4994919Sxy150489 	DEBUGFUNC("e1000_adjust_serdes_amplitude_82540");
5004919Sxy150489 
5016735Scc210113 	ret_val = hw->nvm.ops.read(hw, NVM_SERDES_AMPLITUDE, 1, &nvm_data);
5024919Sxy150489 	if (ret_val)
5034919Sxy150489 		goto out;
5044919Sxy150489 
5054919Sxy150489 	if (nvm_data != NVM_RESERVED_WORD) {
5064919Sxy150489 		/* Adjust serdes output amplitude only. */
5074919Sxy150489 		nvm_data &= NVM_SERDES_AMPLITUDE_MASK;
5086735Scc210113 		ret_val = hw->phy.ops.write_reg(hw,
5094919Sxy150489 		    M88E1000_PHY_EXT_CTRL,
5104919Sxy150489 		    nvm_data);
5114919Sxy150489 		if (ret_val)
5124919Sxy150489 			goto out;
5134919Sxy150489 	}
5144919Sxy150489 out:
5154919Sxy150489 	return (ret_val);
5164919Sxy150489 }
5174919Sxy150489 
5184919Sxy150489 /*
5196735Scc210113  *  e1000_set_vco_speed_82540 - Set VCO speed for better performance
5206735Scc210113  *  @hw: pointer to the HW structure
5214919Sxy150489  *
5226735Scc210113  *  Set the VCO speed to improve Bit Error Rate (BER) performance.
5234919Sxy150489  */
5244919Sxy150489 static s32
5254919Sxy150489 e1000_set_vco_speed_82540(struct e1000_hw *hw)
5264919Sxy150489 {
5274919Sxy150489 	s32 ret_val = E1000_SUCCESS;
5284919Sxy150489 	u16 default_page = 0;
5294919Sxy150489 	u16 phy_data;
5304919Sxy150489 
5314919Sxy150489 	DEBUGFUNC("e1000_set_vco_speed_82540");
5324919Sxy150489 
5334919Sxy150489 	/* Set PHY register 30, page 5, bit 8 to 0 */
5344919Sxy150489 
5356735Scc210113 	ret_val = hw->phy.ops.read_reg(hw,
5364919Sxy150489 	    M88E1000_PHY_PAGE_SELECT,
5374919Sxy150489 	    &default_page);
5384919Sxy150489 	if (ret_val)
5394919Sxy150489 		goto out;
5404919Sxy150489 
5416735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0005);
5424919Sxy150489 	if (ret_val)
5434919Sxy150489 		goto out;
5444919Sxy150489 
5456735Scc210113 	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
5464919Sxy150489 	if (ret_val)
5474919Sxy150489 		goto out;
5484919Sxy150489 
5494919Sxy150489 	phy_data &= ~M88E1000_PHY_VCO_REG_BIT8;
5506735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
5514919Sxy150489 	if (ret_val)
5524919Sxy150489 		goto out;
5534919Sxy150489 
5544919Sxy150489 	/* Set PHY register 30, page 4, bit 11 to 1 */
5554919Sxy150489 
5566735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT, 0x0004);
5574919Sxy150489 	if (ret_val)
5584919Sxy150489 		goto out;
5594919Sxy150489 
5606735Scc210113 	ret_val = hw->phy.ops.read_reg(hw, M88E1000_PHY_GEN_CONTROL, &phy_data);
5614919Sxy150489 	if (ret_val)
5624919Sxy150489 		goto out;
5634919Sxy150489 
5644919Sxy150489 	phy_data |= M88E1000_PHY_VCO_REG_BIT11;
5656735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_GEN_CONTROL, phy_data);
5664919Sxy150489 	if (ret_val)
5674919Sxy150489 		goto out;
5684919Sxy150489 
5696735Scc210113 	ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
5704919Sxy150489 	    default_page);
5714919Sxy150489 
5724919Sxy150489 out:
5734919Sxy150489 	return (ret_val);
5744919Sxy150489 }
5754919Sxy150489 
5764919Sxy150489 /*
5776735Scc210113  *  e1000_set_phy_mode_82540 - Set PHY to class A mode
5786735Scc210113  *  @hw: pointer to the HW structure
5794919Sxy150489  *
5806735Scc210113  *  Sets the PHY to class A mode and assumes the following operations will
5816735Scc210113  *  follow to enable the new class mode:
5826735Scc210113  *    1.  Do a PHY soft reset.
5836735Scc210113  *    2.  Restart auto-negotiation or force link.
5844919Sxy150489  */
5854919Sxy150489 static s32
5864919Sxy150489 e1000_set_phy_mode_82540(struct e1000_hw *hw)
5874919Sxy150489 {
5884919Sxy150489 	struct e1000_phy_info *phy = &hw->phy;
5894919Sxy150489 	s32 ret_val = E1000_SUCCESS;
5904919Sxy150489 	u16 nvm_data;
5914919Sxy150489 
5924919Sxy150489 	DEBUGFUNC("e1000_set_phy_mode_82540");
5934919Sxy150489 
5944919Sxy150489 	if (hw->mac.type != e1000_82545_rev_3)
5954919Sxy150489 		goto out;
5964919Sxy150489 
5976735Scc210113 	ret_val = hw->nvm.ops.read(hw, NVM_PHY_CLASS_WORD, 1, &nvm_data);
5984919Sxy150489 	if (ret_val) {
5994919Sxy150489 		ret_val = -E1000_ERR_PHY;
6004919Sxy150489 		goto out;
6014919Sxy150489 	}
6024919Sxy150489 
6034919Sxy150489 	if ((nvm_data != NVM_RESERVED_WORD) && (nvm_data & NVM_PHY_CLASS_A)) {
6046735Scc210113 		ret_val = hw->phy.ops.write_reg(hw, M88E1000_PHY_PAGE_SELECT,
6054919Sxy150489 		    0x000B);
6064919Sxy150489 		if (ret_val) {
6074919Sxy150489 			ret_val = -E1000_ERR_PHY;
6084919Sxy150489 			goto out;
6094919Sxy150489 		}
6106735Scc210113 		ret_val = hw->phy.ops.write_reg(hw,
6114919Sxy150489 		    M88E1000_PHY_GEN_CONTROL,
6124919Sxy150489 		    0x8104);
6134919Sxy150489 		if (ret_val) {
6144919Sxy150489 			ret_val = -E1000_ERR_PHY;
6154919Sxy150489 			goto out;
6164919Sxy150489 		}
6174919Sxy150489 
6187607STed.You@Sun.COM 		phy->reset_disable = false;
6194919Sxy150489 	}
6204919Sxy150489 
6214919Sxy150489 out:
6224919Sxy150489 	return (ret_val);
6234919Sxy150489 }
6244919Sxy150489 
6254919Sxy150489 /*
6266735Scc210113  * e1000_power_down_phy_copper_82540 - Remove link in case of PHY power down
6274919Sxy150489  * @hw: pointer to the HW structure
6284919Sxy150489  *
6296735Scc210113  * In the case of a PHY power down to save power, or to turn off link during a
6306735Scc210113  * driver unload, or wake on lan is not enabled, remove the link.
6316735Scc210113  */
6326735Scc210113 static void
6336735Scc210113 e1000_power_down_phy_copper_82540(struct e1000_hw *hw)
6346735Scc210113 {
6356735Scc210113 	/* If the management interface is not enabled, then power down */
6366735Scc210113 	if (!(E1000_READ_REG(hw, E1000_MANC) & E1000_MANC_SMBUS_EN))
6376735Scc210113 		e1000_power_down_phy_copper(hw);
6386735Scc210113 }
6396735Scc210113 
6406735Scc210113 /*
6416735Scc210113  *  e1000_clear_hw_cntrs_82540 - Clear device specific hardware counters
6426735Scc210113  *  @hw: pointer to the HW structure
6436735Scc210113  *
6446735Scc210113  *  Clears the hardware counters by reading the counter registers.
6454919Sxy150489  */
6464919Sxy150489 static void
6474919Sxy150489 e1000_clear_hw_cntrs_82540(struct e1000_hw *hw)
6484919Sxy150489 {
6494919Sxy150489 	DEBUGFUNC("e1000_clear_hw_cntrs_82540");
6504919Sxy150489 
6514919Sxy150489 	e1000_clear_hw_cntrs_base_generic(hw);
6524919Sxy150489 
6537426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC64);
6547426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC127);
6557426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC255);
6567426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC511);
6577426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC1023);
6587426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PRC1522);
6597426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC64);
6607426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC127);
6617426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC255);
6627426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC511);
6637426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC1023);
6647426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_PTC1522);
6654919Sxy150489 
6667426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_ALGNERRC);
6677426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_RXERRC);
6687426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TNCRS);
6697426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_CEXTERR);
6707426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TSCTC);
6717426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_TSCTFC);
6724919Sxy150489 
6737426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPRC);
6747426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPDC);
6757426SChenliang.Xu@Sun.COM 	(void) E1000_READ_REG(hw, E1000_MGTPTC);
6764919Sxy150489 }
677