xref: /freebsd/sys/dev/e1000/e1000_ich8lan.c (revision 9d81738f8f543736fc9da9cf1622b381fec98361)
18cfa0ad2SJack F Vogel /******************************************************************************
28cfa0ad2SJack F Vogel 
3d035aa2dSJack F Vogel   Copyright (c) 2001-2009, Intel Corporation
48cfa0ad2SJack F Vogel   All rights reserved.
58cfa0ad2SJack F Vogel 
68cfa0ad2SJack F Vogel   Redistribution and use in source and binary forms, with or without
78cfa0ad2SJack F Vogel   modification, are permitted provided that the following conditions are met:
88cfa0ad2SJack F Vogel 
98cfa0ad2SJack F Vogel    1. Redistributions of source code must retain the above copyright notice,
108cfa0ad2SJack F Vogel       this list of conditions and the following disclaimer.
118cfa0ad2SJack F Vogel 
128cfa0ad2SJack F Vogel    2. Redistributions in binary form must reproduce the above copyright
138cfa0ad2SJack F Vogel       notice, this list of conditions and the following disclaimer in the
148cfa0ad2SJack F Vogel       documentation and/or other materials provided with the distribution.
158cfa0ad2SJack F Vogel 
168cfa0ad2SJack F Vogel    3. Neither the name of the Intel Corporation nor the names of its
178cfa0ad2SJack F Vogel       contributors may be used to endorse or promote products derived from
188cfa0ad2SJack F Vogel       this software without specific prior written permission.
198cfa0ad2SJack F Vogel 
208cfa0ad2SJack F Vogel   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
218cfa0ad2SJack F Vogel   AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
228cfa0ad2SJack F Vogel   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
238cfa0ad2SJack F Vogel   ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
248cfa0ad2SJack F Vogel   LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
258cfa0ad2SJack F Vogel   CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
268cfa0ad2SJack F Vogel   SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
278cfa0ad2SJack F Vogel   INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
288cfa0ad2SJack F Vogel   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
298cfa0ad2SJack F Vogel   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
308cfa0ad2SJack F Vogel   POSSIBILITY OF SUCH DAMAGE.
318cfa0ad2SJack F Vogel 
328cfa0ad2SJack F Vogel ******************************************************************************/
338cfa0ad2SJack F Vogel /*$FreeBSD$*/
348cfa0ad2SJack F Vogel 
35daf9197cSJack F Vogel /*
36daf9197cSJack F Vogel  * 82562G 10/100 Network Connection
37daf9197cSJack F Vogel  * 82562G-2 10/100 Network Connection
38daf9197cSJack F Vogel  * 82562GT 10/100 Network Connection
39daf9197cSJack F Vogel  * 82562GT-2 10/100 Network Connection
40daf9197cSJack F Vogel  * 82562V 10/100 Network Connection
41daf9197cSJack F Vogel  * 82562V-2 10/100 Network Connection
42daf9197cSJack F Vogel  * 82566DC-2 Gigabit Network Connection
43daf9197cSJack F Vogel  * 82566DC Gigabit Network Connection
44daf9197cSJack F Vogel  * 82566DM-2 Gigabit Network Connection
45daf9197cSJack F Vogel  * 82566DM Gigabit Network Connection
46daf9197cSJack F Vogel  * 82566MC Gigabit Network Connection
47daf9197cSJack F Vogel  * 82566MM Gigabit Network Connection
48daf9197cSJack F Vogel  * 82567LM Gigabit Network Connection
49daf9197cSJack F Vogel  * 82567LF Gigabit Network Connection
50daf9197cSJack F Vogel  * 82567V Gigabit Network Connection
51daf9197cSJack F Vogel  * 82567LM-2 Gigabit Network Connection
52daf9197cSJack F Vogel  * 82567LF-2 Gigabit Network Connection
53daf9197cSJack F Vogel  * 82567V-2 Gigabit Network Connection
54daf9197cSJack F Vogel  * 82567LF-3 Gigabit Network Connection
55daf9197cSJack F Vogel  * 82567LM-3 Gigabit Network Connection
56daf9197cSJack F Vogel  * 82567LM-4 Gigabit Network Connection
579d81738fSJack F Vogel  * 82577LM Gigabit Network Connection
589d81738fSJack F Vogel  * 82577LC Gigabit Network Connection
599d81738fSJack F Vogel  * 82578DM Gigabit Network Connection
609d81738fSJack F Vogel  * 82578DC Gigabit Network Connection
618cfa0ad2SJack F Vogel  */
628cfa0ad2SJack F Vogel 
638cfa0ad2SJack F Vogel #include "e1000_api.h"
648cfa0ad2SJack F Vogel 
658cfa0ad2SJack F Vogel static s32  e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
669d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
678cfa0ad2SJack F Vogel static s32  e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
688cfa0ad2SJack F Vogel static s32  e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
698cfa0ad2SJack F Vogel static s32  e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
708cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
718cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
728cfa0ad2SJack F Vogel static s32  e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
738cfa0ad2SJack F Vogel static s32  e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
748cfa0ad2SJack F Vogel static s32  e1000_get_phy_info_ich8lan(struct e1000_hw *hw);
758cfa0ad2SJack F Vogel static s32  e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
768cfa0ad2SJack F Vogel                                             bool active);
778cfa0ad2SJack F Vogel static s32  e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
788cfa0ad2SJack F Vogel                                             bool active);
798cfa0ad2SJack F Vogel static s32  e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
808cfa0ad2SJack F Vogel                                    u16 words, u16 *data);
818cfa0ad2SJack F Vogel static s32  e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
828cfa0ad2SJack F Vogel                                     u16 words, u16 *data);
838cfa0ad2SJack F Vogel static s32  e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
848cfa0ad2SJack F Vogel static s32  e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
858cfa0ad2SJack F Vogel static s32  e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
868cfa0ad2SJack F Vogel                                             u16 *data);
879d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
888cfa0ad2SJack F Vogel static s32  e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
898cfa0ad2SJack F Vogel static s32  e1000_reset_hw_ich8lan(struct e1000_hw *hw);
908cfa0ad2SJack F Vogel static s32  e1000_init_hw_ich8lan(struct e1000_hw *hw);
918cfa0ad2SJack F Vogel static s32  e1000_setup_link_ich8lan(struct e1000_hw *hw);
928cfa0ad2SJack F Vogel static s32  e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
938cfa0ad2SJack F Vogel static s32  e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
948cfa0ad2SJack F Vogel                                            u16 *speed, u16 *duplex);
958cfa0ad2SJack F Vogel static s32  e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
968cfa0ad2SJack F Vogel static s32  e1000_led_on_ich8lan(struct e1000_hw *hw);
978cfa0ad2SJack F Vogel static s32  e1000_led_off_ich8lan(struct e1000_hw *hw);
989d81738fSJack F Vogel static s32  e1000_setup_led_pchlan(struct e1000_hw *hw);
999d81738fSJack F Vogel static s32  e1000_cleanup_led_pchlan(struct e1000_hw *hw);
1009d81738fSJack F Vogel static s32  e1000_led_on_pchlan(struct e1000_hw *hw);
1019d81738fSJack F Vogel static s32  e1000_led_off_pchlan(struct e1000_hw *hw);
1028cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1038cfa0ad2SJack F Vogel static s32  e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1048cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
1058cfa0ad2SJack F Vogel static s32  e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
1068cfa0ad2SJack F Vogel static s32  e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
1078cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1088cfa0ad2SJack F Vogel static s32  e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1098cfa0ad2SJack F Vogel static s32  e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1108cfa0ad2SJack F Vogel                                           u32 offset, u8 *data);
1118cfa0ad2SJack F Vogel static s32  e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1128cfa0ad2SJack F Vogel                                           u8 size, u16 *data);
1138cfa0ad2SJack F Vogel static s32  e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1148cfa0ad2SJack F Vogel                                           u32 offset, u16 *data);
1158cfa0ad2SJack F Vogel static s32  e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1168cfa0ad2SJack F Vogel                                                  u32 offset, u8 byte);
1178cfa0ad2SJack F Vogel static s32  e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
1188cfa0ad2SJack F Vogel                                            u32 offset, u8 data);
1198cfa0ad2SJack F Vogel static s32  e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1208cfa0ad2SJack F Vogel                                            u8 size, u16 data);
1218cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1228cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
1238cfa0ad2SJack F Vogel 
1248cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1258cfa0ad2SJack F Vogel /* Offset 04h HSFSTS */
1268cfa0ad2SJack F Vogel union ich8_hws_flash_status {
1278cfa0ad2SJack F Vogel 	struct ich8_hsfsts {
1288cfa0ad2SJack F Vogel 		u16 flcdone    :1; /* bit 0 Flash Cycle Done */
1298cfa0ad2SJack F Vogel 		u16 flcerr     :1; /* bit 1 Flash Cycle Error */
1308cfa0ad2SJack F Vogel 		u16 dael       :1; /* bit 2 Direct Access error Log */
1318cfa0ad2SJack F Vogel 		u16 berasesz   :2; /* bit 4:3 Sector Erase Size */
1328cfa0ad2SJack F Vogel 		u16 flcinprog  :1; /* bit 5 flash cycle in Progress */
1338cfa0ad2SJack F Vogel 		u16 reserved1  :2; /* bit 13:6 Reserved */
1348cfa0ad2SJack F Vogel 		u16 reserved2  :6; /* bit 13:6 Reserved */
1358cfa0ad2SJack F Vogel 		u16 fldesvalid :1; /* bit 14 Flash Descriptor Valid */
1368cfa0ad2SJack F Vogel 		u16 flockdn    :1; /* bit 15 Flash Config Lock-Down */
1378cfa0ad2SJack F Vogel 	} hsf_status;
1388cfa0ad2SJack F Vogel 	u16 regval;
1398cfa0ad2SJack F Vogel };
1408cfa0ad2SJack F Vogel 
1418cfa0ad2SJack F Vogel /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1428cfa0ad2SJack F Vogel /* Offset 06h FLCTL */
1438cfa0ad2SJack F Vogel union ich8_hws_flash_ctrl {
1448cfa0ad2SJack F Vogel 	struct ich8_hsflctl {
1458cfa0ad2SJack F Vogel 		u16 flcgo      :1;   /* 0 Flash Cycle Go */
1468cfa0ad2SJack F Vogel 		u16 flcycle    :2;   /* 2:1 Flash Cycle */
1478cfa0ad2SJack F Vogel 		u16 reserved   :5;   /* 7:3 Reserved  */
1488cfa0ad2SJack F Vogel 		u16 fldbcount  :2;   /* 9:8 Flash Data Byte Count */
1498cfa0ad2SJack F Vogel 		u16 flockdn    :6;   /* 15:10 Reserved */
1508cfa0ad2SJack F Vogel 	} hsf_ctrl;
1518cfa0ad2SJack F Vogel 	u16 regval;
1528cfa0ad2SJack F Vogel };
1538cfa0ad2SJack F Vogel 
1548cfa0ad2SJack F Vogel /* ICH Flash Region Access Permissions */
1558cfa0ad2SJack F Vogel union ich8_hws_flash_regacc {
1568cfa0ad2SJack F Vogel 	struct ich8_flracc {
1578cfa0ad2SJack F Vogel 		u32 grra      :8; /* 0:7 GbE region Read Access */
1588cfa0ad2SJack F Vogel 		u32 grwa      :8; /* 8:15 GbE region Write Access */
1598cfa0ad2SJack F Vogel 		u32 gmrag     :8; /* 23:16 GbE Master Read Access Grant */
1608cfa0ad2SJack F Vogel 		u32 gmwag     :8; /* 31:24 GbE Master Write Access Grant */
1618cfa0ad2SJack F Vogel 	} hsf_flregacc;
1628cfa0ad2SJack F Vogel 	u16 regval;
1638cfa0ad2SJack F Vogel };
1648cfa0ad2SJack F Vogel 
1658cfa0ad2SJack F Vogel /**
1669d81738fSJack F Vogel  *  e1000_init_phy_params_pchlan - Initialize PHY function pointers
1679d81738fSJack F Vogel  *  @hw: pointer to the HW structure
1689d81738fSJack F Vogel  *
1699d81738fSJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
1709d81738fSJack F Vogel  **/
1719d81738fSJack F Vogel static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw)
1729d81738fSJack F Vogel {
1739d81738fSJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
1749d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
1759d81738fSJack F Vogel 
1769d81738fSJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_pchlan");
1779d81738fSJack F Vogel 
1789d81738fSJack F Vogel 	phy->addr                     = 1;
1799d81738fSJack F Vogel 	phy->reset_delay_us           = 100;
1809d81738fSJack F Vogel 
1819d81738fSJack F Vogel 	phy->ops.acquire              = e1000_acquire_swflag_ich8lan;
1829d81738fSJack F Vogel 	phy->ops.check_polarity       = e1000_check_polarity_ife;
1839d81738fSJack F Vogel 	phy->ops.check_reset_block    = e1000_check_reset_block_ich8lan;
1849d81738fSJack F Vogel 	phy->ops.force_speed_duplex   = e1000_phy_force_speed_duplex_ife;
1859d81738fSJack F Vogel 	phy->ops.get_cable_length     = e1000_get_cable_length_igp_2;
1869d81738fSJack F Vogel 	phy->ops.get_cfg_done         = e1000_get_cfg_done_ich8lan;
1879d81738fSJack F Vogel 	phy->ops.get_info             = e1000_get_phy_info_ich8lan;
1889d81738fSJack F Vogel 	phy->ops.read_reg             = e1000_read_phy_reg_hv;
1899d81738fSJack F Vogel 	phy->ops.release              = e1000_release_swflag_ich8lan;
1909d81738fSJack F Vogel 	phy->ops.reset                = e1000_phy_hw_reset_ich8lan;
1919d81738fSJack F Vogel 	phy->ops.set_d0_lplu_state    = e1000_set_d0_lplu_state_ich8lan;
1929d81738fSJack F Vogel 	phy->ops.set_d3_lplu_state    = e1000_set_d3_lplu_state_ich8lan;
1939d81738fSJack F Vogel 	phy->ops.write_reg            = e1000_write_phy_reg_hv;
1949d81738fSJack F Vogel 	phy->ops.power_up             = e1000_power_up_phy_copper;
1959d81738fSJack F Vogel 	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
1969d81738fSJack F Vogel 	phy->autoneg_mask             = AUTONEG_ADVERTISE_SPEED_DEFAULT;
1979d81738fSJack F Vogel 
1989d81738fSJack F Vogel 	phy->id = e1000_phy_unknown;
1999d81738fSJack F Vogel 	e1000_get_phy_id(hw);
2009d81738fSJack F Vogel 	phy->type = e1000_get_phy_type_from_id(phy->id);
2019d81738fSJack F Vogel 
2029d81738fSJack F Vogel 	if (phy->type == e1000_phy_82577) {
2039d81738fSJack F Vogel 		phy->ops.check_polarity = e1000_check_polarity_82577;
2049d81738fSJack F Vogel 		phy->ops.force_speed_duplex =
2059d81738fSJack F Vogel 			e1000_phy_force_speed_duplex_82577;
2069d81738fSJack F Vogel 		phy->ops.get_cable_length   = e1000_get_cable_length_82577;
2079d81738fSJack F Vogel 		phy->ops.get_info = e1000_get_phy_info_82577;
2089d81738fSJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
2099d81738fSJack F Vogel 	}
2109d81738fSJack F Vogel 
2119d81738fSJack F Vogel 	return ret_val;
2129d81738fSJack F Vogel }
2139d81738fSJack F Vogel 
2149d81738fSJack F Vogel /**
2158cfa0ad2SJack F Vogel  *  e1000_init_phy_params_ich8lan - Initialize PHY function pointers
2168cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
2178cfa0ad2SJack F Vogel  *
2188cfa0ad2SJack F Vogel  *  Initialize family-specific PHY parameters and function pointers.
2198cfa0ad2SJack F Vogel  **/
2208cfa0ad2SJack F Vogel static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
2218cfa0ad2SJack F Vogel {
2228cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
2238cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
2248cfa0ad2SJack F Vogel 	u16 i = 0;
2258cfa0ad2SJack F Vogel 
2268cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_phy_params_ich8lan");
2278cfa0ad2SJack F Vogel 
2288cfa0ad2SJack F Vogel 	phy->addr                     = 1;
2298cfa0ad2SJack F Vogel 	phy->reset_delay_us           = 100;
2308cfa0ad2SJack F Vogel 
2318cfa0ad2SJack F Vogel 	phy->ops.acquire              = e1000_acquire_swflag_ich8lan;
2329d81738fSJack F Vogel 	phy->ops.check_polarity       = e1000_check_polarity_ife;
2338cfa0ad2SJack F Vogel 	phy->ops.check_reset_block    = e1000_check_reset_block_ich8lan;
2349d81738fSJack F Vogel 	phy->ops.force_speed_duplex   = e1000_phy_force_speed_duplex_ife;
2358cfa0ad2SJack F Vogel 	phy->ops.get_cable_length     = e1000_get_cable_length_igp_2;
2368cfa0ad2SJack F Vogel 	phy->ops.get_cfg_done         = e1000_get_cfg_done_ich8lan;
2378cfa0ad2SJack F Vogel 	phy->ops.get_info             = e1000_get_phy_info_ich8lan;
2388cfa0ad2SJack F Vogel 	phy->ops.read_reg             = e1000_read_phy_reg_igp;
2398cfa0ad2SJack F Vogel 	phy->ops.release              = e1000_release_swflag_ich8lan;
2408cfa0ad2SJack F Vogel 	phy->ops.reset                = e1000_phy_hw_reset_ich8lan;
2418cfa0ad2SJack F Vogel 	phy->ops.set_d0_lplu_state    = e1000_set_d0_lplu_state_ich8lan;
2428cfa0ad2SJack F Vogel 	phy->ops.set_d3_lplu_state    = e1000_set_d3_lplu_state_ich8lan;
2438cfa0ad2SJack F Vogel 	phy->ops.write_reg            = e1000_write_phy_reg_igp;
2448cfa0ad2SJack F Vogel 	phy->ops.power_up             = e1000_power_up_phy_copper;
2458cfa0ad2SJack F Vogel 	phy->ops.power_down           = e1000_power_down_phy_copper_ich8lan;
2468cfa0ad2SJack F Vogel 
2478cfa0ad2SJack F Vogel 	/*
2488cfa0ad2SJack F Vogel 	 * We may need to do this twice - once for IGP and if that fails,
2498cfa0ad2SJack F Vogel 	 * we'll set BM func pointers and try again
2508cfa0ad2SJack F Vogel 	 */
2518cfa0ad2SJack F Vogel 	ret_val = e1000_determine_phy_address(hw);
2528cfa0ad2SJack F Vogel 	if (ret_val) {
2538cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
2548cfa0ad2SJack F Vogel 		phy->ops.read_reg  = e1000_read_phy_reg_bm;
2558cfa0ad2SJack F Vogel 		ret_val = e1000_determine_phy_address(hw);
2568cfa0ad2SJack F Vogel 		if (ret_val) {
257d035aa2dSJack F Vogel 			DEBUGOUT("Cannot determine PHY addr. Erroring out\n");
2588cfa0ad2SJack F Vogel 			goto out;
2598cfa0ad2SJack F Vogel 		}
2608cfa0ad2SJack F Vogel 	}
2618cfa0ad2SJack F Vogel 
2628cfa0ad2SJack F Vogel 	phy->id = 0;
2638cfa0ad2SJack F Vogel 	while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
2648cfa0ad2SJack F Vogel 	       (i++ < 100)) {
2658cfa0ad2SJack F Vogel 		msec_delay(1);
2668cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_id(hw);
2678cfa0ad2SJack F Vogel 		if (ret_val)
2688cfa0ad2SJack F Vogel 			goto out;
2698cfa0ad2SJack F Vogel 	}
2708cfa0ad2SJack F Vogel 
2718cfa0ad2SJack F Vogel 	/* Verify phy id */
2728cfa0ad2SJack F Vogel 	switch (phy->id) {
2738cfa0ad2SJack F Vogel 	case IGP03E1000_E_PHY_ID:
2748cfa0ad2SJack F Vogel 		phy->type = e1000_phy_igp_3;
2758cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
2768cfa0ad2SJack F Vogel 		break;
2778cfa0ad2SJack F Vogel 	case IFE_E_PHY_ID:
2788cfa0ad2SJack F Vogel 	case IFE_PLUS_E_PHY_ID:
2798cfa0ad2SJack F Vogel 	case IFE_C_E_PHY_ID:
2808cfa0ad2SJack F Vogel 		phy->type = e1000_phy_ife;
2818cfa0ad2SJack F Vogel 		phy->autoneg_mask = E1000_ALL_NOT_GIG;
2828cfa0ad2SJack F Vogel 		break;
2838cfa0ad2SJack F Vogel 	case BME1000_E_PHY_ID:
2848cfa0ad2SJack F Vogel 		phy->type = e1000_phy_bm;
2858cfa0ad2SJack F Vogel 		phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
2868cfa0ad2SJack F Vogel 		phy->ops.read_reg = e1000_read_phy_reg_bm;
2878cfa0ad2SJack F Vogel 		phy->ops.write_reg = e1000_write_phy_reg_bm;
2888cfa0ad2SJack F Vogel 		phy->ops.commit = e1000_phy_sw_reset_generic;
2898cfa0ad2SJack F Vogel 		break;
2908cfa0ad2SJack F Vogel 	default:
2918cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_PHY;
2928cfa0ad2SJack F Vogel 		goto out;
2938cfa0ad2SJack F Vogel 	}
2948cfa0ad2SJack F Vogel 
2958cfa0ad2SJack F Vogel out:
2968cfa0ad2SJack F Vogel 	return ret_val;
2978cfa0ad2SJack F Vogel }
2988cfa0ad2SJack F Vogel 
2998cfa0ad2SJack F Vogel /**
3008cfa0ad2SJack F Vogel  *  e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
3018cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3028cfa0ad2SJack F Vogel  *
3038cfa0ad2SJack F Vogel  *  Initialize family-specific NVM parameters and function
3048cfa0ad2SJack F Vogel  *  pointers.
3058cfa0ad2SJack F Vogel  **/
3068cfa0ad2SJack F Vogel static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
3078cfa0ad2SJack F Vogel {
3088cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
309daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3109d81738fSJack F Vogel 	union ich8_hws_flash_status hsfsts;
3118cfa0ad2SJack F Vogel 	u32 gfpreg, sector_base_addr, sector_end_addr;
3128cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
3138cfa0ad2SJack F Vogel 	u16 i;
3148cfa0ad2SJack F Vogel 
3158cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_nvm_params_ich8lan");
3168cfa0ad2SJack F Vogel 
3178cfa0ad2SJack F Vogel 	/* Can't read flash registers if the register set isn't mapped. */
3188cfa0ad2SJack F Vogel 	if (!hw->flash_address) {
3198cfa0ad2SJack F Vogel 		DEBUGOUT("ERROR: Flash registers not mapped\n");
3208cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
3218cfa0ad2SJack F Vogel 		goto out;
3228cfa0ad2SJack F Vogel 	}
3238cfa0ad2SJack F Vogel 
3248cfa0ad2SJack F Vogel 	nvm->type = e1000_nvm_flash_sw;
3258cfa0ad2SJack F Vogel 
3268cfa0ad2SJack F Vogel 	gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
3278cfa0ad2SJack F Vogel 
3288cfa0ad2SJack F Vogel 	/*
3298cfa0ad2SJack F Vogel 	 * sector_X_addr is a "sector"-aligned address (4096 bytes)
3308cfa0ad2SJack F Vogel 	 * Add 1 to sector_end_addr since this sector is included in
3318cfa0ad2SJack F Vogel 	 * the overall size.
3328cfa0ad2SJack F Vogel 	 */
3338cfa0ad2SJack F Vogel 	sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
3348cfa0ad2SJack F Vogel 	sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
3358cfa0ad2SJack F Vogel 
3368cfa0ad2SJack F Vogel 	/* flash_base_addr is byte-aligned */
3378cfa0ad2SJack F Vogel 	nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
3388cfa0ad2SJack F Vogel 
3398cfa0ad2SJack F Vogel 	/*
3408cfa0ad2SJack F Vogel 	 * find total size of the NVM, then cut in half since the total
3418cfa0ad2SJack F Vogel 	 * size represents two separate NVM banks.
3428cfa0ad2SJack F Vogel 	 */
3438cfa0ad2SJack F Vogel 	nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
3448cfa0ad2SJack F Vogel 	                          << FLASH_SECTOR_ADDR_SHIFT;
3458cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= 2;
3468cfa0ad2SJack F Vogel 	/* Adjust to word count */
3478cfa0ad2SJack F Vogel 	nvm->flash_bank_size /= sizeof(u16);
3488cfa0ad2SJack F Vogel 
3499d81738fSJack F Vogel 	/*
3509d81738fSJack F Vogel 	 * Make sure the flash bank size does not overwrite the 4k
3519d81738fSJack F Vogel 	 * sector ranges. We may have 64k allotted to us but we only care
3529d81738fSJack F Vogel 	 * about the first 2 4k sectors. Therefore, if we have anything less
3539d81738fSJack F Vogel 	 * than 64k set in the HSFSTS register, we will reduce the bank size
3549d81738fSJack F Vogel 	 * down to 4k and let the rest remain unused. If berasesz == 3, then
3559d81738fSJack F Vogel 	 * we are working in 64k mode. Otherwise we are not.
3569d81738fSJack F Vogel 	 */
3579d81738fSJack F Vogel 	if (nvm->flash_bank_size > E1000_SHADOW_RAM_WORDS) {
3589d81738fSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
3599d81738fSJack F Vogel 		if (hsfsts.hsf_status.berasesz != 3)
3609d81738fSJack F Vogel 			nvm->flash_bank_size = E1000_SHADOW_RAM_WORDS;
3619d81738fSJack F Vogel 	}
3629d81738fSJack F Vogel 
3638cfa0ad2SJack F Vogel 	nvm->word_size = E1000_SHADOW_RAM_WORDS;
3648cfa0ad2SJack F Vogel 
3658cfa0ad2SJack F Vogel 	/* Clear shadow ram */
3668cfa0ad2SJack F Vogel 	for (i = 0; i < nvm->word_size; i++) {
3678cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
3688cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value    = 0xFFFF;
3698cfa0ad2SJack F Vogel 	}
3708cfa0ad2SJack F Vogel 
3718cfa0ad2SJack F Vogel 	/* Function Pointers */
3728cfa0ad2SJack F Vogel 	nvm->ops.acquire       = e1000_acquire_swflag_ich8lan;
3738cfa0ad2SJack F Vogel 	nvm->ops.read          = e1000_read_nvm_ich8lan;
3748cfa0ad2SJack F Vogel 	nvm->ops.release       = e1000_release_swflag_ich8lan;
3758cfa0ad2SJack F Vogel 	nvm->ops.update        = e1000_update_nvm_checksum_ich8lan;
3768cfa0ad2SJack F Vogel 	nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
3778cfa0ad2SJack F Vogel 	nvm->ops.validate      = e1000_validate_nvm_checksum_ich8lan;
3788cfa0ad2SJack F Vogel 	nvm->ops.write         = e1000_write_nvm_ich8lan;
3798cfa0ad2SJack F Vogel 
3808cfa0ad2SJack F Vogel out:
3818cfa0ad2SJack F Vogel 	return ret_val;
3828cfa0ad2SJack F Vogel }
3838cfa0ad2SJack F Vogel 
3848cfa0ad2SJack F Vogel /**
3858cfa0ad2SJack F Vogel  *  e1000_init_mac_params_ich8lan - Initialize MAC function pointers
3868cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
3878cfa0ad2SJack F Vogel  *
3888cfa0ad2SJack F Vogel  *  Initialize family-specific MAC parameters and function
3898cfa0ad2SJack F Vogel  *  pointers.
3908cfa0ad2SJack F Vogel  **/
3918cfa0ad2SJack F Vogel static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
3928cfa0ad2SJack F Vogel {
3938cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
394d035aa2dSJack F Vogel 	u16 pci_cfg;
3958cfa0ad2SJack F Vogel 
3968cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_mac_params_ich8lan");
3978cfa0ad2SJack F Vogel 
3988cfa0ad2SJack F Vogel 	/* Set media type function pointer */
3998cfa0ad2SJack F Vogel 	hw->phy.media_type = e1000_media_type_copper;
4008cfa0ad2SJack F Vogel 
4018cfa0ad2SJack F Vogel 	/* Set mta register count */
4028cfa0ad2SJack F Vogel 	mac->mta_reg_count = 32;
4038cfa0ad2SJack F Vogel 	/* Set rar entry count */
4048cfa0ad2SJack F Vogel 	mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
4058cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
4068cfa0ad2SJack F Vogel 		mac->rar_entry_count--;
4078cfa0ad2SJack F Vogel 	/* Set if part includes ASF firmware */
4088cfa0ad2SJack F Vogel 	mac->asf_firmware_present = TRUE;
4098cfa0ad2SJack F Vogel 	/* Set if manageability features are enabled. */
4108cfa0ad2SJack F Vogel 	mac->arc_subsystem_valid = TRUE;
4118cfa0ad2SJack F Vogel 
4128cfa0ad2SJack F Vogel 	/* Function pointers */
4138cfa0ad2SJack F Vogel 
4148cfa0ad2SJack F Vogel 	/* bus type/speed/width */
4158cfa0ad2SJack F Vogel 	mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
416daf9197cSJack F Vogel 	/* function id */
417daf9197cSJack F Vogel 	mac->ops.set_lan_id = e1000_set_lan_id_single_port;
4188cfa0ad2SJack F Vogel 	/* reset */
4198cfa0ad2SJack F Vogel 	mac->ops.reset_hw = e1000_reset_hw_ich8lan;
4208cfa0ad2SJack F Vogel 	/* hw initialization */
4218cfa0ad2SJack F Vogel 	mac->ops.init_hw = e1000_init_hw_ich8lan;
4228cfa0ad2SJack F Vogel 	/* link setup */
4238cfa0ad2SJack F Vogel 	mac->ops.setup_link = e1000_setup_link_ich8lan;
4248cfa0ad2SJack F Vogel 	/* physical interface setup */
4258cfa0ad2SJack F Vogel 	mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
4268cfa0ad2SJack F Vogel 	/* check for link */
4278cfa0ad2SJack F Vogel 	mac->ops.check_for_link = e1000_check_for_copper_link_generic;
4288cfa0ad2SJack F Vogel 	/* check management mode */
4298cfa0ad2SJack F Vogel 	mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
4308cfa0ad2SJack F Vogel 	/* link info */
4318cfa0ad2SJack F Vogel 	mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
4328cfa0ad2SJack F Vogel 	/* multicast address update */
4338cfa0ad2SJack F Vogel 	mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
4348cfa0ad2SJack F Vogel 	/* setting MTA */
4358cfa0ad2SJack F Vogel 	mac->ops.mta_set = e1000_mta_set_generic;
436d035aa2dSJack F Vogel 	/* clear hardware counters */
437d035aa2dSJack F Vogel 	mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
438d035aa2dSJack F Vogel 
439d035aa2dSJack F Vogel 	/* LED operations */
440d035aa2dSJack F Vogel 	switch (mac->type) {
441d035aa2dSJack F Vogel 	case e1000_ich8lan:
442d035aa2dSJack F Vogel 	case e1000_ich9lan:
443d035aa2dSJack F Vogel 	case e1000_ich10lan:
444d035aa2dSJack F Vogel 		/* ID LED init */
445d035aa2dSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_generic;
4468cfa0ad2SJack F Vogel 		/* blink LED */
4478cfa0ad2SJack F Vogel 		mac->ops.blink_led = e1000_blink_led_generic;
4488cfa0ad2SJack F Vogel 		/* setup LED */
4498cfa0ad2SJack F Vogel 		mac->ops.setup_led = e1000_setup_led_generic;
4508cfa0ad2SJack F Vogel 		/* cleanup LED */
4518cfa0ad2SJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
4528cfa0ad2SJack F Vogel 		/* turn on/off LED */
4538cfa0ad2SJack F Vogel 		mac->ops.led_on = e1000_led_on_ich8lan;
4548cfa0ad2SJack F Vogel 		mac->ops.led_off = e1000_led_off_ich8lan;
455d035aa2dSJack F Vogel 		break;
4569d81738fSJack F Vogel 	case e1000_pchlan:
4579d81738fSJack F Vogel 		/* save PCH revision_id */
4589d81738fSJack F Vogel 		e1000_read_pci_cfg(hw, 0x2, &pci_cfg);
4599d81738fSJack F Vogel 		hw->revision_id = (u8)(pci_cfg &= 0x000F);
4609d81738fSJack F Vogel 		/* ID LED init */
4619d81738fSJack F Vogel 		mac->ops.id_led_init = e1000_id_led_init_pchlan;
4629d81738fSJack F Vogel 		/* setup LED */
4639d81738fSJack F Vogel 		mac->ops.setup_led = e1000_setup_led_pchlan;
4649d81738fSJack F Vogel 		/* cleanup LED */
4659d81738fSJack F Vogel 		mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
4669d81738fSJack F Vogel 		/* turn on/off LED */
4679d81738fSJack F Vogel 		mac->ops.led_on = e1000_led_on_pchlan;
4689d81738fSJack F Vogel 		mac->ops.led_off = e1000_led_off_pchlan;
4699d81738fSJack F Vogel 		break;
470d035aa2dSJack F Vogel 	default:
471d035aa2dSJack F Vogel 		break;
472d035aa2dSJack F Vogel 	}
4738cfa0ad2SJack F Vogel 
4748cfa0ad2SJack F Vogel 	/* Enable PCS Lock-loss workaround for ICH8 */
4758cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
4768cfa0ad2SJack F Vogel 		e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, TRUE);
4778cfa0ad2SJack F Vogel 
4788cfa0ad2SJack F Vogel 
479daf9197cSJack F Vogel 	return E1000_SUCCESS;
4808cfa0ad2SJack F Vogel }
4818cfa0ad2SJack F Vogel 
4828cfa0ad2SJack F Vogel /**
4838cfa0ad2SJack F Vogel  *  e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
4848cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
4858cfa0ad2SJack F Vogel  *
4868cfa0ad2SJack F Vogel  *  Initialize family-specific function pointers for PHY, MAC, and NVM.
4878cfa0ad2SJack F Vogel  **/
4888cfa0ad2SJack F Vogel void e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
4898cfa0ad2SJack F Vogel {
4908cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_function_pointers_ich8lan");
4918cfa0ad2SJack F Vogel 
4928cfa0ad2SJack F Vogel 	hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
4938cfa0ad2SJack F Vogel 	hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
4949d81738fSJack F Vogel 	switch (hw->mac.type) {
4959d81738fSJack F Vogel 	case e1000_ich8lan:
4969d81738fSJack F Vogel 	case e1000_ich9lan:
4979d81738fSJack F Vogel 	case e1000_ich10lan:
4988cfa0ad2SJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
4999d81738fSJack F Vogel 		break;
5009d81738fSJack F Vogel 	case e1000_pchlan:
5019d81738fSJack F Vogel 		hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
5029d81738fSJack F Vogel 		break;
5039d81738fSJack F Vogel 	default:
5049d81738fSJack F Vogel 		break;
5059d81738fSJack F Vogel 	}
5068cfa0ad2SJack F Vogel }
5078cfa0ad2SJack F Vogel 
5088cfa0ad2SJack F Vogel /**
5098cfa0ad2SJack F Vogel  *  e1000_acquire_swflag_ich8lan - Acquire software control flag
5108cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5118cfa0ad2SJack F Vogel  *
5128cfa0ad2SJack F Vogel  *  Acquires the software control flag for performing NVM and PHY
5138cfa0ad2SJack F Vogel  *  operations.  This is a function pointer entry point only called by
5148cfa0ad2SJack F Vogel  *  read/write routines for the PHY and NVM parts.
5158cfa0ad2SJack F Vogel  **/
5168cfa0ad2SJack F Vogel static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
5178cfa0ad2SJack F Vogel {
5188cfa0ad2SJack F Vogel 	u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
5198cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
5208cfa0ad2SJack F Vogel 
5218cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_acquire_swflag_ich8lan");
5228cfa0ad2SJack F Vogel 
5238cfa0ad2SJack F Vogel 	while (timeout) {
5248cfa0ad2SJack F Vogel 		extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
5259d81738fSJack F Vogel 
5269d81738fSJack F Vogel 		if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) {
5278cfa0ad2SJack F Vogel 			extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
5288cfa0ad2SJack F Vogel 			E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
5298cfa0ad2SJack F Vogel 
5308cfa0ad2SJack F Vogel 			extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
5318cfa0ad2SJack F Vogel 			if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
5328cfa0ad2SJack F Vogel 				break;
5339d81738fSJack F Vogel 		}
5348cfa0ad2SJack F Vogel 		msec_delay_irq(1);
5358cfa0ad2SJack F Vogel 		timeout--;
5368cfa0ad2SJack F Vogel 	}
5378cfa0ad2SJack F Vogel 
5388cfa0ad2SJack F Vogel 	if (!timeout) {
5399d81738fSJack F Vogel 		DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
5408cfa0ad2SJack F Vogel 		extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
5418cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
5428cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
5438cfa0ad2SJack F Vogel 		goto out;
5448cfa0ad2SJack F Vogel 	}
5458cfa0ad2SJack F Vogel 
5468cfa0ad2SJack F Vogel out:
5478cfa0ad2SJack F Vogel 	return ret_val;
5488cfa0ad2SJack F Vogel }
5498cfa0ad2SJack F Vogel 
5508cfa0ad2SJack F Vogel /**
5518cfa0ad2SJack F Vogel  *  e1000_release_swflag_ich8lan - Release software control flag
5528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5538cfa0ad2SJack F Vogel  *
5548cfa0ad2SJack F Vogel  *  Releases the software control flag for performing NVM and PHY operations.
5558cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
5568cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
5578cfa0ad2SJack F Vogel  **/
5588cfa0ad2SJack F Vogel static void e1000_release_swflag_ich8lan(struct e1000_hw *hw)
5598cfa0ad2SJack F Vogel {
5608cfa0ad2SJack F Vogel 	u32 extcnf_ctrl;
5618cfa0ad2SJack F Vogel 
5628cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_release_swflag_ich8lan");
5638cfa0ad2SJack F Vogel 
5648cfa0ad2SJack F Vogel 	extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
5658cfa0ad2SJack F Vogel 	extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
5668cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
5678cfa0ad2SJack F Vogel 
5688cfa0ad2SJack F Vogel 	return;
5698cfa0ad2SJack F Vogel }
5708cfa0ad2SJack F Vogel 
5718cfa0ad2SJack F Vogel /**
5728cfa0ad2SJack F Vogel  *  e1000_check_mng_mode_ich8lan - Checks management mode
5738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5748cfa0ad2SJack F Vogel  *
5758cfa0ad2SJack F Vogel  *  This checks if the adapter has manageability enabled.
5768cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by read/write
5778cfa0ad2SJack F Vogel  *  routines for the PHY and NVM parts.
5788cfa0ad2SJack F Vogel  **/
5798cfa0ad2SJack F Vogel static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
5808cfa0ad2SJack F Vogel {
5818cfa0ad2SJack F Vogel 	u32 fwsm;
5828cfa0ad2SJack F Vogel 
5838cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_mng_mode_ich8lan");
5848cfa0ad2SJack F Vogel 
5858cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
5868cfa0ad2SJack F Vogel 
587daf9197cSJack F Vogel 	return (fwsm & E1000_FWSM_MODE_MASK) ==
588daf9197cSJack F Vogel 	        (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT);
5898cfa0ad2SJack F Vogel }
5908cfa0ad2SJack F Vogel 
5918cfa0ad2SJack F Vogel /**
5928cfa0ad2SJack F Vogel  *  e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
5938cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
5948cfa0ad2SJack F Vogel  *
5958cfa0ad2SJack F Vogel  *  Checks if firmware is blocking the reset of the PHY.
5968cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
5978cfa0ad2SJack F Vogel  *  reset routines.
5988cfa0ad2SJack F Vogel  **/
5998cfa0ad2SJack F Vogel static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
6008cfa0ad2SJack F Vogel {
6018cfa0ad2SJack F Vogel 	u32 fwsm;
6028cfa0ad2SJack F Vogel 
6038cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_check_reset_block_ich8lan");
6048cfa0ad2SJack F Vogel 
6058cfa0ad2SJack F Vogel 	fwsm = E1000_READ_REG(hw, E1000_FWSM);
6068cfa0ad2SJack F Vogel 
6078cfa0ad2SJack F Vogel 	return (fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
6088cfa0ad2SJack F Vogel 	                                        : E1000_BLK_PHY_RESET;
6098cfa0ad2SJack F Vogel }
6108cfa0ad2SJack F Vogel 
6118cfa0ad2SJack F Vogel /**
6129d81738fSJack F Vogel  *  e1000_hv_phy_powerdown_workaround_ich8lan - Power down workaround on Sx
6139d81738fSJack F Vogel  *  @hw: pointer to the HW structure
6149d81738fSJack F Vogel  **/
6159d81738fSJack F Vogel s32 e1000_hv_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
6169d81738fSJack F Vogel {
6179d81738fSJack F Vogel 	if ((hw->phy.type != e1000_phy_82577) || (hw->revision_id > 2))
6189d81738fSJack F Vogel 		return E1000_SUCCESS;
6199d81738fSJack F Vogel 
6209d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0444);
6219d81738fSJack F Vogel }
6229d81738fSJack F Vogel 
6239d81738fSJack F Vogel /**
6249d81738fSJack F Vogel  *  e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
6259d81738fSJack F Vogel  *  done after every PHY reset.
6269d81738fSJack F Vogel  **/
6279d81738fSJack F Vogel static s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
6289d81738fSJack F Vogel {
6299d81738fSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
6309d81738fSJack F Vogel 
6319d81738fSJack F Vogel 	if (hw->mac.type != e1000_pchlan)
6329d81738fSJack F Vogel 		return ret_val;
6339d81738fSJack F Vogel 
6349d81738fSJack F Vogel 	/* Hanksville M Phy init for IEEE. */
6359d81738fSJack F Vogel 	if ((hw->revision_id == 2) &&
6369d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577) &&
6379d81738fSJack F Vogel 	    ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
6389d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8823);
6399d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0018);
6409d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8824);
6419d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0016);
6429d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8825);
6439d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x001A);
6449d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888C);
6459d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
6469d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888D);
6479d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
6489d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x888E);
6499d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0007);
6509d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8827);
6519d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
6529d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8835);
6539d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
6549d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8834);
6559d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0001);
6569d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x10, 0x8833);
6579d81738fSJack F Vogel 		hw->phy.ops.write_reg(hw, 0x11, 0x0002);
6589d81738fSJack F Vogel 	}
6599d81738fSJack F Vogel 
6609d81738fSJack F Vogel 	if (((hw->phy.type == e1000_phy_82577) &&
6619d81738fSJack F Vogel 	     ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
6629d81738fSJack F Vogel 	    ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
6639d81738fSJack F Vogel 		/* Disable generation of early preamble */
6649d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
6659d81738fSJack F Vogel 		if (ret_val)
6669d81738fSJack F Vogel 			return ret_val;
6679d81738fSJack F Vogel 
6689d81738fSJack F Vogel 		/* Preamble tuning for SSC */
6699d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
6709d81738fSJack F Vogel 		if (ret_val)
6719d81738fSJack F Vogel 			return ret_val;
6729d81738fSJack F Vogel 	}
6739d81738fSJack F Vogel 
6749d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
6759d81738fSJack F Vogel 		if (hw->revision_id < 3) {
6769d81738fSJack F Vogel 			/* PHY config */
6779d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29,
6789d81738fSJack F Vogel 			                                0x66C0);
6799d81738fSJack F Vogel 			if (ret_val)
6809d81738fSJack F Vogel 				return ret_val;
6819d81738fSJack F Vogel 
6829d81738fSJack F Vogel 			/* PHY config */
6839d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E,
6849d81738fSJack F Vogel 			                                0xFFFF);
6859d81738fSJack F Vogel 			if (ret_val)
6869d81738fSJack F Vogel 				return ret_val;
6879d81738fSJack F Vogel 		}
6889d81738fSJack F Vogel 
6899d81738fSJack F Vogel 		/*
6909d81738fSJack F Vogel 		 * Return registers to default by doing a soft reset then
6919d81738fSJack F Vogel 		 * writing 0x3140 to the control register.
6929d81738fSJack F Vogel 		 */
6939d81738fSJack F Vogel 		if (hw->phy.revision < 2) {
6949d81738fSJack F Vogel 			e1000_phy_sw_reset_generic(hw);
6959d81738fSJack F Vogel 			ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
6969d81738fSJack F Vogel 			                                0x3140);
6979d81738fSJack F Vogel 		}
6989d81738fSJack F Vogel 	}
6999d81738fSJack F Vogel 
7009d81738fSJack F Vogel 	if ((hw->revision_id == 2) &&
7019d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577) &&
7029d81738fSJack F Vogel 	    ((hw->phy.revision == 2) || (hw->phy.revision == 3))) {
7039d81738fSJack F Vogel 		/*
7049d81738fSJack F Vogel 		 * Workaround for OEM (GbE) not operating after reset -
7059d81738fSJack F Vogel 		 * restart AN (twice)
7069d81738fSJack F Vogel 		 */
7079d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
7089d81738fSJack F Vogel 		if (ret_val)
7099d81738fSJack F Vogel 			return ret_val;
7109d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, PHY_REG(768, 25), 0x0400);
7119d81738fSJack F Vogel 		if (ret_val)
7129d81738fSJack F Vogel 			return ret_val;
7139d81738fSJack F Vogel 	}
7149d81738fSJack F Vogel 
7159d81738fSJack F Vogel 	/* Select page 0 */
7169d81738fSJack F Vogel 	ret_val = hw->phy.ops.acquire(hw);
7179d81738fSJack F Vogel 	if (ret_val)
7189d81738fSJack F Vogel 		return ret_val;
7199d81738fSJack F Vogel 	hw->phy.addr = 1;
7209d81738fSJack F Vogel 	e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
7219d81738fSJack F Vogel 	hw->phy.ops.release(hw);
7229d81738fSJack F Vogel 
7239d81738fSJack F Vogel 	return ret_val;
7249d81738fSJack F Vogel }
7259d81738fSJack F Vogel 
7269d81738fSJack F Vogel /**
7279d81738fSJack F Vogel  *  e1000_lan_init_done_ich8lan - Check for PHY config completion
7288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7298cfa0ad2SJack F Vogel  *
7309d81738fSJack F Vogel  *  Check the appropriate indication the MAC has finished configuring the
7319d81738fSJack F Vogel  *  PHY after a software reset.
7328cfa0ad2SJack F Vogel  **/
7339d81738fSJack F Vogel static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
7348cfa0ad2SJack F Vogel {
7359d81738fSJack F Vogel 	u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
7368cfa0ad2SJack F Vogel 
7379d81738fSJack F Vogel 	DEBUGFUNC("e1000_lan_init_done_ich8lan");
7388cfa0ad2SJack F Vogel 
7399d81738fSJack F Vogel 	/* Wait for basic configuration completes before proceeding */
7409d81738fSJack F Vogel 	do {
7419d81738fSJack F Vogel 		data = E1000_READ_REG(hw, E1000_STATUS);
7429d81738fSJack F Vogel 		data &= E1000_STATUS_LAN_INIT_DONE;
7439d81738fSJack F Vogel 		usec_delay(100);
7449d81738fSJack F Vogel 	} while ((!data) && --loop);
7458cfa0ad2SJack F Vogel 
7469d81738fSJack F Vogel 	/*
7479d81738fSJack F Vogel 	 * If basic configuration is incomplete before the above loop
7489d81738fSJack F Vogel 	 * count reaches 0, loading the configuration from NVM will
7499d81738fSJack F Vogel 	 * leave the PHY in a bad state possibly resulting in no link.
7509d81738fSJack F Vogel 	 */
7519d81738fSJack F Vogel 	if (loop == 0)
7529d81738fSJack F Vogel 		DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
7538cfa0ad2SJack F Vogel 
7549d81738fSJack F Vogel 	/* Clear the Init Done bit for the next init event */
7559d81738fSJack F Vogel 	data = E1000_READ_REG(hw, E1000_STATUS);
7569d81738fSJack F Vogel 	data &= ~E1000_STATUS_LAN_INIT_DONE;
7579d81738fSJack F Vogel 	E1000_WRITE_REG(hw, E1000_STATUS, data);
7588cfa0ad2SJack F Vogel }
7598cfa0ad2SJack F Vogel 
7608cfa0ad2SJack F Vogel /**
7618cfa0ad2SJack F Vogel  *  e1000_phy_hw_reset_ich8lan - Performs a PHY reset
7628cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
7638cfa0ad2SJack F Vogel  *
7648cfa0ad2SJack F Vogel  *  Resets the PHY
7658cfa0ad2SJack F Vogel  *  This is a function pointer entry point called by drivers
7668cfa0ad2SJack F Vogel  *  or other shared routines.
7678cfa0ad2SJack F Vogel  **/
7688cfa0ad2SJack F Vogel static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
7698cfa0ad2SJack F Vogel {
7708cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
7718cfa0ad2SJack F Vogel 	u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
7728cfa0ad2SJack F Vogel 	s32 ret_val;
7738cfa0ad2SJack F Vogel 	u16 word_addr, reg_data, reg_addr, phy_page = 0;
7748cfa0ad2SJack F Vogel 
7758cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
7768cfa0ad2SJack F Vogel 
7778cfa0ad2SJack F Vogel 	ret_val = e1000_phy_hw_reset_generic(hw);
7788cfa0ad2SJack F Vogel 	if (ret_val)
7798cfa0ad2SJack F Vogel 		goto out;
7808cfa0ad2SJack F Vogel 
7819d81738fSJack F Vogel 	/* Allow time for h/w to get to a quiescent state after reset */
7829d81738fSJack F Vogel 	msec_delay(10);
7839d81738fSJack F Vogel 
7849d81738fSJack F Vogel 	if (hw->mac.type == e1000_pchlan) {
7859d81738fSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
7869d81738fSJack F Vogel 		if (ret_val)
7879d81738fSJack F Vogel 			goto out;
7889d81738fSJack F Vogel 	}
7899d81738fSJack F Vogel 
7908cfa0ad2SJack F Vogel 	/*
7918cfa0ad2SJack F Vogel 	 * Initialize the PHY from the NVM on ICH platforms.  This
7928cfa0ad2SJack F Vogel 	 * is needed due to an issue where the NVM configuration is
7938cfa0ad2SJack F Vogel 	 * not properly autoloaded after power transitions.
7948cfa0ad2SJack F Vogel 	 * Therefore, after each PHY reset, we will load the
7958cfa0ad2SJack F Vogel 	 * configuration data out of the NVM manually.
7968cfa0ad2SJack F Vogel 	 */
7978cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) {
7988cfa0ad2SJack F Vogel 		/* Check if SW needs configure the PHY */
7998cfa0ad2SJack F Vogel 		if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
8008cfa0ad2SJack F Vogel 		    (hw->device_id == E1000_DEV_ID_ICH8_IGP_M))
8018cfa0ad2SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
8028cfa0ad2SJack F Vogel 		else
8038cfa0ad2SJack F Vogel 			sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
8048cfa0ad2SJack F Vogel 
8058cfa0ad2SJack F Vogel 		data = E1000_READ_REG(hw, E1000_FEXTNVM);
8068cfa0ad2SJack F Vogel 		if (!(data & sw_cfg_mask))
8078cfa0ad2SJack F Vogel 			goto out;
8088cfa0ad2SJack F Vogel 
8098cfa0ad2SJack F Vogel 		/* Wait for basic configuration completes before proceeding */
8109d81738fSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
8118cfa0ad2SJack F Vogel 
8128cfa0ad2SJack F Vogel 		/*
8138cfa0ad2SJack F Vogel 		 * Make sure HW does not configure LCD from PHY
8148cfa0ad2SJack F Vogel 		 * extended configuration before SW configuration
8158cfa0ad2SJack F Vogel 		 */
8168cfa0ad2SJack F Vogel 		data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
8178cfa0ad2SJack F Vogel 		if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
8188cfa0ad2SJack F Vogel 			goto out;
8198cfa0ad2SJack F Vogel 
8208cfa0ad2SJack F Vogel 		cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
8218cfa0ad2SJack F Vogel 		cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
8228cfa0ad2SJack F Vogel 		cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
8238cfa0ad2SJack F Vogel 		if (!cnf_size)
8248cfa0ad2SJack F Vogel 			goto out;
8258cfa0ad2SJack F Vogel 
8268cfa0ad2SJack F Vogel 		cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
8278cfa0ad2SJack F Vogel 		cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
8288cfa0ad2SJack F Vogel 
829daf9197cSJack F Vogel 		/* Configure LCD from extended configuration region. */
8308cfa0ad2SJack F Vogel 
8318cfa0ad2SJack F Vogel 		/* cnf_base_addr is in DWORD */
8328cfa0ad2SJack F Vogel 		word_addr = (u16)(cnf_base_addr << 1);
8338cfa0ad2SJack F Vogel 
8348cfa0ad2SJack F Vogel 		for (i = 0; i < cnf_size; i++) {
835daf9197cSJack F Vogel 			ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
8368cfa0ad2SJack F Vogel 			                           &reg_data);
8378cfa0ad2SJack F Vogel 			if (ret_val)
8388cfa0ad2SJack F Vogel 				goto out;
8398cfa0ad2SJack F Vogel 
840daf9197cSJack F Vogel 			ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
841daf9197cSJack F Vogel 			                           1, &reg_addr);
8428cfa0ad2SJack F Vogel 			if (ret_val)
8438cfa0ad2SJack F Vogel 				goto out;
8448cfa0ad2SJack F Vogel 
8458cfa0ad2SJack F Vogel 			/* Save off the PHY page for future writes. */
8468cfa0ad2SJack F Vogel 			if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
8478cfa0ad2SJack F Vogel 				phy_page = reg_data;
8488cfa0ad2SJack F Vogel 				continue;
8498cfa0ad2SJack F Vogel 			}
8508cfa0ad2SJack F Vogel 
8518cfa0ad2SJack F Vogel 			reg_addr |= phy_page;
8528cfa0ad2SJack F Vogel 
853daf9197cSJack F Vogel 			ret_val = phy->ops.write_reg(hw, (u32)reg_addr, reg_data);
8548cfa0ad2SJack F Vogel 			if (ret_val)
8558cfa0ad2SJack F Vogel 				goto out;
8568cfa0ad2SJack F Vogel 		}
8578cfa0ad2SJack F Vogel 	}
8588cfa0ad2SJack F Vogel 
8598cfa0ad2SJack F Vogel out:
8608cfa0ad2SJack F Vogel 	return ret_val;
8618cfa0ad2SJack F Vogel }
8628cfa0ad2SJack F Vogel 
8638cfa0ad2SJack F Vogel /**
8648cfa0ad2SJack F Vogel  *  e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
8658cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8668cfa0ad2SJack F Vogel  *
8678cfa0ad2SJack F Vogel  *  Wrapper for calling the get_phy_info routines for the appropriate phy type.
8688cfa0ad2SJack F Vogel  **/
8698cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
8708cfa0ad2SJack F Vogel {
8718cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_PHY_TYPE;
8728cfa0ad2SJack F Vogel 
8738cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_phy_info_ich8lan");
8748cfa0ad2SJack F Vogel 
8758cfa0ad2SJack F Vogel 	switch (hw->phy.type) {
8768cfa0ad2SJack F Vogel 	case e1000_phy_ife:
8778cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_info_ife_ich8lan(hw);
8788cfa0ad2SJack F Vogel 		break;
8798cfa0ad2SJack F Vogel 	case e1000_phy_igp_3:
8808cfa0ad2SJack F Vogel 	case e1000_phy_bm:
8819d81738fSJack F Vogel 	case e1000_phy_82578:
8829d81738fSJack F Vogel 	case e1000_phy_82577:
8838cfa0ad2SJack F Vogel 		ret_val = e1000_get_phy_info_igp(hw);
8848cfa0ad2SJack F Vogel 		break;
8858cfa0ad2SJack F Vogel 	default:
8868cfa0ad2SJack F Vogel 		break;
8878cfa0ad2SJack F Vogel 	}
8888cfa0ad2SJack F Vogel 
8898cfa0ad2SJack F Vogel 	return ret_val;
8908cfa0ad2SJack F Vogel }
8918cfa0ad2SJack F Vogel 
8928cfa0ad2SJack F Vogel /**
8938cfa0ad2SJack F Vogel  *  e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
8948cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
8958cfa0ad2SJack F Vogel  *
8968cfa0ad2SJack F Vogel  *  Populates "phy" structure with various feature states.
8978cfa0ad2SJack F Vogel  *  This function is only called by other family-specific
8988cfa0ad2SJack F Vogel  *  routines.
8998cfa0ad2SJack F Vogel  **/
9008cfa0ad2SJack F Vogel static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
9018cfa0ad2SJack F Vogel {
9028cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
9038cfa0ad2SJack F Vogel 	s32 ret_val;
9048cfa0ad2SJack F Vogel 	u16 data;
9058cfa0ad2SJack F Vogel 	bool link;
9068cfa0ad2SJack F Vogel 
9078cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_phy_info_ife_ich8lan");
9088cfa0ad2SJack F Vogel 
9098cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
9108cfa0ad2SJack F Vogel 	if (ret_val)
9118cfa0ad2SJack F Vogel 		goto out;
9128cfa0ad2SJack F Vogel 
9138cfa0ad2SJack F Vogel 	if (!link) {
9148cfa0ad2SJack F Vogel 		DEBUGOUT("Phy info is only valid if link is up\n");
9158cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_CONFIG;
9168cfa0ad2SJack F Vogel 		goto out;
9178cfa0ad2SJack F Vogel 	}
9188cfa0ad2SJack F Vogel 
9198cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
9208cfa0ad2SJack F Vogel 	if (ret_val)
9218cfa0ad2SJack F Vogel 		goto out;
9228cfa0ad2SJack F Vogel 	phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
9238cfa0ad2SJack F Vogel 	                           ? FALSE : TRUE;
9248cfa0ad2SJack F Vogel 
9258cfa0ad2SJack F Vogel 	if (phy->polarity_correction) {
9269d81738fSJack F Vogel 		ret_val = e1000_check_polarity_ife(hw);
9278cfa0ad2SJack F Vogel 		if (ret_val)
9288cfa0ad2SJack F Vogel 			goto out;
9298cfa0ad2SJack F Vogel 	} else {
9308cfa0ad2SJack F Vogel 		/* Polarity is forced */
9318cfa0ad2SJack F Vogel 		phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
9328cfa0ad2SJack F Vogel 		                      ? e1000_rev_polarity_reversed
9338cfa0ad2SJack F Vogel 		                      : e1000_rev_polarity_normal;
9348cfa0ad2SJack F Vogel 	}
9358cfa0ad2SJack F Vogel 
9368cfa0ad2SJack F Vogel 	ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
9378cfa0ad2SJack F Vogel 	if (ret_val)
9388cfa0ad2SJack F Vogel 		goto out;
9398cfa0ad2SJack F Vogel 
9408cfa0ad2SJack F Vogel 	phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? TRUE : FALSE;
9418cfa0ad2SJack F Vogel 
9428cfa0ad2SJack F Vogel 	/* The following parameters are undefined for 10/100 operation. */
9438cfa0ad2SJack F Vogel 	phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
9448cfa0ad2SJack F Vogel 	phy->local_rx = e1000_1000t_rx_status_undefined;
9458cfa0ad2SJack F Vogel 	phy->remote_rx = e1000_1000t_rx_status_undefined;
9468cfa0ad2SJack F Vogel 
9478cfa0ad2SJack F Vogel out:
9488cfa0ad2SJack F Vogel 	return ret_val;
9498cfa0ad2SJack F Vogel }
9508cfa0ad2SJack F Vogel 
9518cfa0ad2SJack F Vogel /**
9528cfa0ad2SJack F Vogel  *  e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
9538cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
9548cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
9558cfa0ad2SJack F Vogel  *
9568cfa0ad2SJack F Vogel  *  Sets the LPLU D0 state according to the active flag.  When
9578cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
9588cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
9598cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
9608cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
9618cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
9628cfa0ad2SJack F Vogel  *  PHY setup routines.
9638cfa0ad2SJack F Vogel  **/
964daf9197cSJack F Vogel static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
9658cfa0ad2SJack F Vogel {
9668cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
9678cfa0ad2SJack F Vogel 	u32 phy_ctrl;
9688cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
9698cfa0ad2SJack F Vogel 	u16 data;
9708cfa0ad2SJack F Vogel 
9718cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
9728cfa0ad2SJack F Vogel 
9738cfa0ad2SJack F Vogel 	if (phy->type == e1000_phy_ife)
9748cfa0ad2SJack F Vogel 		goto out;
9758cfa0ad2SJack F Vogel 
9768cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
9778cfa0ad2SJack F Vogel 
9788cfa0ad2SJack F Vogel 	if (active) {
9798cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
9808cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
9818cfa0ad2SJack F Vogel 
9829d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
9839d81738fSJack F Vogel 			goto out;
9849d81738fSJack F Vogel 
9858cfa0ad2SJack F Vogel 		/*
9868cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
9878cfa0ad2SJack F Vogel 		 * any PHY registers
9888cfa0ad2SJack F Vogel 		 */
9899d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
9908cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
9918cfa0ad2SJack F Vogel 
9928cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
9938cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
9948cfa0ad2SJack F Vogel 		                            IGP01E1000_PHY_PORT_CONFIG,
9958cfa0ad2SJack F Vogel 		                            &data);
9968cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
9978cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
9988cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_PORT_CONFIG,
9998cfa0ad2SJack F Vogel 		                             data);
10008cfa0ad2SJack F Vogel 		if (ret_val)
10018cfa0ad2SJack F Vogel 			goto out;
10028cfa0ad2SJack F Vogel 	} else {
10038cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
10048cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
10058cfa0ad2SJack F Vogel 
10069d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
10079d81738fSJack F Vogel 			goto out;
10089d81738fSJack F Vogel 
10098cfa0ad2SJack F Vogel 		/*
10108cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
10118cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
10128cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
10138cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
10148cfa0ad2SJack F Vogel 		 */
10158cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
10168cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
10178cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
10188cfa0ad2SJack F Vogel 			                            &data);
10198cfa0ad2SJack F Vogel 			if (ret_val)
10208cfa0ad2SJack F Vogel 				goto out;
10218cfa0ad2SJack F Vogel 
10228cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
10238cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10248cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
10258cfa0ad2SJack F Vogel 			                             data);
10268cfa0ad2SJack F Vogel 			if (ret_val)
10278cfa0ad2SJack F Vogel 				goto out;
10288cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
10298cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
10308cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
10318cfa0ad2SJack F Vogel 			                            &data);
10328cfa0ad2SJack F Vogel 			if (ret_val)
10338cfa0ad2SJack F Vogel 				goto out;
10348cfa0ad2SJack F Vogel 
10358cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
10368cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10378cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
10388cfa0ad2SJack F Vogel 			                             data);
10398cfa0ad2SJack F Vogel 			if (ret_val)
10408cfa0ad2SJack F Vogel 				goto out;
10418cfa0ad2SJack F Vogel 		}
10428cfa0ad2SJack F Vogel 	}
10438cfa0ad2SJack F Vogel 
10448cfa0ad2SJack F Vogel out:
10458cfa0ad2SJack F Vogel 	return ret_val;
10468cfa0ad2SJack F Vogel }
10478cfa0ad2SJack F Vogel 
10488cfa0ad2SJack F Vogel /**
10498cfa0ad2SJack F Vogel  *  e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
10508cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
10518cfa0ad2SJack F Vogel  *  @active: TRUE to enable LPLU, FALSE to disable
10528cfa0ad2SJack F Vogel  *
10538cfa0ad2SJack F Vogel  *  Sets the LPLU D3 state according to the active flag.  When
10548cfa0ad2SJack F Vogel  *  activating LPLU this function also disables smart speed
10558cfa0ad2SJack F Vogel  *  and vice versa.  LPLU will not be activated unless the
10568cfa0ad2SJack F Vogel  *  device autonegotiation advertisement meets standards of
10578cfa0ad2SJack F Vogel  *  either 10 or 10/100 or 10/100/1000 at all duplexes.
10588cfa0ad2SJack F Vogel  *  This is a function pointer entry point only called by
10598cfa0ad2SJack F Vogel  *  PHY setup routines.
10608cfa0ad2SJack F Vogel  **/
1061daf9197cSJack F Vogel static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
10628cfa0ad2SJack F Vogel {
10638cfa0ad2SJack F Vogel 	struct e1000_phy_info *phy = &hw->phy;
10648cfa0ad2SJack F Vogel 	u32 phy_ctrl;
10658cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
10668cfa0ad2SJack F Vogel 	u16 data;
10678cfa0ad2SJack F Vogel 
10688cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
10698cfa0ad2SJack F Vogel 
10708cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
10718cfa0ad2SJack F Vogel 
10728cfa0ad2SJack F Vogel 	if (!active) {
10738cfa0ad2SJack F Vogel 		phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
10748cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
10759d81738fSJack F Vogel 
10769d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
10779d81738fSJack F Vogel 			goto out;
10789d81738fSJack F Vogel 
10798cfa0ad2SJack F Vogel 		/*
10808cfa0ad2SJack F Vogel 		 * LPLU and SmartSpeed are mutually exclusive.  LPLU is used
10818cfa0ad2SJack F Vogel 		 * during Dx states where the power conservation is most
10828cfa0ad2SJack F Vogel 		 * important.  During driver activity we should enable
10838cfa0ad2SJack F Vogel 		 * SmartSpeed, so performance is maintained.
10848cfa0ad2SJack F Vogel 		 */
10858cfa0ad2SJack F Vogel 		if (phy->smart_speed == e1000_smart_speed_on) {
10868cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
10878cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
10888cfa0ad2SJack F Vogel 			                            &data);
10898cfa0ad2SJack F Vogel 			if (ret_val)
10908cfa0ad2SJack F Vogel 				goto out;
10918cfa0ad2SJack F Vogel 
10928cfa0ad2SJack F Vogel 			data |= IGP01E1000_PSCFR_SMART_SPEED;
10938cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
10948cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
10958cfa0ad2SJack F Vogel 			                             data);
10968cfa0ad2SJack F Vogel 			if (ret_val)
10978cfa0ad2SJack F Vogel 				goto out;
10988cfa0ad2SJack F Vogel 		} else if (phy->smart_speed == e1000_smart_speed_off) {
10998cfa0ad2SJack F Vogel 			ret_val = phy->ops.read_reg(hw,
11008cfa0ad2SJack F Vogel 			                            IGP01E1000_PHY_PORT_CONFIG,
11018cfa0ad2SJack F Vogel 			                            &data);
11028cfa0ad2SJack F Vogel 			if (ret_val)
11038cfa0ad2SJack F Vogel 				goto out;
11048cfa0ad2SJack F Vogel 
11058cfa0ad2SJack F Vogel 			data &= ~IGP01E1000_PSCFR_SMART_SPEED;
11068cfa0ad2SJack F Vogel 			ret_val = phy->ops.write_reg(hw,
11078cfa0ad2SJack F Vogel 			                             IGP01E1000_PHY_PORT_CONFIG,
11088cfa0ad2SJack F Vogel 			                             data);
11098cfa0ad2SJack F Vogel 			if (ret_val)
11108cfa0ad2SJack F Vogel 				goto out;
11118cfa0ad2SJack F Vogel 		}
11128cfa0ad2SJack F Vogel 	} else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
11138cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
11148cfa0ad2SJack F Vogel 	           (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
11158cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
11168cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
11178cfa0ad2SJack F Vogel 
11189d81738fSJack F Vogel 		if (phy->type != e1000_phy_igp_3)
11199d81738fSJack F Vogel 			goto out;
11209d81738fSJack F Vogel 
11218cfa0ad2SJack F Vogel 		/*
11228cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on LPLU before accessing
11238cfa0ad2SJack F Vogel 		 * any PHY registers
11248cfa0ad2SJack F Vogel 		 */
11259d81738fSJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
11268cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
11278cfa0ad2SJack F Vogel 
11288cfa0ad2SJack F Vogel 		/* When LPLU is enabled, we should disable SmartSpeed */
11298cfa0ad2SJack F Vogel 		ret_val = phy->ops.read_reg(hw,
11308cfa0ad2SJack F Vogel 		                            IGP01E1000_PHY_PORT_CONFIG,
11318cfa0ad2SJack F Vogel 		                            &data);
11328cfa0ad2SJack F Vogel 		if (ret_val)
11338cfa0ad2SJack F Vogel 			goto out;
11348cfa0ad2SJack F Vogel 
11358cfa0ad2SJack F Vogel 		data &= ~IGP01E1000_PSCFR_SMART_SPEED;
11368cfa0ad2SJack F Vogel 		ret_val = phy->ops.write_reg(hw,
11378cfa0ad2SJack F Vogel 		                             IGP01E1000_PHY_PORT_CONFIG,
11388cfa0ad2SJack F Vogel 		                             data);
11398cfa0ad2SJack F Vogel 	}
11408cfa0ad2SJack F Vogel 
11418cfa0ad2SJack F Vogel out:
11428cfa0ad2SJack F Vogel 	return ret_val;
11438cfa0ad2SJack F Vogel }
11448cfa0ad2SJack F Vogel 
11458cfa0ad2SJack F Vogel /**
11468cfa0ad2SJack F Vogel  *  e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
11478cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
11488cfa0ad2SJack F Vogel  *  @bank:  pointer to the variable that returns the active bank
11498cfa0ad2SJack F Vogel  *
11508cfa0ad2SJack F Vogel  *  Reads signature byte from the NVM using the flash access registers.
1151d035aa2dSJack F Vogel  *  Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
11528cfa0ad2SJack F Vogel  **/
11538cfa0ad2SJack F Vogel static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
11548cfa0ad2SJack F Vogel {
1155d035aa2dSJack F Vogel 	u32 eecd;
11568cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
11578cfa0ad2SJack F Vogel 	u32 bank1_offset = nvm->flash_bank_size * sizeof(u16);
11588cfa0ad2SJack F Vogel 	u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
1159d035aa2dSJack F Vogel 	u8 sig_byte = 0;
1160d035aa2dSJack F Vogel 	s32 ret_val = E1000_SUCCESS;
11618cfa0ad2SJack F Vogel 
1162d035aa2dSJack F Vogel 	switch (hw->mac.type) {
1163d035aa2dSJack F Vogel 	case e1000_ich8lan:
1164d035aa2dSJack F Vogel 	case e1000_ich9lan:
1165d035aa2dSJack F Vogel 		eecd = E1000_READ_REG(hw, E1000_EECD);
1166d035aa2dSJack F Vogel 		if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
1167d035aa2dSJack F Vogel 		    E1000_EECD_SEC1VAL_VALID_MASK) {
1168d035aa2dSJack F Vogel 			if (eecd & E1000_EECD_SEC1VAL)
11698cfa0ad2SJack F Vogel 				*bank = 1;
11708cfa0ad2SJack F Vogel 			else
11718cfa0ad2SJack F Vogel 				*bank = 0;
1172d035aa2dSJack F Vogel 
1173d035aa2dSJack F Vogel 			goto out;
1174d035aa2dSJack F Vogel 		}
1175d035aa2dSJack F Vogel 		DEBUGOUT("Unable to determine valid NVM bank via EEC - "
1176d035aa2dSJack F Vogel 		         "reading flash signature\n");
1177d035aa2dSJack F Vogel 		/* fall-thru */
1178d035aa2dSJack F Vogel 	default:
1179d035aa2dSJack F Vogel 		/* set bank to 0 in case flash read fails */
11808cfa0ad2SJack F Vogel 		*bank = 0;
11818cfa0ad2SJack F Vogel 
1182d035aa2dSJack F Vogel 		/* Check bank 0 */
1183d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
1184d035aa2dSJack F Vogel 		                                        &sig_byte);
1185d035aa2dSJack F Vogel 		if (ret_val)
1186d035aa2dSJack F Vogel 			goto out;
1187d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
1188d035aa2dSJack F Vogel 			E1000_ICH_NVM_SIG_VALUE) {
1189d035aa2dSJack F Vogel 			*bank = 0;
1190d035aa2dSJack F Vogel 			goto out;
1191d035aa2dSJack F Vogel 		}
1192d035aa2dSJack F Vogel 
1193d035aa2dSJack F Vogel 		/* Check bank 1 */
1194d035aa2dSJack F Vogel 		ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
1195d035aa2dSJack F Vogel 		                                        bank1_offset,
1196d035aa2dSJack F Vogel 					                &sig_byte);
1197d035aa2dSJack F Vogel 		if (ret_val)
1198d035aa2dSJack F Vogel 			goto out;
1199d035aa2dSJack F Vogel 		if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
1200d035aa2dSJack F Vogel 			E1000_ICH_NVM_SIG_VALUE) {
12018cfa0ad2SJack F Vogel 			*bank = 1;
1202d035aa2dSJack F Vogel 			goto out;
12038cfa0ad2SJack F Vogel 		}
12048cfa0ad2SJack F Vogel 
1205d035aa2dSJack F Vogel 		DEBUGOUT("ERROR: No valid NVM bank present\n");
1206d035aa2dSJack F Vogel 		ret_val = -E1000_ERR_NVM;
1207d035aa2dSJack F Vogel 		break;
1208d035aa2dSJack F Vogel 	}
1209d035aa2dSJack F Vogel out:
12108cfa0ad2SJack F Vogel 	return ret_val;
12118cfa0ad2SJack F Vogel }
12128cfa0ad2SJack F Vogel 
12138cfa0ad2SJack F Vogel /**
12148cfa0ad2SJack F Vogel  *  e1000_read_nvm_ich8lan - Read word(s) from the NVM
12158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12168cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to read.
12178cfa0ad2SJack F Vogel  *  @words: Size of data to read in words
12188cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to read at offset.
12198cfa0ad2SJack F Vogel  *
12208cfa0ad2SJack F Vogel  *  Reads a word(s) from the NVM using the flash access registers.
12218cfa0ad2SJack F Vogel  **/
12228cfa0ad2SJack F Vogel static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
12238cfa0ad2SJack F Vogel                                   u16 *data)
12248cfa0ad2SJack F Vogel {
12258cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
1226daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
12278cfa0ad2SJack F Vogel 	u32 act_offset;
12288cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
12298cfa0ad2SJack F Vogel 	u32 bank = 0;
12308cfa0ad2SJack F Vogel 	u16 i, word;
12318cfa0ad2SJack F Vogel 
12328cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_nvm_ich8lan");
12338cfa0ad2SJack F Vogel 
12348cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
12358cfa0ad2SJack F Vogel 	    (words == 0)) {
12368cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
12378cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
12388cfa0ad2SJack F Vogel 		goto out;
12398cfa0ad2SJack F Vogel 	}
12408cfa0ad2SJack F Vogel 
12418cfa0ad2SJack F Vogel 	ret_val = nvm->ops.acquire(hw);
12428cfa0ad2SJack F Vogel 	if (ret_val)
12438cfa0ad2SJack F Vogel 		goto out;
12448cfa0ad2SJack F Vogel 
12458cfa0ad2SJack F Vogel 	ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
12468cfa0ad2SJack F Vogel 	if (ret_val != E1000_SUCCESS)
1247d035aa2dSJack F Vogel 		goto release;
12488cfa0ad2SJack F Vogel 
12498cfa0ad2SJack F Vogel 	act_offset = (bank) ? nvm->flash_bank_size : 0;
12508cfa0ad2SJack F Vogel 	act_offset += offset;
12518cfa0ad2SJack F Vogel 
12528cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
12538cfa0ad2SJack F Vogel 		if ((dev_spec->shadow_ram) &&
12548cfa0ad2SJack F Vogel 		    (dev_spec->shadow_ram[offset+i].modified)) {
12558cfa0ad2SJack F Vogel 			data[i] = dev_spec->shadow_ram[offset+i].value;
12568cfa0ad2SJack F Vogel 		} else {
12578cfa0ad2SJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw,
12588cfa0ad2SJack F Vogel 			                                        act_offset + i,
12598cfa0ad2SJack F Vogel 			                                        &word);
12608cfa0ad2SJack F Vogel 			if (ret_val)
12618cfa0ad2SJack F Vogel 				break;
12628cfa0ad2SJack F Vogel 			data[i] = word;
12638cfa0ad2SJack F Vogel 		}
12648cfa0ad2SJack F Vogel 	}
12658cfa0ad2SJack F Vogel 
1266d035aa2dSJack F Vogel release:
12678cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
12688cfa0ad2SJack F Vogel 
12698cfa0ad2SJack F Vogel out:
1270d035aa2dSJack F Vogel 	if (ret_val)
1271d035aa2dSJack F Vogel 		DEBUGOUT1("NVM read error: %d\n", ret_val);
1272d035aa2dSJack F Vogel 
12738cfa0ad2SJack F Vogel 	return ret_val;
12748cfa0ad2SJack F Vogel }
12758cfa0ad2SJack F Vogel 
12768cfa0ad2SJack F Vogel /**
12778cfa0ad2SJack F Vogel  *  e1000_flash_cycle_init_ich8lan - Initialize flash
12788cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
12798cfa0ad2SJack F Vogel  *
12808cfa0ad2SJack F Vogel  *  This function does initial flash setup so that a new read/write/erase cycle
12818cfa0ad2SJack F Vogel  *  can be started.
12828cfa0ad2SJack F Vogel  **/
12838cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
12848cfa0ad2SJack F Vogel {
12858cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
12868cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
12878cfa0ad2SJack F Vogel 	s32 i = 0;
12888cfa0ad2SJack F Vogel 
12898cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
12908cfa0ad2SJack F Vogel 
12918cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
12928cfa0ad2SJack F Vogel 
12938cfa0ad2SJack F Vogel 	/* Check if the flash descriptor is valid */
12948cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.fldesvalid == 0) {
12958cfa0ad2SJack F Vogel 		DEBUGOUT("Flash descriptor invalid.  "
12968cfa0ad2SJack F Vogel 		         "SW Sequencing must be used.");
12978cfa0ad2SJack F Vogel 		goto out;
12988cfa0ad2SJack F Vogel 	}
12998cfa0ad2SJack F Vogel 
13008cfa0ad2SJack F Vogel 	/* Clear FCERR and DAEL in hw status by writing 1 */
13018cfa0ad2SJack F Vogel 	hsfsts.hsf_status.flcerr = 1;
13028cfa0ad2SJack F Vogel 	hsfsts.hsf_status.dael = 1;
13038cfa0ad2SJack F Vogel 
13048cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
13058cfa0ad2SJack F Vogel 
13068cfa0ad2SJack F Vogel 	/*
13078cfa0ad2SJack F Vogel 	 * Either we should have a hardware SPI cycle in progress
13088cfa0ad2SJack F Vogel 	 * bit to check against, in order to start a new cycle or
13098cfa0ad2SJack F Vogel 	 * FDONE bit should be changed in the hardware so that it
13108cfa0ad2SJack F Vogel 	 * is 1 after hardware reset, which can then be used as an
13118cfa0ad2SJack F Vogel 	 * indication whether a cycle is in progress or has been
13128cfa0ad2SJack F Vogel 	 * completed.
13138cfa0ad2SJack F Vogel 	 */
13148cfa0ad2SJack F Vogel 
13158cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcinprog == 0) {
13168cfa0ad2SJack F Vogel 		/*
13178cfa0ad2SJack F Vogel 		 * There is no cycle running at present,
13188cfa0ad2SJack F Vogel 		 * so we can start a cycle.
13198cfa0ad2SJack F Vogel 		 * Begin by setting Flash Cycle Done.
13208cfa0ad2SJack F Vogel 		 */
13218cfa0ad2SJack F Vogel 		hsfsts.hsf_status.flcdone = 1;
13228cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
13238cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
13248cfa0ad2SJack F Vogel 	} else {
13258cfa0ad2SJack F Vogel 		/*
13268cfa0ad2SJack F Vogel 		 * Otherwise poll for sometime so the current
13278cfa0ad2SJack F Vogel 		 * cycle has a chance to end before giving up.
13288cfa0ad2SJack F Vogel 		 */
13298cfa0ad2SJack F Vogel 		for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
13308cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
13318cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFSTS);
13328cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcinprog == 0) {
13338cfa0ad2SJack F Vogel 				ret_val = E1000_SUCCESS;
13348cfa0ad2SJack F Vogel 				break;
13358cfa0ad2SJack F Vogel 			}
13368cfa0ad2SJack F Vogel 			usec_delay(1);
13378cfa0ad2SJack F Vogel 		}
13388cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
13398cfa0ad2SJack F Vogel 			/*
13408cfa0ad2SJack F Vogel 			 * Successful in waiting for previous cycle to timeout,
13418cfa0ad2SJack F Vogel 			 * now set the Flash Cycle Done.
13428cfa0ad2SJack F Vogel 			 */
13438cfa0ad2SJack F Vogel 			hsfsts.hsf_status.flcdone = 1;
1344daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS,
13458cfa0ad2SJack F Vogel 			                        hsfsts.regval);
13468cfa0ad2SJack F Vogel 		} else {
13478cfa0ad2SJack F Vogel 			DEBUGOUT("Flash controller busy, cannot get access");
13488cfa0ad2SJack F Vogel 		}
13498cfa0ad2SJack F Vogel 	}
13508cfa0ad2SJack F Vogel 
13518cfa0ad2SJack F Vogel out:
13528cfa0ad2SJack F Vogel 	return ret_val;
13538cfa0ad2SJack F Vogel }
13548cfa0ad2SJack F Vogel 
13558cfa0ad2SJack F Vogel /**
13568cfa0ad2SJack F Vogel  *  e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
13578cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13588cfa0ad2SJack F Vogel  *  @timeout: maximum time to wait for completion
13598cfa0ad2SJack F Vogel  *
13608cfa0ad2SJack F Vogel  *  This function starts a flash cycle and waits for its completion.
13618cfa0ad2SJack F Vogel  **/
13628cfa0ad2SJack F Vogel static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
13638cfa0ad2SJack F Vogel {
13648cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
13658cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
13668cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
13678cfa0ad2SJack F Vogel 	u32 i = 0;
13688cfa0ad2SJack F Vogel 
13698cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_flash_cycle_ich8lan");
13708cfa0ad2SJack F Vogel 
13718cfa0ad2SJack F Vogel 	/* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
13728cfa0ad2SJack F Vogel 	hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
13738cfa0ad2SJack F Vogel 	hsflctl.hsf_ctrl.flcgo = 1;
13748cfa0ad2SJack F Vogel 	E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
13758cfa0ad2SJack F Vogel 
13768cfa0ad2SJack F Vogel 	/* wait till FDONE bit is set to 1 */
13778cfa0ad2SJack F Vogel 	do {
13788cfa0ad2SJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
13798cfa0ad2SJack F Vogel 		if (hsfsts.hsf_status.flcdone == 1)
13808cfa0ad2SJack F Vogel 			break;
13818cfa0ad2SJack F Vogel 		usec_delay(1);
13828cfa0ad2SJack F Vogel 	} while (i++ < timeout);
13838cfa0ad2SJack F Vogel 
13848cfa0ad2SJack F Vogel 	if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
13858cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
13868cfa0ad2SJack F Vogel 
13878cfa0ad2SJack F Vogel 	return ret_val;
13888cfa0ad2SJack F Vogel }
13898cfa0ad2SJack F Vogel 
13908cfa0ad2SJack F Vogel /**
13918cfa0ad2SJack F Vogel  *  e1000_read_flash_word_ich8lan - Read word from flash
13928cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
13938cfa0ad2SJack F Vogel  *  @offset: offset to data location
13948cfa0ad2SJack F Vogel  *  @data: pointer to the location for storing the data
13958cfa0ad2SJack F Vogel  *
13968cfa0ad2SJack F Vogel  *  Reads the flash word at offset into data.  Offset is converted
13978cfa0ad2SJack F Vogel  *  to bytes before read.
13988cfa0ad2SJack F Vogel  **/
13998cfa0ad2SJack F Vogel static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset,
14008cfa0ad2SJack F Vogel                                          u16 *data)
14018cfa0ad2SJack F Vogel {
14028cfa0ad2SJack F Vogel 	s32 ret_val;
14038cfa0ad2SJack F Vogel 
14048cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_word_ich8lan");
14058cfa0ad2SJack F Vogel 
14068cfa0ad2SJack F Vogel 	if (!data) {
14078cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
14088cfa0ad2SJack F Vogel 		goto out;
14098cfa0ad2SJack F Vogel 	}
14108cfa0ad2SJack F Vogel 
14118cfa0ad2SJack F Vogel 	/* Must convert offset into bytes. */
14128cfa0ad2SJack F Vogel 	offset <<= 1;
14138cfa0ad2SJack F Vogel 
14148cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
14158cfa0ad2SJack F Vogel 
14168cfa0ad2SJack F Vogel out:
14178cfa0ad2SJack F Vogel 	return ret_val;
14188cfa0ad2SJack F Vogel }
14198cfa0ad2SJack F Vogel 
14208cfa0ad2SJack F Vogel /**
14218cfa0ad2SJack F Vogel  *  e1000_read_flash_byte_ich8lan - Read byte from flash
14228cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
14238cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to read.
14248cfa0ad2SJack F Vogel  *  @data: Pointer to a byte to store the value read.
14258cfa0ad2SJack F Vogel  *
14268cfa0ad2SJack F Vogel  *  Reads a single byte from the NVM using the flash access registers.
14278cfa0ad2SJack F Vogel  **/
14288cfa0ad2SJack F Vogel static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
14298cfa0ad2SJack F Vogel                                          u8 *data)
14308cfa0ad2SJack F Vogel {
14318cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
14328cfa0ad2SJack F Vogel 	u16 word = 0;
14338cfa0ad2SJack F Vogel 
14348cfa0ad2SJack F Vogel 	ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
14358cfa0ad2SJack F Vogel 	if (ret_val)
14368cfa0ad2SJack F Vogel 		goto out;
14378cfa0ad2SJack F Vogel 
14388cfa0ad2SJack F Vogel 	*data = (u8)word;
14398cfa0ad2SJack F Vogel 
14408cfa0ad2SJack F Vogel out:
14418cfa0ad2SJack F Vogel 	return ret_val;
14428cfa0ad2SJack F Vogel }
14438cfa0ad2SJack F Vogel 
14448cfa0ad2SJack F Vogel /**
14458cfa0ad2SJack F Vogel  *  e1000_read_flash_data_ich8lan - Read byte or word from NVM
14468cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
14478cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte or word to read.
14488cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
14498cfa0ad2SJack F Vogel  *  @data: Pointer to the word to store the value read.
14508cfa0ad2SJack F Vogel  *
14518cfa0ad2SJack F Vogel  *  Reads a byte or word from the NVM using the flash access registers.
14528cfa0ad2SJack F Vogel  **/
14538cfa0ad2SJack F Vogel static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
14548cfa0ad2SJack F Vogel                                          u8 size, u16 *data)
14558cfa0ad2SJack F Vogel {
14568cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
14578cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
14588cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
14598cfa0ad2SJack F Vogel 	u32 flash_data = 0;
14608cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
14618cfa0ad2SJack F Vogel 	u8 count = 0;
14628cfa0ad2SJack F Vogel 
14638cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_read_flash_data_ich8lan");
14648cfa0ad2SJack F Vogel 
14658cfa0ad2SJack F Vogel 	if (size < 1  || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
14668cfa0ad2SJack F Vogel 		goto out;
14678cfa0ad2SJack F Vogel 
14688cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
14698cfa0ad2SJack F Vogel 	                    hw->nvm.flash_base_addr;
14708cfa0ad2SJack F Vogel 
14718cfa0ad2SJack F Vogel 	do {
14728cfa0ad2SJack F Vogel 		usec_delay(1);
14738cfa0ad2SJack F Vogel 		/* Steps */
14748cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
14758cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
14768cfa0ad2SJack F Vogel 			break;
14778cfa0ad2SJack F Vogel 
14788cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
14798cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
14808cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
14818cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
14828cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
14838cfa0ad2SJack F Vogel 
14848cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
14858cfa0ad2SJack F Vogel 
14868cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
14878cfa0ad2SJack F Vogel 		                                ICH_FLASH_READ_COMMAND_TIMEOUT);
14888cfa0ad2SJack F Vogel 
14898cfa0ad2SJack F Vogel 		/*
14908cfa0ad2SJack F Vogel 		 * Check if FCERR is set to 1, if set to 1, clear it
14918cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times, else
14928cfa0ad2SJack F Vogel 		 * read in (shift in) the Flash Data0, the order is
14938cfa0ad2SJack F Vogel 		 * least significant byte first msb to lsb
14948cfa0ad2SJack F Vogel 		 */
14958cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS) {
14968cfa0ad2SJack F Vogel 			flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
1497daf9197cSJack F Vogel 			if (size == 1)
14988cfa0ad2SJack F Vogel 				*data = (u8)(flash_data & 0x000000FF);
1499daf9197cSJack F Vogel 			else if (size == 2)
15008cfa0ad2SJack F Vogel 				*data = (u16)(flash_data & 0x0000FFFF);
15018cfa0ad2SJack F Vogel 			break;
15028cfa0ad2SJack F Vogel 		} else {
15038cfa0ad2SJack F Vogel 			/*
15048cfa0ad2SJack F Vogel 			 * If we've gotten here, then things are probably
15058cfa0ad2SJack F Vogel 			 * completely hosed, but if the error condition is
15068cfa0ad2SJack F Vogel 			 * detected, it won't hurt to give it another try...
15078cfa0ad2SJack F Vogel 			 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
15088cfa0ad2SJack F Vogel 			 */
15098cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
15108cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFSTS);
15118cfa0ad2SJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1) {
15128cfa0ad2SJack F Vogel 				/* Repeat for some time before giving up. */
15138cfa0ad2SJack F Vogel 				continue;
15148cfa0ad2SJack F Vogel 			} else if (hsfsts.hsf_status.flcdone == 0) {
15158cfa0ad2SJack F Vogel 				DEBUGOUT("Timeout error - flash cycle "
15168cfa0ad2SJack F Vogel 				         "did not complete.");
15178cfa0ad2SJack F Vogel 				break;
15188cfa0ad2SJack F Vogel 			}
15198cfa0ad2SJack F Vogel 		}
15208cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
15218cfa0ad2SJack F Vogel 
15228cfa0ad2SJack F Vogel out:
15238cfa0ad2SJack F Vogel 	return ret_val;
15248cfa0ad2SJack F Vogel }
15258cfa0ad2SJack F Vogel 
15268cfa0ad2SJack F Vogel /**
15278cfa0ad2SJack F Vogel  *  e1000_write_nvm_ich8lan - Write word(s) to the NVM
15288cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
15298cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the word(s) to write.
15308cfa0ad2SJack F Vogel  *  @words: Size of data to write in words
15318cfa0ad2SJack F Vogel  *  @data: Pointer to the word(s) to write at offset.
15328cfa0ad2SJack F Vogel  *
15338cfa0ad2SJack F Vogel  *  Writes a byte or word to the NVM using the flash access registers.
15348cfa0ad2SJack F Vogel  **/
15358cfa0ad2SJack F Vogel static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
15368cfa0ad2SJack F Vogel                                    u16 *data)
15378cfa0ad2SJack F Vogel {
15388cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
1539daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
15408cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
15418cfa0ad2SJack F Vogel 	u16 i;
15428cfa0ad2SJack F Vogel 
15438cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_nvm_ich8lan");
15448cfa0ad2SJack F Vogel 
15458cfa0ad2SJack F Vogel 	if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
15468cfa0ad2SJack F Vogel 	    (words == 0)) {
15478cfa0ad2SJack F Vogel 		DEBUGOUT("nvm parameter(s) out of bounds\n");
15488cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
15498cfa0ad2SJack F Vogel 		goto out;
15508cfa0ad2SJack F Vogel 	}
15518cfa0ad2SJack F Vogel 
15528cfa0ad2SJack F Vogel 	ret_val = nvm->ops.acquire(hw);
15538cfa0ad2SJack F Vogel 	if (ret_val)
15548cfa0ad2SJack F Vogel 		goto out;
15558cfa0ad2SJack F Vogel 
15568cfa0ad2SJack F Vogel 	for (i = 0; i < words; i++) {
15578cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].modified = TRUE;
15588cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[offset+i].value = data[i];
15598cfa0ad2SJack F Vogel 	}
15608cfa0ad2SJack F Vogel 
15618cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
15628cfa0ad2SJack F Vogel 
15638cfa0ad2SJack F Vogel out:
15648cfa0ad2SJack F Vogel 	return ret_val;
15658cfa0ad2SJack F Vogel }
15668cfa0ad2SJack F Vogel 
15678cfa0ad2SJack F Vogel /**
15688cfa0ad2SJack F Vogel  *  e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
15698cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
15708cfa0ad2SJack F Vogel  *
15718cfa0ad2SJack F Vogel  *  The NVM checksum is updated by calling the generic update_nvm_checksum,
15728cfa0ad2SJack F Vogel  *  which writes the checksum to the shadow ram.  The changes in the shadow
15738cfa0ad2SJack F Vogel  *  ram are then committed to the EEPROM by processing each bank at a time
15748cfa0ad2SJack F Vogel  *  checking for the modified bit and writing only the pending changes.
15758cfa0ad2SJack F Vogel  *  After a successful commit, the shadow ram is cleared and is ready for
15768cfa0ad2SJack F Vogel  *  future writes.
15778cfa0ad2SJack F Vogel  **/
15788cfa0ad2SJack F Vogel static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
15798cfa0ad2SJack F Vogel {
15808cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
1581daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
15828cfa0ad2SJack F Vogel 	u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
15838cfa0ad2SJack F Vogel 	s32 ret_val;
15848cfa0ad2SJack F Vogel 	u16 data;
15858cfa0ad2SJack F Vogel 
15868cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
15878cfa0ad2SJack F Vogel 
15888cfa0ad2SJack F Vogel 	ret_val = e1000_update_nvm_checksum_generic(hw);
15898cfa0ad2SJack F Vogel 	if (ret_val)
15908cfa0ad2SJack F Vogel 		goto out;
15918cfa0ad2SJack F Vogel 
15928cfa0ad2SJack F Vogel 	if (nvm->type != e1000_nvm_flash_sw)
15938cfa0ad2SJack F Vogel 		goto out;
15948cfa0ad2SJack F Vogel 
15958cfa0ad2SJack F Vogel 	ret_val = nvm->ops.acquire(hw);
15968cfa0ad2SJack F Vogel 	if (ret_val)
15978cfa0ad2SJack F Vogel 		goto out;
15988cfa0ad2SJack F Vogel 
15998cfa0ad2SJack F Vogel 	/*
16008cfa0ad2SJack F Vogel 	 * We're writing to the opposite bank so if we're on bank 1,
16018cfa0ad2SJack F Vogel 	 * write to bank 0 etc.  We also need to erase the segment that
16028cfa0ad2SJack F Vogel 	 * is going to be written
16038cfa0ad2SJack F Vogel 	 */
16048cfa0ad2SJack F Vogel 	ret_val =  e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
1605d035aa2dSJack F Vogel 	if (ret_val != E1000_SUCCESS) {
1606d035aa2dSJack F Vogel 		nvm->ops.release(hw);
16078cfa0ad2SJack F Vogel 		goto out;
1608d035aa2dSJack F Vogel 	}
16098cfa0ad2SJack F Vogel 
16108cfa0ad2SJack F Vogel 	if (bank == 0) {
16118cfa0ad2SJack F Vogel 		new_bank_offset = nvm->flash_bank_size;
16128cfa0ad2SJack F Vogel 		old_bank_offset = 0;
1613d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
1614d035aa2dSJack F Vogel 		if (ret_val) {
1615d035aa2dSJack F Vogel 			nvm->ops.release(hw);
1616d035aa2dSJack F Vogel 			goto out;
1617d035aa2dSJack F Vogel 		}
16188cfa0ad2SJack F Vogel 	} else {
16198cfa0ad2SJack F Vogel 		old_bank_offset = nvm->flash_bank_size;
16208cfa0ad2SJack F Vogel 		new_bank_offset = 0;
1621d035aa2dSJack F Vogel 		ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
1622d035aa2dSJack F Vogel 		if (ret_val) {
1623d035aa2dSJack F Vogel 			nvm->ops.release(hw);
1624d035aa2dSJack F Vogel 			goto out;
1625d035aa2dSJack F Vogel 		}
16268cfa0ad2SJack F Vogel 	}
16278cfa0ad2SJack F Vogel 
16288cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
16298cfa0ad2SJack F Vogel 		/*
16308cfa0ad2SJack F Vogel 		 * Determine whether to write the value stored
16318cfa0ad2SJack F Vogel 		 * in the other NVM bank or a modified value stored
16328cfa0ad2SJack F Vogel 		 * in the shadow RAM
16338cfa0ad2SJack F Vogel 		 */
16348cfa0ad2SJack F Vogel 		if (dev_spec->shadow_ram[i].modified) {
16358cfa0ad2SJack F Vogel 			data = dev_spec->shadow_ram[i].value;
16368cfa0ad2SJack F Vogel 		} else {
1637d035aa2dSJack F Vogel 			ret_val = e1000_read_flash_word_ich8lan(hw, i +
1638d035aa2dSJack F Vogel 			                                        old_bank_offset,
16398cfa0ad2SJack F Vogel 			                                        &data);
1640d035aa2dSJack F Vogel 			if (ret_val)
1641d035aa2dSJack F Vogel 				break;
16428cfa0ad2SJack F Vogel 		}
16438cfa0ad2SJack F Vogel 
16448cfa0ad2SJack F Vogel 		/*
16458cfa0ad2SJack F Vogel 		 * If the word is 0x13, then make sure the signature bits
16468cfa0ad2SJack F Vogel 		 * (15:14) are 11b until the commit has completed.
16478cfa0ad2SJack F Vogel 		 * This will allow us to write 10b which indicates the
16488cfa0ad2SJack F Vogel 		 * signature is valid.  We want to do this after the write
16498cfa0ad2SJack F Vogel 		 * has completed so that we don't mark the segment valid
16508cfa0ad2SJack F Vogel 		 * while the write is still in progress
16518cfa0ad2SJack F Vogel 		 */
16528cfa0ad2SJack F Vogel 		if (i == E1000_ICH_NVM_SIG_WORD)
16538cfa0ad2SJack F Vogel 			data |= E1000_ICH_NVM_SIG_MASK;
16548cfa0ad2SJack F Vogel 
16558cfa0ad2SJack F Vogel 		/* Convert offset to bytes. */
16568cfa0ad2SJack F Vogel 		act_offset = (i + new_bank_offset) << 1;
16578cfa0ad2SJack F Vogel 
16588cfa0ad2SJack F Vogel 		usec_delay(100);
16598cfa0ad2SJack F Vogel 		/* Write the bytes to the new bank. */
16608cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
16618cfa0ad2SJack F Vogel 		                                               act_offset,
16628cfa0ad2SJack F Vogel 		                                               (u8)data);
16638cfa0ad2SJack F Vogel 		if (ret_val)
16648cfa0ad2SJack F Vogel 			break;
16658cfa0ad2SJack F Vogel 
16668cfa0ad2SJack F Vogel 		usec_delay(100);
16678cfa0ad2SJack F Vogel 		ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
16688cfa0ad2SJack F Vogel 		                                          act_offset + 1,
16698cfa0ad2SJack F Vogel 		                                          (u8)(data >> 8));
16708cfa0ad2SJack F Vogel 		if (ret_val)
16718cfa0ad2SJack F Vogel 			break;
16728cfa0ad2SJack F Vogel 	}
16738cfa0ad2SJack F Vogel 
16748cfa0ad2SJack F Vogel 	/*
16758cfa0ad2SJack F Vogel 	 * Don't bother writing the segment valid bits if sector
16768cfa0ad2SJack F Vogel 	 * programming failed.
16778cfa0ad2SJack F Vogel 	 */
16788cfa0ad2SJack F Vogel 	if (ret_val) {
16798cfa0ad2SJack F Vogel 		DEBUGOUT("Flash commit failed.\n");
16808cfa0ad2SJack F Vogel 		nvm->ops.release(hw);
16818cfa0ad2SJack F Vogel 		goto out;
16828cfa0ad2SJack F Vogel 	}
16838cfa0ad2SJack F Vogel 
16848cfa0ad2SJack F Vogel 	/*
16858cfa0ad2SJack F Vogel 	 * Finally validate the new segment by setting bit 15:14
16868cfa0ad2SJack F Vogel 	 * to 10b in word 0x13 , this can be done without an
16878cfa0ad2SJack F Vogel 	 * erase as well since these bits are 11 to start with
16888cfa0ad2SJack F Vogel 	 * and we need to change bit 14 to 0b
16898cfa0ad2SJack F Vogel 	 */
16908cfa0ad2SJack F Vogel 	act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
1691d035aa2dSJack F Vogel 	ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
1692d035aa2dSJack F Vogel 	if (ret_val) {
1693d035aa2dSJack F Vogel 		nvm->ops.release(hw);
1694d035aa2dSJack F Vogel 		goto out;
1695d035aa2dSJack F Vogel 	}
16968cfa0ad2SJack F Vogel 	data &= 0xBFFF;
16978cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
16988cfa0ad2SJack F Vogel 	                                               act_offset * 2 + 1,
16998cfa0ad2SJack F Vogel 	                                               (u8)(data >> 8));
17008cfa0ad2SJack F Vogel 	if (ret_val) {
17018cfa0ad2SJack F Vogel 		nvm->ops.release(hw);
17028cfa0ad2SJack F Vogel 		goto out;
17038cfa0ad2SJack F Vogel 	}
17048cfa0ad2SJack F Vogel 
17058cfa0ad2SJack F Vogel 	/*
17068cfa0ad2SJack F Vogel 	 * And invalidate the previously valid segment by setting
17078cfa0ad2SJack F Vogel 	 * its signature word (0x13) high_byte to 0b. This can be
17088cfa0ad2SJack F Vogel 	 * done without an erase because flash erase sets all bits
17098cfa0ad2SJack F Vogel 	 * to 1's. We can write 1's to 0's without an erase
17108cfa0ad2SJack F Vogel 	 */
17118cfa0ad2SJack F Vogel 	act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
17128cfa0ad2SJack F Vogel 	ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
17138cfa0ad2SJack F Vogel 	if (ret_val) {
17148cfa0ad2SJack F Vogel 		nvm->ops.release(hw);
17158cfa0ad2SJack F Vogel 		goto out;
17168cfa0ad2SJack F Vogel 	}
17178cfa0ad2SJack F Vogel 
17188cfa0ad2SJack F Vogel 	/* Great!  Everything worked, we can now clear the cached entries. */
17198cfa0ad2SJack F Vogel 	for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
17208cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].modified = FALSE;
17218cfa0ad2SJack F Vogel 		dev_spec->shadow_ram[i].value = 0xFFFF;
17228cfa0ad2SJack F Vogel 	}
17238cfa0ad2SJack F Vogel 
17248cfa0ad2SJack F Vogel 	nvm->ops.release(hw);
17258cfa0ad2SJack F Vogel 
17268cfa0ad2SJack F Vogel 	/*
17278cfa0ad2SJack F Vogel 	 * Reload the EEPROM, or else modifications will not appear
17288cfa0ad2SJack F Vogel 	 * until after the next adapter reset.
17298cfa0ad2SJack F Vogel 	 */
17308cfa0ad2SJack F Vogel 	nvm->ops.reload(hw);
17318cfa0ad2SJack F Vogel 	msec_delay(10);
17328cfa0ad2SJack F Vogel 
17338cfa0ad2SJack F Vogel out:
1734d035aa2dSJack F Vogel 	if (ret_val)
1735d035aa2dSJack F Vogel 		DEBUGOUT1("NVM update error: %d\n", ret_val);
1736d035aa2dSJack F Vogel 
17378cfa0ad2SJack F Vogel 	return ret_val;
17388cfa0ad2SJack F Vogel }
17398cfa0ad2SJack F Vogel 
17408cfa0ad2SJack F Vogel /**
17418cfa0ad2SJack F Vogel  *  e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
17428cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
17438cfa0ad2SJack F Vogel  *
17448cfa0ad2SJack F Vogel  *  Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
1745daf9197cSJack F Vogel  *  If the bit is 0, that the EEPROM had been modified, but the checksum was not
1746daf9197cSJack F Vogel  *  calculated, in which case we need to calculate the checksum and set bit 6.
17478cfa0ad2SJack F Vogel  **/
17488cfa0ad2SJack F Vogel static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
17498cfa0ad2SJack F Vogel {
17508cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
17518cfa0ad2SJack F Vogel 	u16 data;
17528cfa0ad2SJack F Vogel 
17538cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
17548cfa0ad2SJack F Vogel 
17558cfa0ad2SJack F Vogel 	/*
17568cfa0ad2SJack F Vogel 	 * Read 0x19 and check bit 6.  If this bit is 0, the checksum
17578cfa0ad2SJack F Vogel 	 * needs to be fixed.  This bit is an indication that the NVM
17588cfa0ad2SJack F Vogel 	 * was prepared by OEM software and did not calculate the
17598cfa0ad2SJack F Vogel 	 * checksum...a likely scenario.
17608cfa0ad2SJack F Vogel 	 */
17618cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
17628cfa0ad2SJack F Vogel 	if (ret_val)
17638cfa0ad2SJack F Vogel 		goto out;
17648cfa0ad2SJack F Vogel 
17658cfa0ad2SJack F Vogel 	if ((data & 0x40) == 0) {
17668cfa0ad2SJack F Vogel 		data |= 0x40;
17678cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
17688cfa0ad2SJack F Vogel 		if (ret_val)
17698cfa0ad2SJack F Vogel 			goto out;
17708cfa0ad2SJack F Vogel 		ret_val = hw->nvm.ops.update(hw);
17718cfa0ad2SJack F Vogel 		if (ret_val)
17728cfa0ad2SJack F Vogel 			goto out;
17738cfa0ad2SJack F Vogel 	}
17748cfa0ad2SJack F Vogel 
17758cfa0ad2SJack F Vogel 	ret_val = e1000_validate_nvm_checksum_generic(hw);
17768cfa0ad2SJack F Vogel 
17778cfa0ad2SJack F Vogel out:
17788cfa0ad2SJack F Vogel 	return ret_val;
17798cfa0ad2SJack F Vogel }
17808cfa0ad2SJack F Vogel 
17818cfa0ad2SJack F Vogel /**
17828cfa0ad2SJack F Vogel  *  e1000_write_flash_data_ich8lan - Writes bytes to the NVM
17838cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
17848cfa0ad2SJack F Vogel  *  @offset: The offset (in bytes) of the byte/word to read.
17858cfa0ad2SJack F Vogel  *  @size: Size of data to read, 1=byte 2=word
17868cfa0ad2SJack F Vogel  *  @data: The byte(s) to write to the NVM.
17878cfa0ad2SJack F Vogel  *
17888cfa0ad2SJack F Vogel  *  Writes one/two bytes to the NVM using the flash access registers.
17898cfa0ad2SJack F Vogel  **/
17908cfa0ad2SJack F Vogel static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
17918cfa0ad2SJack F Vogel                                           u8 size, u16 data)
17928cfa0ad2SJack F Vogel {
17938cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
17948cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
17958cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
17968cfa0ad2SJack F Vogel 	u32 flash_data = 0;
17978cfa0ad2SJack F Vogel 	s32 ret_val = -E1000_ERR_NVM;
17988cfa0ad2SJack F Vogel 	u8 count = 0;
17998cfa0ad2SJack F Vogel 
18008cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_ich8_data");
18018cfa0ad2SJack F Vogel 
18028cfa0ad2SJack F Vogel 	if (size < 1 || size > 2 || data > size * 0xff ||
18038cfa0ad2SJack F Vogel 	    offset > ICH_FLASH_LINEAR_ADDR_MASK)
18048cfa0ad2SJack F Vogel 		goto out;
18058cfa0ad2SJack F Vogel 
18068cfa0ad2SJack F Vogel 	flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
18078cfa0ad2SJack F Vogel 	                    hw->nvm.flash_base_addr;
18088cfa0ad2SJack F Vogel 
18098cfa0ad2SJack F Vogel 	do {
18108cfa0ad2SJack F Vogel 		usec_delay(1);
18118cfa0ad2SJack F Vogel 		/* Steps */
18128cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_init_ich8lan(hw);
18138cfa0ad2SJack F Vogel 		if (ret_val != E1000_SUCCESS)
18148cfa0ad2SJack F Vogel 			break;
18158cfa0ad2SJack F Vogel 
18168cfa0ad2SJack F Vogel 		hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
18178cfa0ad2SJack F Vogel 		/* 0b/1b corresponds to 1 or 2 byte size, respectively. */
18188cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.fldbcount = size - 1;
18198cfa0ad2SJack F Vogel 		hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
18208cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
18218cfa0ad2SJack F Vogel 
18228cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
18238cfa0ad2SJack F Vogel 
18248cfa0ad2SJack F Vogel 		if (size == 1)
18258cfa0ad2SJack F Vogel 			flash_data = (u32)data & 0x00FF;
18268cfa0ad2SJack F Vogel 		else
18278cfa0ad2SJack F Vogel 			flash_data = (u32)data;
18288cfa0ad2SJack F Vogel 
18298cfa0ad2SJack F Vogel 		E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
18308cfa0ad2SJack F Vogel 
18318cfa0ad2SJack F Vogel 		/*
18328cfa0ad2SJack F Vogel 		 * check if FCERR is set to 1 , if set to 1, clear it
18338cfa0ad2SJack F Vogel 		 * and try the whole sequence a few more times else done
18348cfa0ad2SJack F Vogel 		 */
18358cfa0ad2SJack F Vogel 		ret_val = e1000_flash_cycle_ich8lan(hw,
18368cfa0ad2SJack F Vogel 		                               ICH_FLASH_WRITE_COMMAND_TIMEOUT);
1837daf9197cSJack F Vogel 		if (ret_val == E1000_SUCCESS)
18388cfa0ad2SJack F Vogel 			break;
1839daf9197cSJack F Vogel 
18408cfa0ad2SJack F Vogel 		/*
18418cfa0ad2SJack F Vogel 		 * If we're here, then things are most likely
18428cfa0ad2SJack F Vogel 		 * completely hosed, but if the error condition
18438cfa0ad2SJack F Vogel 		 * is detected, it won't hurt to give it another
18448cfa0ad2SJack F Vogel 		 * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
18458cfa0ad2SJack F Vogel 		 */
1846daf9197cSJack F Vogel 		hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
18478cfa0ad2SJack F Vogel 		if (hsfsts.hsf_status.flcerr == 1) {
18488cfa0ad2SJack F Vogel 			/* Repeat for some time before giving up. */
18498cfa0ad2SJack F Vogel 			continue;
18508cfa0ad2SJack F Vogel 		} else if (hsfsts.hsf_status.flcdone == 0) {
18518cfa0ad2SJack F Vogel 			DEBUGOUT("Timeout error - flash cycle "
18528cfa0ad2SJack F Vogel 				 "did not complete.");
18538cfa0ad2SJack F Vogel 			break;
18548cfa0ad2SJack F Vogel 		}
18558cfa0ad2SJack F Vogel 	} while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
18568cfa0ad2SJack F Vogel 
18578cfa0ad2SJack F Vogel out:
18588cfa0ad2SJack F Vogel 	return ret_val;
18598cfa0ad2SJack F Vogel }
18608cfa0ad2SJack F Vogel 
18618cfa0ad2SJack F Vogel /**
18628cfa0ad2SJack F Vogel  *  e1000_write_flash_byte_ich8lan - Write a single byte to NVM
18638cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18648cfa0ad2SJack F Vogel  *  @offset: The index of the byte to read.
18658cfa0ad2SJack F Vogel  *  @data: The byte to write to the NVM.
18668cfa0ad2SJack F Vogel  *
18678cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
18688cfa0ad2SJack F Vogel  **/
18698cfa0ad2SJack F Vogel static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset,
18708cfa0ad2SJack F Vogel                                           u8 data)
18718cfa0ad2SJack F Vogel {
18728cfa0ad2SJack F Vogel 	u16 word = (u16)data;
18738cfa0ad2SJack F Vogel 
18748cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_write_flash_byte_ich8lan");
18758cfa0ad2SJack F Vogel 
18768cfa0ad2SJack F Vogel 	return e1000_write_flash_data_ich8lan(hw, offset, 1, word);
18778cfa0ad2SJack F Vogel }
18788cfa0ad2SJack F Vogel 
18798cfa0ad2SJack F Vogel /**
18808cfa0ad2SJack F Vogel  *  e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
18818cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
18828cfa0ad2SJack F Vogel  *  @offset: The offset of the byte to write.
18838cfa0ad2SJack F Vogel  *  @byte: The byte to write to the NVM.
18848cfa0ad2SJack F Vogel  *
18858cfa0ad2SJack F Vogel  *  Writes a single byte to the NVM using the flash access registers.
18868cfa0ad2SJack F Vogel  *  Goes through a retry algorithm before giving up.
18878cfa0ad2SJack F Vogel  **/
18888cfa0ad2SJack F Vogel static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
18898cfa0ad2SJack F Vogel                                                 u32 offset, u8 byte)
18908cfa0ad2SJack F Vogel {
18918cfa0ad2SJack F Vogel 	s32 ret_val;
18928cfa0ad2SJack F Vogel 	u16 program_retries;
18938cfa0ad2SJack F Vogel 
18948cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
18958cfa0ad2SJack F Vogel 
18968cfa0ad2SJack F Vogel 	ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
18978cfa0ad2SJack F Vogel 	if (ret_val == E1000_SUCCESS)
18988cfa0ad2SJack F Vogel 		goto out;
18998cfa0ad2SJack F Vogel 
19008cfa0ad2SJack F Vogel 	for (program_retries = 0; program_retries < 100; program_retries++) {
19018cfa0ad2SJack F Vogel 		DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
19028cfa0ad2SJack F Vogel 		usec_delay(100);
19038cfa0ad2SJack F Vogel 		ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
19048cfa0ad2SJack F Vogel 		if (ret_val == E1000_SUCCESS)
19058cfa0ad2SJack F Vogel 			break;
19068cfa0ad2SJack F Vogel 	}
19078cfa0ad2SJack F Vogel 	if (program_retries == 100) {
19088cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
19098cfa0ad2SJack F Vogel 		goto out;
19108cfa0ad2SJack F Vogel 	}
19118cfa0ad2SJack F Vogel 
19128cfa0ad2SJack F Vogel out:
19138cfa0ad2SJack F Vogel 	return ret_val;
19148cfa0ad2SJack F Vogel }
19158cfa0ad2SJack F Vogel 
19168cfa0ad2SJack F Vogel /**
19178cfa0ad2SJack F Vogel  *  e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
19188cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
19198cfa0ad2SJack F Vogel  *  @bank: 0 for first bank, 1 for second bank, etc.
19208cfa0ad2SJack F Vogel  *
19218cfa0ad2SJack F Vogel  *  Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
19228cfa0ad2SJack F Vogel  *  bank N is 4096 * N + flash_reg_addr.
19238cfa0ad2SJack F Vogel  **/
19248cfa0ad2SJack F Vogel static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
19258cfa0ad2SJack F Vogel {
19268cfa0ad2SJack F Vogel 	struct e1000_nvm_info *nvm = &hw->nvm;
19278cfa0ad2SJack F Vogel 	union ich8_hws_flash_status hsfsts;
19288cfa0ad2SJack F Vogel 	union ich8_hws_flash_ctrl hsflctl;
19298cfa0ad2SJack F Vogel 	u32 flash_linear_addr;
19308cfa0ad2SJack F Vogel 	/* bank size is in 16bit words - adjust to bytes */
19318cfa0ad2SJack F Vogel 	u32 flash_bank_size = nvm->flash_bank_size * 2;
19328cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
19338cfa0ad2SJack F Vogel 	s32 count = 0;
19348cfa0ad2SJack F Vogel 	s32 j, iteration, sector_size;
19358cfa0ad2SJack F Vogel 
19368cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
19378cfa0ad2SJack F Vogel 
19388cfa0ad2SJack F Vogel 	hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
19398cfa0ad2SJack F Vogel 
19408cfa0ad2SJack F Vogel 	/*
19418cfa0ad2SJack F Vogel 	 * Determine HW Sector size: Read BERASE bits of hw flash status
19428cfa0ad2SJack F Vogel 	 * register
19438cfa0ad2SJack F Vogel 	 * 00: The Hw sector is 256 bytes, hence we need to erase 16
19448cfa0ad2SJack F Vogel 	 *     consecutive sectors.  The start index for the nth Hw sector
19458cfa0ad2SJack F Vogel 	 *     can be calculated as = bank * 4096 + n * 256
19468cfa0ad2SJack F Vogel 	 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
19478cfa0ad2SJack F Vogel 	 *     The start index for the nth Hw sector can be calculated
19488cfa0ad2SJack F Vogel 	 *     as = bank * 4096
19498cfa0ad2SJack F Vogel 	 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
19508cfa0ad2SJack F Vogel 	 *     (ich9 only, otherwise error condition)
19518cfa0ad2SJack F Vogel 	 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
19528cfa0ad2SJack F Vogel 	 */
19538cfa0ad2SJack F Vogel 	switch (hsfsts.hsf_status.berasesz) {
19548cfa0ad2SJack F Vogel 	case 0:
19558cfa0ad2SJack F Vogel 		/* Hw sector size 256 */
19568cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_256;
19578cfa0ad2SJack F Vogel 		iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
19588cfa0ad2SJack F Vogel 		break;
19598cfa0ad2SJack F Vogel 	case 1:
19608cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_4K;
19619d81738fSJack F Vogel 		iteration = 1;
19628cfa0ad2SJack F Vogel 		break;
19638cfa0ad2SJack F Vogel 	case 2:
19648cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich9lan) {
19658cfa0ad2SJack F Vogel 			sector_size = ICH_FLASH_SEG_SIZE_8K;
19668cfa0ad2SJack F Vogel 			iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_8K;
19678cfa0ad2SJack F Vogel 		} else {
19688cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_NVM;
19698cfa0ad2SJack F Vogel 			goto out;
19708cfa0ad2SJack F Vogel 		}
19718cfa0ad2SJack F Vogel 		break;
19728cfa0ad2SJack F Vogel 	case 3:
19738cfa0ad2SJack F Vogel 		sector_size = ICH_FLASH_SEG_SIZE_64K;
19749d81738fSJack F Vogel 		iteration = 1;
19758cfa0ad2SJack F Vogel 		break;
19768cfa0ad2SJack F Vogel 	default:
19778cfa0ad2SJack F Vogel 		ret_val = -E1000_ERR_NVM;
19788cfa0ad2SJack F Vogel 		goto out;
19798cfa0ad2SJack F Vogel 	}
19808cfa0ad2SJack F Vogel 
19818cfa0ad2SJack F Vogel 	/* Start with the base address, then add the sector offset. */
19828cfa0ad2SJack F Vogel 	flash_linear_addr = hw->nvm.flash_base_addr;
19838cfa0ad2SJack F Vogel 	flash_linear_addr += (bank) ? (sector_size * iteration) : 0;
19848cfa0ad2SJack F Vogel 
19858cfa0ad2SJack F Vogel 	for (j = 0; j < iteration ; j++) {
19868cfa0ad2SJack F Vogel 		do {
19878cfa0ad2SJack F Vogel 			/* Steps */
19888cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_init_ich8lan(hw);
19898cfa0ad2SJack F Vogel 			if (ret_val)
19908cfa0ad2SJack F Vogel 				goto out;
19918cfa0ad2SJack F Vogel 
19928cfa0ad2SJack F Vogel 			/*
19938cfa0ad2SJack F Vogel 			 * Write a value 11 (block Erase) in Flash
19948cfa0ad2SJack F Vogel 			 * Cycle field in hw flash control
19958cfa0ad2SJack F Vogel 			 */
19968cfa0ad2SJack F Vogel 			hsflctl.regval = E1000_READ_FLASH_REG16(hw,
19978cfa0ad2SJack F Vogel 			                                      ICH_FLASH_HSFCTL);
19988cfa0ad2SJack F Vogel 			hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
1999daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL,
20008cfa0ad2SJack F Vogel 			                        hsflctl.regval);
20018cfa0ad2SJack F Vogel 
20028cfa0ad2SJack F Vogel 			/*
20038cfa0ad2SJack F Vogel 			 * Write the last 24 bits of an index within the
20048cfa0ad2SJack F Vogel 			 * block into Flash Linear address field in Flash
20058cfa0ad2SJack F Vogel 			 * Address.
20068cfa0ad2SJack F Vogel 			 */
20078cfa0ad2SJack F Vogel 			flash_linear_addr += (j * sector_size);
2008daf9197cSJack F Vogel 			E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR,
20098cfa0ad2SJack F Vogel 			                      flash_linear_addr);
20108cfa0ad2SJack F Vogel 
20118cfa0ad2SJack F Vogel 			ret_val = e1000_flash_cycle_ich8lan(hw,
20128cfa0ad2SJack F Vogel 			                       ICH_FLASH_ERASE_COMMAND_TIMEOUT);
2013daf9197cSJack F Vogel 			if (ret_val == E1000_SUCCESS)
20148cfa0ad2SJack F Vogel 				break;
2015daf9197cSJack F Vogel 
20168cfa0ad2SJack F Vogel 			/*
20178cfa0ad2SJack F Vogel 			 * Check if FCERR is set to 1.  If 1,
20188cfa0ad2SJack F Vogel 			 * clear it and try the whole sequence
20198cfa0ad2SJack F Vogel 			 * a few more times else Done
20208cfa0ad2SJack F Vogel 			 */
20218cfa0ad2SJack F Vogel 			hsfsts.regval = E1000_READ_FLASH_REG16(hw,
20228cfa0ad2SJack F Vogel 						      ICH_FLASH_HSFSTS);
2023daf9197cSJack F Vogel 			if (hsfsts.hsf_status.flcerr == 1)
2024daf9197cSJack F Vogel 				/* repeat for some time before giving up */
20258cfa0ad2SJack F Vogel 				continue;
2026daf9197cSJack F Vogel 			else if (hsfsts.hsf_status.flcdone == 0)
20278cfa0ad2SJack F Vogel 				goto out;
20288cfa0ad2SJack F Vogel 		} while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
20298cfa0ad2SJack F Vogel 	}
20308cfa0ad2SJack F Vogel 
20318cfa0ad2SJack F Vogel out:
20328cfa0ad2SJack F Vogel 	return ret_val;
20338cfa0ad2SJack F Vogel }
20348cfa0ad2SJack F Vogel 
20358cfa0ad2SJack F Vogel /**
20368cfa0ad2SJack F Vogel  *  e1000_valid_led_default_ich8lan - Set the default LED settings
20378cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
20388cfa0ad2SJack F Vogel  *  @data: Pointer to the LED settings
20398cfa0ad2SJack F Vogel  *
20408cfa0ad2SJack F Vogel  *  Reads the LED default settings from the NVM to data.  If the NVM LED
20418cfa0ad2SJack F Vogel  *  settings is all 0's or F's, set the LED default to a valid LED default
20428cfa0ad2SJack F Vogel  *  setting.
20438cfa0ad2SJack F Vogel  **/
20448cfa0ad2SJack F Vogel static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
20458cfa0ad2SJack F Vogel {
20468cfa0ad2SJack F Vogel 	s32 ret_val;
20478cfa0ad2SJack F Vogel 
20488cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_valid_led_default_ich8lan");
20498cfa0ad2SJack F Vogel 
20508cfa0ad2SJack F Vogel 	ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
20518cfa0ad2SJack F Vogel 	if (ret_val) {
20528cfa0ad2SJack F Vogel 		DEBUGOUT("NVM Read Error\n");
20538cfa0ad2SJack F Vogel 		goto out;
20548cfa0ad2SJack F Vogel 	}
20558cfa0ad2SJack F Vogel 
20568cfa0ad2SJack F Vogel 	if (*data == ID_LED_RESERVED_0000 ||
20578cfa0ad2SJack F Vogel 	    *data == ID_LED_RESERVED_FFFF)
20588cfa0ad2SJack F Vogel 		*data = ID_LED_DEFAULT_ICH8LAN;
20598cfa0ad2SJack F Vogel 
20608cfa0ad2SJack F Vogel out:
20618cfa0ad2SJack F Vogel 	return ret_val;
20628cfa0ad2SJack F Vogel }
20638cfa0ad2SJack F Vogel 
20648cfa0ad2SJack F Vogel /**
20659d81738fSJack F Vogel  *  e1000_id_led_init_pchlan - store LED configurations
20669d81738fSJack F Vogel  *  @hw: pointer to the HW structure
20679d81738fSJack F Vogel  *
20689d81738fSJack F Vogel  *  PCH does not control LEDs via the LEDCTL register, rather it uses
20699d81738fSJack F Vogel  *  the PHY LED configuration register.
20709d81738fSJack F Vogel  *
20719d81738fSJack F Vogel  *  PCH also does not have an "always on" or "always off" mode which
20729d81738fSJack F Vogel  *  complicates the ID feature.  Instead of using the "on" mode to indicate
20739d81738fSJack F Vogel  *  in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
20749d81738fSJack F Vogel  *  use "link_up" mode.  The LEDs will still ID on request if there is no
20759d81738fSJack F Vogel  *  link based on logic in e1000_led_[on|off]_pchlan().
20769d81738fSJack F Vogel  **/
20779d81738fSJack F Vogel static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw)
20789d81738fSJack F Vogel {
20799d81738fSJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
20809d81738fSJack F Vogel 	s32 ret_val;
20819d81738fSJack F Vogel 	const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
20829d81738fSJack F Vogel 	const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
20839d81738fSJack F Vogel 	u16 data, i, temp, shift;
20849d81738fSJack F Vogel 
20859d81738fSJack F Vogel 	DEBUGFUNC("e1000_id_led_init_pchlan");
20869d81738fSJack F Vogel 
20879d81738fSJack F Vogel 	/* Get default ID LED modes */
20889d81738fSJack F Vogel 	ret_val = hw->nvm.ops.valid_led_default(hw, &data);
20899d81738fSJack F Vogel 	if (ret_val)
20909d81738fSJack F Vogel 		goto out;
20919d81738fSJack F Vogel 
20929d81738fSJack F Vogel 	mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
20939d81738fSJack F Vogel 	mac->ledctl_mode1 = mac->ledctl_default;
20949d81738fSJack F Vogel 	mac->ledctl_mode2 = mac->ledctl_default;
20959d81738fSJack F Vogel 
20969d81738fSJack F Vogel 	for (i = 0; i < 4; i++) {
20979d81738fSJack F Vogel 		temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
20989d81738fSJack F Vogel 		shift = (i * 5);
20999d81738fSJack F Vogel 		switch (temp) {
21009d81738fSJack F Vogel 		case ID_LED_ON1_DEF2:
21019d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
21029d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
21039d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
21049d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_on << shift);
21059d81738fSJack F Vogel 			break;
21069d81738fSJack F Vogel 		case ID_LED_OFF1_DEF2:
21079d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
21089d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
21099d81738fSJack F Vogel 			mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
21109d81738fSJack F Vogel 			mac->ledctl_mode1 |= (ledctl_off << shift);
21119d81738fSJack F Vogel 			break;
21129d81738fSJack F Vogel 		default:
21139d81738fSJack F Vogel 			/* Do nothing */
21149d81738fSJack F Vogel 			break;
21159d81738fSJack F Vogel 		}
21169d81738fSJack F Vogel 		switch (temp) {
21179d81738fSJack F Vogel 		case ID_LED_DEF1_ON2:
21189d81738fSJack F Vogel 		case ID_LED_ON1_ON2:
21199d81738fSJack F Vogel 		case ID_LED_OFF1_ON2:
21209d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
21219d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_on << shift);
21229d81738fSJack F Vogel 			break;
21239d81738fSJack F Vogel 		case ID_LED_DEF1_OFF2:
21249d81738fSJack F Vogel 		case ID_LED_ON1_OFF2:
21259d81738fSJack F Vogel 		case ID_LED_OFF1_OFF2:
21269d81738fSJack F Vogel 			mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
21279d81738fSJack F Vogel 			mac->ledctl_mode2 |= (ledctl_off << shift);
21289d81738fSJack F Vogel 			break;
21299d81738fSJack F Vogel 		default:
21309d81738fSJack F Vogel 			/* Do nothing */
21319d81738fSJack F Vogel 			break;
21329d81738fSJack F Vogel 		}
21339d81738fSJack F Vogel 	}
21349d81738fSJack F Vogel 
21359d81738fSJack F Vogel out:
21369d81738fSJack F Vogel 	return ret_val;
21379d81738fSJack F Vogel }
21389d81738fSJack F Vogel 
21399d81738fSJack F Vogel /**
21408cfa0ad2SJack F Vogel  *  e1000_get_bus_info_ich8lan - Get/Set the bus type and width
21418cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
21428cfa0ad2SJack F Vogel  *
21438cfa0ad2SJack F Vogel  *  ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
21448cfa0ad2SJack F Vogel  *  register, so the the bus width is hard coded.
21458cfa0ad2SJack F Vogel  **/
21468cfa0ad2SJack F Vogel static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
21478cfa0ad2SJack F Vogel {
21488cfa0ad2SJack F Vogel 	struct e1000_bus_info *bus = &hw->bus;
21498cfa0ad2SJack F Vogel 	s32 ret_val;
21508cfa0ad2SJack F Vogel 
21518cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_bus_info_ich8lan");
21528cfa0ad2SJack F Vogel 
21538cfa0ad2SJack F Vogel 	ret_val = e1000_get_bus_info_pcie_generic(hw);
21548cfa0ad2SJack F Vogel 
21558cfa0ad2SJack F Vogel 	/*
21568cfa0ad2SJack F Vogel 	 * ICH devices are "PCI Express"-ish.  They have
21578cfa0ad2SJack F Vogel 	 * a configuration space, but do not contain
21588cfa0ad2SJack F Vogel 	 * PCI Express Capability registers, so bus width
21598cfa0ad2SJack F Vogel 	 * must be hardcoded.
21608cfa0ad2SJack F Vogel 	 */
21618cfa0ad2SJack F Vogel 	if (bus->width == e1000_bus_width_unknown)
21628cfa0ad2SJack F Vogel 		bus->width = e1000_bus_width_pcie_x1;
21638cfa0ad2SJack F Vogel 
21648cfa0ad2SJack F Vogel 	return ret_val;
21658cfa0ad2SJack F Vogel }
21668cfa0ad2SJack F Vogel 
21678cfa0ad2SJack F Vogel /**
21688cfa0ad2SJack F Vogel  *  e1000_reset_hw_ich8lan - Reset the hardware
21698cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
21708cfa0ad2SJack F Vogel  *
21718cfa0ad2SJack F Vogel  *  Does a full reset of the hardware which includes a reset of the PHY and
21728cfa0ad2SJack F Vogel  *  MAC.
21738cfa0ad2SJack F Vogel  **/
21748cfa0ad2SJack F Vogel static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
21758cfa0ad2SJack F Vogel {
21768cfa0ad2SJack F Vogel 	u32 ctrl, icr, kab;
21778cfa0ad2SJack F Vogel 	s32 ret_val;
21788cfa0ad2SJack F Vogel 
21798cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_reset_hw_ich8lan");
21808cfa0ad2SJack F Vogel 
21818cfa0ad2SJack F Vogel 	/*
21828cfa0ad2SJack F Vogel 	 * Prevent the PCI-E bus from sticking if there is no TLP connection
21838cfa0ad2SJack F Vogel 	 * on the last TLP read/write transaction when MAC is reset.
21848cfa0ad2SJack F Vogel 	 */
21858cfa0ad2SJack F Vogel 	ret_val = e1000_disable_pcie_master_generic(hw);
2186daf9197cSJack F Vogel 	if (ret_val)
21878cfa0ad2SJack F Vogel 		DEBUGOUT("PCI-E Master disable polling has failed.\n");
21888cfa0ad2SJack F Vogel 
21898cfa0ad2SJack F Vogel 	DEBUGOUT("Masking off all interrupts\n");
21908cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
21918cfa0ad2SJack F Vogel 
21928cfa0ad2SJack F Vogel 	/*
21938cfa0ad2SJack F Vogel 	 * Disable the Transmit and Receive units.  Then delay to allow
21948cfa0ad2SJack F Vogel 	 * any pending transactions to complete before we hit the MAC
21958cfa0ad2SJack F Vogel 	 * with the global reset.
21968cfa0ad2SJack F Vogel 	 */
21978cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_RCTL, 0);
21988cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
21998cfa0ad2SJack F Vogel 	E1000_WRITE_FLUSH(hw);
22008cfa0ad2SJack F Vogel 
22018cfa0ad2SJack F Vogel 	msec_delay(10);
22028cfa0ad2SJack F Vogel 
22038cfa0ad2SJack F Vogel 	/* Workaround for ICH8 bit corruption issue in FIFO memory */
22048cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
22058cfa0ad2SJack F Vogel 		/* Set Tx and Rx buffer allocation to 8k apiece. */
22068cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
22078cfa0ad2SJack F Vogel 		/* Set Packet Buffer Size to 16k. */
22088cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
22098cfa0ad2SJack F Vogel 	}
22108cfa0ad2SJack F Vogel 
22118cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
22128cfa0ad2SJack F Vogel 
22138cfa0ad2SJack F Vogel 	if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
22149d81738fSJack F Vogel 		/* Clear PHY Reset Asserted bit */
22159d81738fSJack F Vogel 		if (hw->mac.type >= e1000_pchlan) {
22169d81738fSJack F Vogel 			u32 status = E1000_READ_REG(hw, E1000_STATUS);
22179d81738fSJack F Vogel 			E1000_WRITE_REG(hw, E1000_STATUS, status &
22189d81738fSJack F Vogel 			                ~E1000_STATUS_PHYRA);
22199d81738fSJack F Vogel 		}
22209d81738fSJack F Vogel 
22218cfa0ad2SJack F Vogel 		/*
22228cfa0ad2SJack F Vogel 		 * PHY HW reset requires MAC CORE reset at the same
22238cfa0ad2SJack F Vogel 		 * time to make sure the interface between MAC and the
22248cfa0ad2SJack F Vogel 		 * external PHY is reset.
22258cfa0ad2SJack F Vogel 		 */
22268cfa0ad2SJack F Vogel 		ctrl |= E1000_CTRL_PHY_RST;
22278cfa0ad2SJack F Vogel 	}
22288cfa0ad2SJack F Vogel 	ret_val = e1000_acquire_swflag_ich8lan(hw);
2229daf9197cSJack F Vogel 	DEBUGOUT("Issuing a global reset to ich8lan\n");
22308cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
22318cfa0ad2SJack F Vogel 	msec_delay(20);
22328cfa0ad2SJack F Vogel 
22339d81738fSJack F Vogel 	if (!ret_val)
22349d81738fSJack F Vogel 		e1000_release_swflag_ich8lan(hw);
22359d81738fSJack F Vogel 
22369d81738fSJack F Vogel 	if (ctrl & E1000_CTRL_PHY_RST)
22379d81738fSJack F Vogel 		ret_val = hw->phy.ops.get_cfg_done(hw);
22389d81738fSJack F Vogel 
22399d81738fSJack F Vogel 	if (hw->mac.type >= e1000_ich10lan) {
22409d81738fSJack F Vogel 		e1000_lan_init_done_ich8lan(hw);
22419d81738fSJack F Vogel 	} else {
22428cfa0ad2SJack F Vogel 		ret_val = e1000_get_auto_rd_done_generic(hw);
22438cfa0ad2SJack F Vogel 		if (ret_val) {
22448cfa0ad2SJack F Vogel 			/*
22458cfa0ad2SJack F Vogel 			 * When auto config read does not complete, do not
22468cfa0ad2SJack F Vogel 			 * return with an error. This can happen in situations
22478cfa0ad2SJack F Vogel 			 * where there is no eeprom and prevents getting link.
22488cfa0ad2SJack F Vogel 			 */
22498cfa0ad2SJack F Vogel 			DEBUGOUT("Auto Read Done did not complete\n");
22508cfa0ad2SJack F Vogel 		}
22519d81738fSJack F Vogel 	}
22528cfa0ad2SJack F Vogel 
22538cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
22548cfa0ad2SJack F Vogel 	icr = E1000_READ_REG(hw, E1000_ICR);
22558cfa0ad2SJack F Vogel 
22568cfa0ad2SJack F Vogel 	kab = E1000_READ_REG(hw, E1000_KABGTXD);
22578cfa0ad2SJack F Vogel 	kab |= E1000_KABGTXD_BGSQLBIAS;
22588cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
22598cfa0ad2SJack F Vogel 
22609d81738fSJack F Vogel 	if (hw->mac.type == e1000_pchlan)
22619d81738fSJack F Vogel 		ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
22629d81738fSJack F Vogel 
22638cfa0ad2SJack F Vogel 	return ret_val;
22648cfa0ad2SJack F Vogel }
22658cfa0ad2SJack F Vogel 
22668cfa0ad2SJack F Vogel /**
22678cfa0ad2SJack F Vogel  *  e1000_init_hw_ich8lan - Initialize the hardware
22688cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
22698cfa0ad2SJack F Vogel  *
22708cfa0ad2SJack F Vogel  *  Prepares the hardware for transmit and receive by doing the following:
22718cfa0ad2SJack F Vogel  *   - initialize hardware bits
22728cfa0ad2SJack F Vogel  *   - initialize LED identification
22738cfa0ad2SJack F Vogel  *   - setup receive address registers
22748cfa0ad2SJack F Vogel  *   - setup flow control
22758cfa0ad2SJack F Vogel  *   - setup transmit descriptors
22768cfa0ad2SJack F Vogel  *   - clear statistics
22778cfa0ad2SJack F Vogel  **/
22788cfa0ad2SJack F Vogel static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw)
22798cfa0ad2SJack F Vogel {
22808cfa0ad2SJack F Vogel 	struct e1000_mac_info *mac = &hw->mac;
22818cfa0ad2SJack F Vogel 	u32 ctrl_ext, txdctl, snoop;
22828cfa0ad2SJack F Vogel 	s32 ret_val;
22838cfa0ad2SJack F Vogel 	u16 i;
22848cfa0ad2SJack F Vogel 
22858cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_init_hw_ich8lan");
22868cfa0ad2SJack F Vogel 
22878cfa0ad2SJack F Vogel 	e1000_initialize_hw_bits_ich8lan(hw);
22888cfa0ad2SJack F Vogel 
22898cfa0ad2SJack F Vogel 	/* Initialize identification LED */
2290d035aa2dSJack F Vogel 	ret_val = mac->ops.id_led_init(hw);
2291d035aa2dSJack F Vogel 	if (ret_val)
22928cfa0ad2SJack F Vogel 		/* This is not fatal and we should not stop init due to this */
2293d035aa2dSJack F Vogel 		DEBUGOUT("Error initializing identification LED\n");
22948cfa0ad2SJack F Vogel 
22958cfa0ad2SJack F Vogel 	/* Setup the receive address. */
22968cfa0ad2SJack F Vogel 	e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
22978cfa0ad2SJack F Vogel 
22988cfa0ad2SJack F Vogel 	/* Zero out the Multicast HASH table */
22998cfa0ad2SJack F Vogel 	DEBUGOUT("Zeroing the MTA\n");
23008cfa0ad2SJack F Vogel 	for (i = 0; i < mac->mta_reg_count; i++)
23018cfa0ad2SJack F Vogel 		E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
23028cfa0ad2SJack F Vogel 
23039d81738fSJack F Vogel 	/*
23049d81738fSJack F Vogel 	 * The 82578 Rx buffer will stall if wakeup is enabled in host and
23059d81738fSJack F Vogel 	 * the ME.  Reading the BM_WUC register will clear the host wakeup bit.
23069d81738fSJack F Vogel 	 * Reset the phy after disabling host wakeup to reset the Rx buffer.
23079d81738fSJack F Vogel 	 */
23089d81738fSJack F Vogel 	if (hw->phy.type == e1000_phy_82578) {
23099d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, BM_WUC, &i);
23109d81738fSJack F Vogel 		ret_val = e1000_phy_hw_reset_ich8lan(hw);
23119d81738fSJack F Vogel 		if (ret_val)
23129d81738fSJack F Vogel 			return ret_val;
23139d81738fSJack F Vogel 	}
23149d81738fSJack F Vogel 
23158cfa0ad2SJack F Vogel 	/* Setup link and flow control */
23168cfa0ad2SJack F Vogel 	ret_val = mac->ops.setup_link(hw);
23178cfa0ad2SJack F Vogel 
23188cfa0ad2SJack F Vogel 	/* Set the transmit descriptor write-back policy for both queues */
23198cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
23208cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
23218cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
23228cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
23238cfa0ad2SJack F Vogel 	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
23248cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
23258cfa0ad2SJack F Vogel 	txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
23268cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
23278cfa0ad2SJack F Vogel 		 E1000_TXDCTL_FULL_TX_DESC_WB;
23288cfa0ad2SJack F Vogel 	txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
23298cfa0ad2SJack F Vogel 	         E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
23308cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
23318cfa0ad2SJack F Vogel 
23328cfa0ad2SJack F Vogel 	/*
23338cfa0ad2SJack F Vogel 	 * ICH8 has opposite polarity of no_snoop bits.
23348cfa0ad2SJack F Vogel 	 * By default, we should use snoop behavior.
23358cfa0ad2SJack F Vogel 	 */
23368cfa0ad2SJack F Vogel 	if (mac->type == e1000_ich8lan)
23378cfa0ad2SJack F Vogel 		snoop = PCIE_ICH8_SNOOP_ALL;
23388cfa0ad2SJack F Vogel 	else
23398cfa0ad2SJack F Vogel 		snoop = (u32)~(PCIE_NO_SNOOP_ALL);
23408cfa0ad2SJack F Vogel 	e1000_set_pcie_no_snoop_generic(hw, snoop);
23418cfa0ad2SJack F Vogel 
23428cfa0ad2SJack F Vogel 	ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
23438cfa0ad2SJack F Vogel 	ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
23448cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
23458cfa0ad2SJack F Vogel 
23468cfa0ad2SJack F Vogel 	/*
23478cfa0ad2SJack F Vogel 	 * Clear all of the statistics registers (clear on read).  It is
23488cfa0ad2SJack F Vogel 	 * important that we do this after we have tried to establish link
23498cfa0ad2SJack F Vogel 	 * because the symbol error count will increment wildly if there
23508cfa0ad2SJack F Vogel 	 * is no link.
23518cfa0ad2SJack F Vogel 	 */
23528cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_ich8lan(hw);
23538cfa0ad2SJack F Vogel 
23548cfa0ad2SJack F Vogel 	return ret_val;
23558cfa0ad2SJack F Vogel }
23568cfa0ad2SJack F Vogel /**
23578cfa0ad2SJack F Vogel  *  e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
23588cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
23598cfa0ad2SJack F Vogel  *
23608cfa0ad2SJack F Vogel  *  Sets/Clears required hardware bits necessary for correctly setting up the
23618cfa0ad2SJack F Vogel  *  hardware for transmit and receive.
23628cfa0ad2SJack F Vogel  **/
23638cfa0ad2SJack F Vogel static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
23648cfa0ad2SJack F Vogel {
23658cfa0ad2SJack F Vogel 	u32 reg;
23668cfa0ad2SJack F Vogel 
23678cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
23688cfa0ad2SJack F Vogel 
23698cfa0ad2SJack F Vogel 	/* Extended Device Control */
23708cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
23718cfa0ad2SJack F Vogel 	reg |= (1 << 22);
23729d81738fSJack F Vogel 	/* Enable PHY low-power state when MAC is at D3 w/o WoL */
23739d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan)
23749d81738fSJack F Vogel 		reg |= E1000_CTRL_EXT_PHYPDEN;
23758cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
23768cfa0ad2SJack F Vogel 
23778cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 0 */
23788cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
23798cfa0ad2SJack F Vogel 	reg |= (1 << 22);
23808cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
23818cfa0ad2SJack F Vogel 
23828cfa0ad2SJack F Vogel 	/* Transmit Descriptor Control 1 */
23838cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
23848cfa0ad2SJack F Vogel 	reg |= (1 << 22);
23858cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
23868cfa0ad2SJack F Vogel 
23878cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 0 */
23888cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(0));
23898cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan)
23908cfa0ad2SJack F Vogel 		reg |= (1 << 28) | (1 << 29);
23918cfa0ad2SJack F Vogel 	reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
23928cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(0), reg);
23938cfa0ad2SJack F Vogel 
23948cfa0ad2SJack F Vogel 	/* Transmit Arbitration Control 1 */
23958cfa0ad2SJack F Vogel 	reg = E1000_READ_REG(hw, E1000_TARC(1));
23968cfa0ad2SJack F Vogel 	if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
23978cfa0ad2SJack F Vogel 		reg &= ~(1 << 28);
23988cfa0ad2SJack F Vogel 	else
23998cfa0ad2SJack F Vogel 		reg |= (1 << 28);
24008cfa0ad2SJack F Vogel 	reg |= (1 << 24) | (1 << 26) | (1 << 30);
24018cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_TARC(1), reg);
24028cfa0ad2SJack F Vogel 
24038cfa0ad2SJack F Vogel 	/* Device Status */
24048cfa0ad2SJack F Vogel 	if (hw->mac.type == e1000_ich8lan) {
24058cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_STATUS);
24068cfa0ad2SJack F Vogel 		reg &= ~(1 << 31);
24078cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_STATUS, reg);
24088cfa0ad2SJack F Vogel 	}
24098cfa0ad2SJack F Vogel 
24108cfa0ad2SJack F Vogel 	return;
24118cfa0ad2SJack F Vogel }
24128cfa0ad2SJack F Vogel 
24138cfa0ad2SJack F Vogel /**
24148cfa0ad2SJack F Vogel  *  e1000_setup_link_ich8lan - Setup flow control and link settings
24158cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
24168cfa0ad2SJack F Vogel  *
24178cfa0ad2SJack F Vogel  *  Determines which flow control settings to use, then configures flow
24188cfa0ad2SJack F Vogel  *  control.  Calls the appropriate media-specific link configuration
24198cfa0ad2SJack F Vogel  *  function.  Assuming the adapter has a valid link partner, a valid link
24208cfa0ad2SJack F Vogel  *  should be established.  Assumes the hardware has previously been reset
24218cfa0ad2SJack F Vogel  *  and the transmitter and receiver are not enabled.
24228cfa0ad2SJack F Vogel  **/
24238cfa0ad2SJack F Vogel static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw)
24248cfa0ad2SJack F Vogel {
24258cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
24268cfa0ad2SJack F Vogel 
24278cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_link_ich8lan");
24288cfa0ad2SJack F Vogel 
24298cfa0ad2SJack F Vogel 	if (hw->phy.ops.check_reset_block(hw))
24308cfa0ad2SJack F Vogel 		goto out;
24318cfa0ad2SJack F Vogel 
24328cfa0ad2SJack F Vogel 	/*
24338cfa0ad2SJack F Vogel 	 * ICH parts do not have a word in the NVM to determine
24348cfa0ad2SJack F Vogel 	 * the default flow control setting, so we explicitly
24358cfa0ad2SJack F Vogel 	 * set it to full.
24368cfa0ad2SJack F Vogel 	 */
2437daf9197cSJack F Vogel 	if (hw->fc.requested_mode == e1000_fc_default)
2438daf9197cSJack F Vogel 		hw->fc.requested_mode = e1000_fc_full;
24398cfa0ad2SJack F Vogel 
2440daf9197cSJack F Vogel 	/*
2441daf9197cSJack F Vogel 	 * Save off the requested flow control mode for use later.  Depending
2442daf9197cSJack F Vogel 	 * on the link partner's capabilities, we may or may not use this mode.
2443daf9197cSJack F Vogel 	 */
2444daf9197cSJack F Vogel 	hw->fc.current_mode = hw->fc.requested_mode;
24458cfa0ad2SJack F Vogel 
2446daf9197cSJack F Vogel 	DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
2447daf9197cSJack F Vogel 		hw->fc.current_mode);
24488cfa0ad2SJack F Vogel 
24498cfa0ad2SJack F Vogel 	/* Continue to configure the copper link. */
24508cfa0ad2SJack F Vogel 	ret_val = hw->mac.ops.setup_physical_interface(hw);
24518cfa0ad2SJack F Vogel 	if (ret_val)
24528cfa0ad2SJack F Vogel 		goto out;
24538cfa0ad2SJack F Vogel 
24548cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
24559d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
24569d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
24579d81738fSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
24589d81738fSJack F Vogel 		                             PHY_REG(BM_PORT_CTRL_PAGE, 27),
24599d81738fSJack F Vogel 		                             hw->fc.pause_time);
24609d81738fSJack F Vogel 		if (ret_val)
24619d81738fSJack F Vogel 			goto out;
24629d81738fSJack F Vogel 	}
24638cfa0ad2SJack F Vogel 
24648cfa0ad2SJack F Vogel 	ret_val = e1000_set_fc_watermarks_generic(hw);
24658cfa0ad2SJack F Vogel 
24668cfa0ad2SJack F Vogel out:
24678cfa0ad2SJack F Vogel 	return ret_val;
24688cfa0ad2SJack F Vogel }
24698cfa0ad2SJack F Vogel 
24708cfa0ad2SJack F Vogel /**
24718cfa0ad2SJack F Vogel  *  e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
24728cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
24738cfa0ad2SJack F Vogel  *
24748cfa0ad2SJack F Vogel  *  Configures the kumeran interface to the PHY to wait the appropriate time
24758cfa0ad2SJack F Vogel  *  when polling the PHY, then call the generic setup_copper_link to finish
24768cfa0ad2SJack F Vogel  *  configuring the copper link.
24778cfa0ad2SJack F Vogel  **/
24788cfa0ad2SJack F Vogel static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
24798cfa0ad2SJack F Vogel {
24808cfa0ad2SJack F Vogel 	u32 ctrl;
24818cfa0ad2SJack F Vogel 	s32 ret_val;
24828cfa0ad2SJack F Vogel 	u16 reg_data;
24838cfa0ad2SJack F Vogel 
24848cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_setup_copper_link_ich8lan");
24858cfa0ad2SJack F Vogel 
24868cfa0ad2SJack F Vogel 	ctrl = E1000_READ_REG(hw, E1000_CTRL);
24878cfa0ad2SJack F Vogel 	ctrl |= E1000_CTRL_SLU;
24888cfa0ad2SJack F Vogel 	ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
24898cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
24908cfa0ad2SJack F Vogel 
24918cfa0ad2SJack F Vogel 	/*
24928cfa0ad2SJack F Vogel 	 * Set the mac to wait the maximum time between each iteration
24938cfa0ad2SJack F Vogel 	 * and increase the max iterations when polling the phy;
24948cfa0ad2SJack F Vogel 	 * this fixes erroneous timeouts at 10Mbps.
24958cfa0ad2SJack F Vogel 	 */
24969d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
24979d81738fSJack F Vogel 	                                       E1000_KMRNCTRLSTA_TIMEOUTS,
24988cfa0ad2SJack F Vogel 	                                       0xFFFF);
24998cfa0ad2SJack F Vogel 	if (ret_val)
25008cfa0ad2SJack F Vogel 		goto out;
25019d81738fSJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw,
25029d81738fSJack F Vogel 	                                      E1000_KMRNCTRLSTA_INBAND_PARAM,
25038cfa0ad2SJack F Vogel 	                                      &reg_data);
25048cfa0ad2SJack F Vogel 	if (ret_val)
25058cfa0ad2SJack F Vogel 		goto out;
25068cfa0ad2SJack F Vogel 	reg_data |= 0x3F;
25079d81738fSJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
25089d81738fSJack F Vogel 	                                       E1000_KMRNCTRLSTA_INBAND_PARAM,
25098cfa0ad2SJack F Vogel 	                                       reg_data);
25108cfa0ad2SJack F Vogel 	if (ret_val)
25118cfa0ad2SJack F Vogel 		goto out;
25128cfa0ad2SJack F Vogel 
2513d035aa2dSJack F Vogel 	switch (hw->phy.type) {
2514d035aa2dSJack F Vogel 	case e1000_phy_igp_3:
25158cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_igp(hw);
25168cfa0ad2SJack F Vogel 		if (ret_val)
25178cfa0ad2SJack F Vogel 			goto out;
2518d035aa2dSJack F Vogel 		break;
2519d035aa2dSJack F Vogel 	case e1000_phy_bm:
25209d81738fSJack F Vogel 	case e1000_phy_82578:
25218cfa0ad2SJack F Vogel 		ret_val = e1000_copper_link_setup_m88(hw);
25228cfa0ad2SJack F Vogel 		if (ret_val)
25238cfa0ad2SJack F Vogel 			goto out;
2524d035aa2dSJack F Vogel 		break;
25259d81738fSJack F Vogel 	case e1000_phy_82577:
25269d81738fSJack F Vogel 		ret_val = e1000_copper_link_setup_82577(hw);
25279d81738fSJack F Vogel 		if (ret_val)
25289d81738fSJack F Vogel 			goto out;
25299d81738fSJack F Vogel 		break;
2530d035aa2dSJack F Vogel 	case e1000_phy_ife:
25318cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
25328cfa0ad2SJack F Vogel 		                               &reg_data);
25338cfa0ad2SJack F Vogel 		if (ret_val)
25348cfa0ad2SJack F Vogel 			goto out;
25358cfa0ad2SJack F Vogel 
25368cfa0ad2SJack F Vogel 		reg_data &= ~IFE_PMC_AUTO_MDIX;
25378cfa0ad2SJack F Vogel 
25388cfa0ad2SJack F Vogel 		switch (hw->phy.mdix) {
25398cfa0ad2SJack F Vogel 		case 1:
25408cfa0ad2SJack F Vogel 			reg_data &= ~IFE_PMC_FORCE_MDIX;
25418cfa0ad2SJack F Vogel 			break;
25428cfa0ad2SJack F Vogel 		case 2:
25438cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_FORCE_MDIX;
25448cfa0ad2SJack F Vogel 			break;
25458cfa0ad2SJack F Vogel 		case 0:
25468cfa0ad2SJack F Vogel 		default:
25478cfa0ad2SJack F Vogel 			reg_data |= IFE_PMC_AUTO_MDIX;
25488cfa0ad2SJack F Vogel 			break;
25498cfa0ad2SJack F Vogel 		}
25508cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
25518cfa0ad2SJack F Vogel 		                                reg_data);
25528cfa0ad2SJack F Vogel 		if (ret_val)
25538cfa0ad2SJack F Vogel 			goto out;
2554d035aa2dSJack F Vogel 		break;
2555d035aa2dSJack F Vogel 	default:
2556d035aa2dSJack F Vogel 		break;
25578cfa0ad2SJack F Vogel 	}
25588cfa0ad2SJack F Vogel 	ret_val = e1000_setup_copper_link_generic(hw);
25598cfa0ad2SJack F Vogel 
25608cfa0ad2SJack F Vogel out:
25618cfa0ad2SJack F Vogel 	return ret_val;
25628cfa0ad2SJack F Vogel }
25638cfa0ad2SJack F Vogel 
25648cfa0ad2SJack F Vogel /**
25658cfa0ad2SJack F Vogel  *  e1000_get_link_up_info_ich8lan - Get current link speed and duplex
25668cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
25678cfa0ad2SJack F Vogel  *  @speed: pointer to store current link speed
25688cfa0ad2SJack F Vogel  *  @duplex: pointer to store the current link duplex
25698cfa0ad2SJack F Vogel  *
25708cfa0ad2SJack F Vogel  *  Calls the generic get_speed_and_duplex to retrieve the current link
25718cfa0ad2SJack F Vogel  *  information and then calls the Kumeran lock loss workaround for links at
25728cfa0ad2SJack F Vogel  *  gigabit speeds.
25738cfa0ad2SJack F Vogel  **/
25748cfa0ad2SJack F Vogel static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed,
25758cfa0ad2SJack F Vogel                                           u16 *duplex)
25768cfa0ad2SJack F Vogel {
25778cfa0ad2SJack F Vogel 	s32 ret_val;
25788cfa0ad2SJack F Vogel 
25798cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_get_link_up_info_ich8lan");
25808cfa0ad2SJack F Vogel 
25818cfa0ad2SJack F Vogel 	ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
25828cfa0ad2SJack F Vogel 	if (ret_val)
25838cfa0ad2SJack F Vogel 		goto out;
25848cfa0ad2SJack F Vogel 
25858cfa0ad2SJack F Vogel 	if ((hw->mac.type == e1000_ich8lan) &&
25868cfa0ad2SJack F Vogel 	    (hw->phy.type == e1000_phy_igp_3) &&
25878cfa0ad2SJack F Vogel 	    (*speed == SPEED_1000)) {
25888cfa0ad2SJack F Vogel 		ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
25898cfa0ad2SJack F Vogel 	}
25908cfa0ad2SJack F Vogel 
25918cfa0ad2SJack F Vogel out:
25928cfa0ad2SJack F Vogel 	return ret_val;
25938cfa0ad2SJack F Vogel }
25948cfa0ad2SJack F Vogel 
25958cfa0ad2SJack F Vogel /**
25968cfa0ad2SJack F Vogel  *  e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
25978cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
25988cfa0ad2SJack F Vogel  *
25998cfa0ad2SJack F Vogel  *  Work-around for 82566 Kumeran PCS lock loss:
26008cfa0ad2SJack F Vogel  *  On link status change (i.e. PCI reset, speed change) and link is up and
26018cfa0ad2SJack F Vogel  *  speed is gigabit-
26028cfa0ad2SJack F Vogel  *    0) if workaround is optionally disabled do nothing
26038cfa0ad2SJack F Vogel  *    1) wait 1ms for Kumeran link to come up
26048cfa0ad2SJack F Vogel  *    2) check Kumeran Diagnostic register PCS lock loss bit
26058cfa0ad2SJack F Vogel  *    3) if not set the link is locked (all is good), otherwise...
26068cfa0ad2SJack F Vogel  *    4) reset the PHY
26078cfa0ad2SJack F Vogel  *    5) repeat up to 10 times
26088cfa0ad2SJack F Vogel  *  Note: this is only called for IGP3 copper when speed is 1gb.
26098cfa0ad2SJack F Vogel  **/
26108cfa0ad2SJack F Vogel static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
26118cfa0ad2SJack F Vogel {
2612daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
26138cfa0ad2SJack F Vogel 	u32 phy_ctrl;
26148cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
26158cfa0ad2SJack F Vogel 	u16 i, data;
26168cfa0ad2SJack F Vogel 	bool link;
26178cfa0ad2SJack F Vogel 
26188cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
26198cfa0ad2SJack F Vogel 
26208cfa0ad2SJack F Vogel 	if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
26218cfa0ad2SJack F Vogel 		goto out;
26228cfa0ad2SJack F Vogel 
26238cfa0ad2SJack F Vogel 	/*
26248cfa0ad2SJack F Vogel 	 * Make sure link is up before proceeding.  If not just return.
26258cfa0ad2SJack F Vogel 	 * Attempting this while link is negotiating fouled up link
26268cfa0ad2SJack F Vogel 	 * stability
26278cfa0ad2SJack F Vogel 	 */
26288cfa0ad2SJack F Vogel 	ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
26298cfa0ad2SJack F Vogel 	if (!link) {
26308cfa0ad2SJack F Vogel 		ret_val = E1000_SUCCESS;
26318cfa0ad2SJack F Vogel 		goto out;
26328cfa0ad2SJack F Vogel 	}
26338cfa0ad2SJack F Vogel 
26348cfa0ad2SJack F Vogel 	for (i = 0; i < 10; i++) {
26358cfa0ad2SJack F Vogel 		/* read once to clear */
26368cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
26378cfa0ad2SJack F Vogel 		if (ret_val)
26388cfa0ad2SJack F Vogel 			goto out;
26398cfa0ad2SJack F Vogel 		/* and again to get new status */
26408cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
26418cfa0ad2SJack F Vogel 		if (ret_val)
26428cfa0ad2SJack F Vogel 			goto out;
26438cfa0ad2SJack F Vogel 
26448cfa0ad2SJack F Vogel 		/* check for PCS lock */
26458cfa0ad2SJack F Vogel 		if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
26468cfa0ad2SJack F Vogel 			ret_val = E1000_SUCCESS;
26478cfa0ad2SJack F Vogel 			goto out;
26488cfa0ad2SJack F Vogel 		}
26498cfa0ad2SJack F Vogel 
26508cfa0ad2SJack F Vogel 		/* Issue PHY reset */
26518cfa0ad2SJack F Vogel 		hw->phy.ops.reset(hw);
26528cfa0ad2SJack F Vogel 		msec_delay_irq(5);
26538cfa0ad2SJack F Vogel 	}
26548cfa0ad2SJack F Vogel 	/* Disable GigE link negotiation */
26558cfa0ad2SJack F Vogel 	phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
26568cfa0ad2SJack F Vogel 	phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
26578cfa0ad2SJack F Vogel 	             E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
26588cfa0ad2SJack F Vogel 	E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
26598cfa0ad2SJack F Vogel 
26608cfa0ad2SJack F Vogel 	/*
26618cfa0ad2SJack F Vogel 	 * Call gig speed drop workaround on Gig disable before accessing
26628cfa0ad2SJack F Vogel 	 * any PHY registers
26638cfa0ad2SJack F Vogel 	 */
26648cfa0ad2SJack F Vogel 	e1000_gig_downshift_workaround_ich8lan(hw);
26658cfa0ad2SJack F Vogel 
26668cfa0ad2SJack F Vogel 	/* unable to acquire PCS lock */
26678cfa0ad2SJack F Vogel 	ret_val = -E1000_ERR_PHY;
26688cfa0ad2SJack F Vogel 
26698cfa0ad2SJack F Vogel out:
26708cfa0ad2SJack F Vogel 	return ret_val;
26718cfa0ad2SJack F Vogel }
26728cfa0ad2SJack F Vogel 
26738cfa0ad2SJack F Vogel /**
26748cfa0ad2SJack F Vogel  *  e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
26758cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
26768cfa0ad2SJack F Vogel  *  @state: boolean value used to set the current Kumeran workaround state
26778cfa0ad2SJack F Vogel  *
26788cfa0ad2SJack F Vogel  *  If ICH8, set the current Kumeran workaround state (enabled - TRUE
26798cfa0ad2SJack F Vogel  *  /disabled - FALSE).
26808cfa0ad2SJack F Vogel  **/
26818cfa0ad2SJack F Vogel void e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
26828cfa0ad2SJack F Vogel                                                  bool state)
26838cfa0ad2SJack F Vogel {
2684daf9197cSJack F Vogel 	struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
26858cfa0ad2SJack F Vogel 
26868cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
26878cfa0ad2SJack F Vogel 
26888cfa0ad2SJack F Vogel 	if (hw->mac.type != e1000_ich8lan) {
26898cfa0ad2SJack F Vogel 		DEBUGOUT("Workaround applies to ICH8 only.\n");
2690daf9197cSJack F Vogel 		return;
26918cfa0ad2SJack F Vogel 	}
26928cfa0ad2SJack F Vogel 
26938cfa0ad2SJack F Vogel 	dev_spec->kmrn_lock_loss_workaround_enabled = state;
26948cfa0ad2SJack F Vogel 
26958cfa0ad2SJack F Vogel 	return;
26968cfa0ad2SJack F Vogel }
26978cfa0ad2SJack F Vogel 
26988cfa0ad2SJack F Vogel /**
26998cfa0ad2SJack F Vogel  *  e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
27008cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
27018cfa0ad2SJack F Vogel  *
27028cfa0ad2SJack F Vogel  *  Workaround for 82566 power-down on D3 entry:
27038cfa0ad2SJack F Vogel  *    1) disable gigabit link
27048cfa0ad2SJack F Vogel  *    2) write VR power-down enable
27058cfa0ad2SJack F Vogel  *    3) read it back
27068cfa0ad2SJack F Vogel  *  Continue if successful, else issue LCD reset and repeat
27078cfa0ad2SJack F Vogel  **/
27088cfa0ad2SJack F Vogel void e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
27098cfa0ad2SJack F Vogel {
27108cfa0ad2SJack F Vogel 	u32 reg;
27118cfa0ad2SJack F Vogel 	u16 data;
27128cfa0ad2SJack F Vogel 	u8  retry = 0;
27138cfa0ad2SJack F Vogel 
27148cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
27158cfa0ad2SJack F Vogel 
27168cfa0ad2SJack F Vogel 	if (hw->phy.type != e1000_phy_igp_3)
27178cfa0ad2SJack F Vogel 		goto out;
27188cfa0ad2SJack F Vogel 
27198cfa0ad2SJack F Vogel 	/* Try the workaround twice (if needed) */
27208cfa0ad2SJack F Vogel 	do {
27218cfa0ad2SJack F Vogel 		/* Disable link */
27228cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
27238cfa0ad2SJack F Vogel 		reg |= (E1000_PHY_CTRL_GBE_DISABLE |
27248cfa0ad2SJack F Vogel 		        E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
27258cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
27268cfa0ad2SJack F Vogel 
27278cfa0ad2SJack F Vogel 		/*
27288cfa0ad2SJack F Vogel 		 * Call gig speed drop workaround on Gig disable before
27298cfa0ad2SJack F Vogel 		 * accessing any PHY registers
27308cfa0ad2SJack F Vogel 		 */
27318cfa0ad2SJack F Vogel 		if (hw->mac.type == e1000_ich8lan)
27328cfa0ad2SJack F Vogel 			e1000_gig_downshift_workaround_ich8lan(hw);
27338cfa0ad2SJack F Vogel 
27348cfa0ad2SJack F Vogel 		/* Write VR power-down enable */
27358cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
27368cfa0ad2SJack F Vogel 		data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
2737daf9197cSJack F Vogel 		hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
27388cfa0ad2SJack F Vogel 		                   data | IGP3_VR_CTRL_MODE_SHUTDOWN);
27398cfa0ad2SJack F Vogel 
27408cfa0ad2SJack F Vogel 		/* Read it back and test */
27418cfa0ad2SJack F Vogel 		hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
27428cfa0ad2SJack F Vogel 		data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
27438cfa0ad2SJack F Vogel 		if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
27448cfa0ad2SJack F Vogel 			break;
27458cfa0ad2SJack F Vogel 
27468cfa0ad2SJack F Vogel 		/* Issue PHY reset and repeat at most one more time */
27478cfa0ad2SJack F Vogel 		reg = E1000_READ_REG(hw, E1000_CTRL);
27488cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
27498cfa0ad2SJack F Vogel 		retry++;
27508cfa0ad2SJack F Vogel 	} while (retry);
27518cfa0ad2SJack F Vogel 
27528cfa0ad2SJack F Vogel out:
27538cfa0ad2SJack F Vogel 	return;
27548cfa0ad2SJack F Vogel }
27558cfa0ad2SJack F Vogel 
27568cfa0ad2SJack F Vogel /**
27578cfa0ad2SJack F Vogel  *  e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
27588cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
27598cfa0ad2SJack F Vogel  *
27608cfa0ad2SJack F Vogel  *  Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
27618cfa0ad2SJack F Vogel  *  LPLU, Gig disable, MDIC PHY reset):
27628cfa0ad2SJack F Vogel  *    1) Set Kumeran Near-end loopback
27638cfa0ad2SJack F Vogel  *    2) Clear Kumeran Near-end loopback
27648cfa0ad2SJack F Vogel  *  Should only be called for ICH8[m] devices with IGP_3 Phy.
27658cfa0ad2SJack F Vogel  **/
27668cfa0ad2SJack F Vogel void e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
27678cfa0ad2SJack F Vogel {
27688cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
27698cfa0ad2SJack F Vogel 	u16 reg_data;
27708cfa0ad2SJack F Vogel 
27718cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
27728cfa0ad2SJack F Vogel 
27738cfa0ad2SJack F Vogel 	if ((hw->mac.type != e1000_ich8lan) ||
27748cfa0ad2SJack F Vogel 	    (hw->phy.type != e1000_phy_igp_3))
27758cfa0ad2SJack F Vogel 		goto out;
27768cfa0ad2SJack F Vogel 
27778cfa0ad2SJack F Vogel 	ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
27788cfa0ad2SJack F Vogel 	                                      &reg_data);
27798cfa0ad2SJack F Vogel 	if (ret_val)
27808cfa0ad2SJack F Vogel 		goto out;
27818cfa0ad2SJack F Vogel 	reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
27828cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
27838cfa0ad2SJack F Vogel 	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
27848cfa0ad2SJack F Vogel 	                                       reg_data);
27858cfa0ad2SJack F Vogel 	if (ret_val)
27868cfa0ad2SJack F Vogel 		goto out;
27878cfa0ad2SJack F Vogel 	reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
27888cfa0ad2SJack F Vogel 	ret_val = e1000_write_kmrn_reg_generic(hw,
27898cfa0ad2SJack F Vogel 	                                       E1000_KMRNCTRLSTA_DIAG_OFFSET,
27908cfa0ad2SJack F Vogel 	                                       reg_data);
27918cfa0ad2SJack F Vogel out:
27928cfa0ad2SJack F Vogel 	return;
27938cfa0ad2SJack F Vogel }
27948cfa0ad2SJack F Vogel 
27958cfa0ad2SJack F Vogel /**
27968cfa0ad2SJack F Vogel  *  e1000_disable_gig_wol_ich8lan - disable gig during WoL
27978cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
27988cfa0ad2SJack F Vogel  *
27998cfa0ad2SJack F Vogel  *  During S0 to Sx transition, it is possible the link remains at gig
28008cfa0ad2SJack F Vogel  *  instead of negotiating to a lower speed.  Before going to Sx, set
28018cfa0ad2SJack F Vogel  *  'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
28028cfa0ad2SJack F Vogel  *  to a lower speed.
28038cfa0ad2SJack F Vogel  *
2804d035aa2dSJack F Vogel  *  Should only be called for applicable parts.
28058cfa0ad2SJack F Vogel  **/
28068cfa0ad2SJack F Vogel void e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
28078cfa0ad2SJack F Vogel {
28088cfa0ad2SJack F Vogel 	u32 phy_ctrl;
28098cfa0ad2SJack F Vogel 
2810d035aa2dSJack F Vogel 	switch (hw->mac.type) {
2811d035aa2dSJack F Vogel 	case e1000_ich9lan:
2812d035aa2dSJack F Vogel 	case e1000_ich10lan:
28139d81738fSJack F Vogel 	case e1000_pchlan:
28148cfa0ad2SJack F Vogel 		phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
28158cfa0ad2SJack F Vogel 		phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
28168cfa0ad2SJack F Vogel 		            E1000_PHY_CTRL_GBE_DISABLE;
28178cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
28189d81738fSJack F Vogel 
28199d81738fSJack F Vogel 		/* Workaround SWFLAG unexpectedly set during S0->Sx */
28209d81738fSJack F Vogel 		if (hw->mac.type == e1000_pchlan)
28219d81738fSJack F Vogel 			usec_delay(500);
2822d035aa2dSJack F Vogel 	default:
2823d035aa2dSJack F Vogel 		break;
28248cfa0ad2SJack F Vogel 	}
28258cfa0ad2SJack F Vogel 
28268cfa0ad2SJack F Vogel 	return;
28278cfa0ad2SJack F Vogel }
28288cfa0ad2SJack F Vogel 
28298cfa0ad2SJack F Vogel /**
28308cfa0ad2SJack F Vogel  *  e1000_cleanup_led_ich8lan - Restore the default LED operation
28318cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28328cfa0ad2SJack F Vogel  *
28338cfa0ad2SJack F Vogel  *  Return the LED back to the default configuration.
28348cfa0ad2SJack F Vogel  **/
28358cfa0ad2SJack F Vogel static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
28368cfa0ad2SJack F Vogel {
28378cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28388cfa0ad2SJack F Vogel 
28398cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_ich8lan");
28408cfa0ad2SJack F Vogel 
28418cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
2842daf9197cSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
28438cfa0ad2SJack F Vogel 		                              0);
28448cfa0ad2SJack F Vogel 	else
28458cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
28468cfa0ad2SJack F Vogel 
28478cfa0ad2SJack F Vogel 	return ret_val;
28488cfa0ad2SJack F Vogel }
28498cfa0ad2SJack F Vogel 
28508cfa0ad2SJack F Vogel /**
28518cfa0ad2SJack F Vogel  *  e1000_led_on_ich8lan - Turn LEDs on
28528cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28538cfa0ad2SJack F Vogel  *
28548cfa0ad2SJack F Vogel  *  Turn on the LEDs.
28558cfa0ad2SJack F Vogel  **/
28568cfa0ad2SJack F Vogel static s32 e1000_led_on_ich8lan(struct e1000_hw *hw)
28578cfa0ad2SJack F Vogel {
28588cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28598cfa0ad2SJack F Vogel 
28608cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_on_ich8lan");
28618cfa0ad2SJack F Vogel 
28628cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
2863daf9197cSJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
28648cfa0ad2SJack F Vogel 		                (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
28658cfa0ad2SJack F Vogel 	else
28668cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
28678cfa0ad2SJack F Vogel 
28688cfa0ad2SJack F Vogel 	return ret_val;
28698cfa0ad2SJack F Vogel }
28708cfa0ad2SJack F Vogel 
28718cfa0ad2SJack F Vogel /**
28728cfa0ad2SJack F Vogel  *  e1000_led_off_ich8lan - Turn LEDs off
28738cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
28748cfa0ad2SJack F Vogel  *
28758cfa0ad2SJack F Vogel  *  Turn off the LEDs.
28768cfa0ad2SJack F Vogel  **/
28778cfa0ad2SJack F Vogel static s32 e1000_led_off_ich8lan(struct e1000_hw *hw)
28788cfa0ad2SJack F Vogel {
28798cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
28808cfa0ad2SJack F Vogel 
28818cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_led_off_ich8lan");
28828cfa0ad2SJack F Vogel 
28838cfa0ad2SJack F Vogel 	if (hw->phy.type == e1000_phy_ife)
28848cfa0ad2SJack F Vogel 		ret_val = hw->phy.ops.write_reg(hw,
28858cfa0ad2SJack F Vogel 		               IFE_PHY_SPECIAL_CONTROL_LED,
28868cfa0ad2SJack F Vogel 		               (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
28878cfa0ad2SJack F Vogel 	else
28888cfa0ad2SJack F Vogel 		E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
28898cfa0ad2SJack F Vogel 
28908cfa0ad2SJack F Vogel 	return ret_val;
28918cfa0ad2SJack F Vogel }
28928cfa0ad2SJack F Vogel 
28938cfa0ad2SJack F Vogel /**
28949d81738fSJack F Vogel  *  e1000_setup_led_pchlan - Configures SW controllable LED
28959d81738fSJack F Vogel  *  @hw: pointer to the HW structure
28969d81738fSJack F Vogel  *
28979d81738fSJack F Vogel  *  This prepares the SW controllable LED for use.
28989d81738fSJack F Vogel  **/
28999d81738fSJack F Vogel static s32 e1000_setup_led_pchlan(struct e1000_hw *hw)
29009d81738fSJack F Vogel {
29019d81738fSJack F Vogel 	DEBUGFUNC("e1000_setup_led_pchlan");
29029d81738fSJack F Vogel 
29039d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
29049d81738fSJack F Vogel 					(u16)hw->mac.ledctl_mode1);
29059d81738fSJack F Vogel }
29069d81738fSJack F Vogel 
29079d81738fSJack F Vogel /**
29089d81738fSJack F Vogel  *  e1000_cleanup_led_pchlan - Restore the default LED operation
29099d81738fSJack F Vogel  *  @hw: pointer to the HW structure
29109d81738fSJack F Vogel  *
29119d81738fSJack F Vogel  *  Return the LED back to the default configuration.
29129d81738fSJack F Vogel  **/
29139d81738fSJack F Vogel static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw)
29149d81738fSJack F Vogel {
29159d81738fSJack F Vogel 	DEBUGFUNC("e1000_cleanup_led_pchlan");
29169d81738fSJack F Vogel 
29179d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
29189d81738fSJack F Vogel 					(u16)hw->mac.ledctl_default);
29199d81738fSJack F Vogel }
29209d81738fSJack F Vogel 
29219d81738fSJack F Vogel /**
29229d81738fSJack F Vogel  *  e1000_led_on_pchlan - Turn LEDs on
29239d81738fSJack F Vogel  *  @hw: pointer to the HW structure
29249d81738fSJack F Vogel  *
29259d81738fSJack F Vogel  *  Turn on the LEDs.
29269d81738fSJack F Vogel  **/
29279d81738fSJack F Vogel static s32 e1000_led_on_pchlan(struct e1000_hw *hw)
29289d81738fSJack F Vogel {
29299d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode2;
29309d81738fSJack F Vogel 	u32 i, led;
29319d81738fSJack F Vogel 
29329d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_on_pchlan");
29339d81738fSJack F Vogel 
29349d81738fSJack F Vogel 	/*
29359d81738fSJack F Vogel 	 * If no link, then turn LED on by setting the invert bit
29369d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode2.
29379d81738fSJack F Vogel 	 */
29389d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
29399d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
29409d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
29419d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
29429d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
29439d81738fSJack F Vogel 				continue;
29449d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
29459d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
29469d81738fSJack F Vogel 			else
29479d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
29489d81738fSJack F Vogel 		}
29499d81738fSJack F Vogel 	}
29509d81738fSJack F Vogel 
29519d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
29529d81738fSJack F Vogel }
29539d81738fSJack F Vogel 
29549d81738fSJack F Vogel /**
29559d81738fSJack F Vogel  *  e1000_led_off_pchlan - Turn LEDs off
29569d81738fSJack F Vogel  *  @hw: pointer to the HW structure
29579d81738fSJack F Vogel  *
29589d81738fSJack F Vogel  *  Turn off the LEDs.
29599d81738fSJack F Vogel  **/
29609d81738fSJack F Vogel static s32 e1000_led_off_pchlan(struct e1000_hw *hw)
29619d81738fSJack F Vogel {
29629d81738fSJack F Vogel 	u16 data = (u16)hw->mac.ledctl_mode1;
29639d81738fSJack F Vogel 	u32 i, led;
29649d81738fSJack F Vogel 
29659d81738fSJack F Vogel 	DEBUGFUNC("e1000_led_off_pchlan");
29669d81738fSJack F Vogel 
29679d81738fSJack F Vogel 	/*
29689d81738fSJack F Vogel 	 * If no link, then turn LED off by clearing the invert bit
29699d81738fSJack F Vogel 	 * for each LED that's mode is "link_up" in ledctl_mode1.
29709d81738fSJack F Vogel 	 */
29719d81738fSJack F Vogel 	if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
29729d81738fSJack F Vogel 		for (i = 0; i < 3; i++) {
29739d81738fSJack F Vogel 			led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
29749d81738fSJack F Vogel 			if ((led & E1000_PHY_LED0_MODE_MASK) !=
29759d81738fSJack F Vogel 			    E1000_LEDCTL_MODE_LINK_UP)
29769d81738fSJack F Vogel 				continue;
29779d81738fSJack F Vogel 			if (led & E1000_PHY_LED0_IVRT)
29789d81738fSJack F Vogel 				data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
29799d81738fSJack F Vogel 			else
29809d81738fSJack F Vogel 				data |= (E1000_PHY_LED0_IVRT << (i * 5));
29819d81738fSJack F Vogel 		}
29829d81738fSJack F Vogel 	}
29839d81738fSJack F Vogel 
29849d81738fSJack F Vogel 	return hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data);
29859d81738fSJack F Vogel }
29869d81738fSJack F Vogel 
29879d81738fSJack F Vogel /**
29888cfa0ad2SJack F Vogel  *  e1000_get_cfg_done_ich8lan - Read config done bit
29898cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
29908cfa0ad2SJack F Vogel  *
29918cfa0ad2SJack F Vogel  *  Read the management control register for the config done bit for
29928cfa0ad2SJack F Vogel  *  completion status.  NOTE: silicon which is EEPROM-less will fail trying
29938cfa0ad2SJack F Vogel  *  to read the config done bit, so an error is *ONLY* logged and returns
29948cfa0ad2SJack F Vogel  *  E1000_SUCCESS.  If we were to return with error, EEPROM-less silicon
29958cfa0ad2SJack F Vogel  *  would not be able to be reset or change link.
29968cfa0ad2SJack F Vogel  **/
29978cfa0ad2SJack F Vogel static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
29988cfa0ad2SJack F Vogel {
29998cfa0ad2SJack F Vogel 	s32 ret_val = E1000_SUCCESS;
30008cfa0ad2SJack F Vogel 	u32 bank = 0;
30018cfa0ad2SJack F Vogel 
30029d81738fSJack F Vogel 	if (hw->mac.type >= e1000_pchlan) {
30039d81738fSJack F Vogel 		u32 status = E1000_READ_REG(hw, E1000_STATUS);
30049d81738fSJack F Vogel 
30059d81738fSJack F Vogel 		if (status & E1000_STATUS_PHYRA) {
30069d81738fSJack F Vogel 			E1000_WRITE_REG(hw, E1000_STATUS, status &
30079d81738fSJack F Vogel 			                ~E1000_STATUS_PHYRA);
30089d81738fSJack F Vogel 		} else
30099d81738fSJack F Vogel 			DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
30109d81738fSJack F Vogel 	}
30119d81738fSJack F Vogel 
30128cfa0ad2SJack F Vogel 	e1000_get_cfg_done_generic(hw);
30138cfa0ad2SJack F Vogel 
30148cfa0ad2SJack F Vogel 	/* If EEPROM is not marked present, init the IGP 3 PHY manually */
30159d81738fSJack F Vogel 	if ((hw->mac.type != e1000_ich10lan) &&
30169d81738fSJack F Vogel 	    (hw->mac.type != e1000_pchlan)) {
30178cfa0ad2SJack F Vogel 		if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
30188cfa0ad2SJack F Vogel 		    (hw->phy.type == e1000_phy_igp_3)) {
30198cfa0ad2SJack F Vogel 			e1000_phy_init_script_igp3(hw);
30208cfa0ad2SJack F Vogel 		}
30218cfa0ad2SJack F Vogel 	} else {
30228cfa0ad2SJack F Vogel 		if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
3023daf9197cSJack F Vogel 			/* Maybe we should do a basic PHY config */
30248cfa0ad2SJack F Vogel 			DEBUGOUT("EEPROM not present\n");
30258cfa0ad2SJack F Vogel 			ret_val = -E1000_ERR_CONFIG;
30268cfa0ad2SJack F Vogel 		}
30278cfa0ad2SJack F Vogel 	}
30288cfa0ad2SJack F Vogel 
30298cfa0ad2SJack F Vogel 	return ret_val;
30308cfa0ad2SJack F Vogel }
30318cfa0ad2SJack F Vogel 
30328cfa0ad2SJack F Vogel /**
30338cfa0ad2SJack F Vogel  * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
30348cfa0ad2SJack F Vogel  * @hw: pointer to the HW structure
30358cfa0ad2SJack F Vogel  *
30368cfa0ad2SJack F Vogel  * In the case of a PHY power down to save power, or to turn off link during a
30378cfa0ad2SJack F Vogel  * driver unload, or wake on lan is not enabled, remove the link.
30388cfa0ad2SJack F Vogel  **/
30398cfa0ad2SJack F Vogel static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
30408cfa0ad2SJack F Vogel {
30418cfa0ad2SJack F Vogel 	/* If the management interface is not enabled, then power down */
3042daf9197cSJack F Vogel 	if (!(hw->mac.ops.check_mng_mode(hw) ||
3043daf9197cSJack F Vogel 	      hw->phy.ops.check_reset_block(hw)))
30448cfa0ad2SJack F Vogel 		e1000_power_down_phy_copper(hw);
30458cfa0ad2SJack F Vogel 
30468cfa0ad2SJack F Vogel 	return;
30478cfa0ad2SJack F Vogel }
30488cfa0ad2SJack F Vogel 
30498cfa0ad2SJack F Vogel /**
30508cfa0ad2SJack F Vogel  *  e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
30518cfa0ad2SJack F Vogel  *  @hw: pointer to the HW structure
30528cfa0ad2SJack F Vogel  *
30538cfa0ad2SJack F Vogel  *  Clears hardware counters specific to the silicon family and calls
30548cfa0ad2SJack F Vogel  *  clear_hw_cntrs_generic to clear all general purpose counters.
30558cfa0ad2SJack F Vogel  **/
30568cfa0ad2SJack F Vogel static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
30578cfa0ad2SJack F Vogel {
30589d81738fSJack F Vogel 	u16 phy_data;
30599d81738fSJack F Vogel 
30608cfa0ad2SJack F Vogel 	DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
30618cfa0ad2SJack F Vogel 
30628cfa0ad2SJack F Vogel 	e1000_clear_hw_cntrs_base_generic(hw);
30638cfa0ad2SJack F Vogel 
3064daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ALGNERRC);
3065daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_RXERRC);
3066daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TNCRS);
3067daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_CEXTERR);
3068daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTC);
3069daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_TSCTFC);
30708cfa0ad2SJack F Vogel 
3071daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPRC);
3072daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPDC);
3073daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_MGTPTC);
30748cfa0ad2SJack F Vogel 
3075daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_IAC);
3076daf9197cSJack F Vogel 	E1000_READ_REG(hw, E1000_ICRXOC);
30779d81738fSJack F Vogel 
30789d81738fSJack F Vogel 	/* Clear PHY statistics registers */
30799d81738fSJack F Vogel 	if ((hw->phy.type == e1000_phy_82578) ||
30809d81738fSJack F Vogel 	    (hw->phy.type == e1000_phy_82577)) {
30819d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
30829d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
30839d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
30849d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
30859d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
30869d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
30879d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
30889d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
30899d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
30909d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
30919d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
30929d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
30939d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
30949d81738fSJack F Vogel 		hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
30959d81738fSJack F Vogel 	}
30968cfa0ad2SJack F Vogel }
30978cfa0ad2SJack F Vogel 
3098