14919Sxy150489 /*
24919Sxy150489 * This file is provided under a CDDLv1 license. When using or
34919Sxy150489 * redistributing this file, you may do so under this license.
44919Sxy150489 * In redistributing this file this license must be included
54919Sxy150489 * and no other modification of this header file is permitted.
64919Sxy150489 *
74919Sxy150489 * CDDL LICENSE SUMMARY
84919Sxy150489 *
98479SChenlu.Chen@Sun.COM * Copyright(c) 1999 - 2009 Intel Corporation. All rights reserved.
104919Sxy150489 *
114919Sxy150489 * The contents of this file are subject to the terms of Version
124919Sxy150489 * 1.0 of the Common Development and Distribution License (the "License").
134919Sxy150489 *
144919Sxy150489 * You should have received a copy of the License with this software.
154919Sxy150489 * You can obtain a copy of the License at
166735Scc210113 * http://www.opensolaris.org/os/licensing.
174919Sxy150489 * See the License for the specific language governing permissions
184919Sxy150489 * and limitations under the License.
194919Sxy150489 */
204919Sxy150489
214919Sxy150489 /*
228479SChenlu.Chen@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
234919Sxy150489 * Use is subject to license terms of the CDDLv1.
244919Sxy150489 */
254919Sxy150489
264919Sxy150489 /*
2711020SMin.Xu@Sun.COM * IntelVersion: 1.186.2.1 v3-1-10-1_2009-9-18_Release14-6
284919Sxy150489 */
296735Scc210113
304919Sxy150489 /*
318479SChenlu.Chen@Sun.COM * 82562G 10/100 Network Connection
328479SChenlu.Chen@Sun.COM * 82562G-2 10/100 Network Connection
338479SChenlu.Chen@Sun.COM * 82562GT 10/100 Network Connection
348479SChenlu.Chen@Sun.COM * 82562GT-2 10/100 Network Connection
358479SChenlu.Chen@Sun.COM * 82562V 10/100 Network Connection
368479SChenlu.Chen@Sun.COM * 82562V-2 10/100 Network Connection
378479SChenlu.Chen@Sun.COM * 82566DC-2 Gigabit Network Connection
388479SChenlu.Chen@Sun.COM * 82566DC Gigabit Network Connection
398479SChenlu.Chen@Sun.COM * 82566DM-2 Gigabit Network Connection
408479SChenlu.Chen@Sun.COM * 82566DM Gigabit Network Connection
418479SChenlu.Chen@Sun.COM * 82566MC Gigabit Network Connection
428479SChenlu.Chen@Sun.COM * 82566MM Gigabit Network Connection
438479SChenlu.Chen@Sun.COM * 82567LM Gigabit Network Connection
448479SChenlu.Chen@Sun.COM * 82567LF Gigabit Network Connection
458479SChenlu.Chen@Sun.COM * 82567V Gigabit Network Connection
468479SChenlu.Chen@Sun.COM * 82567LM-2 Gigabit Network Connection
478479SChenlu.Chen@Sun.COM * 82567LF-2 Gigabit Network Connection
488479SChenlu.Chen@Sun.COM * 82567V-2 Gigabit Network Connection
498479SChenlu.Chen@Sun.COM * 82567LF-3 Gigabit Network Connection
508479SChenlu.Chen@Sun.COM * 82567LM-3 Gigabit Network Connection
518479SChenlu.Chen@Sun.COM * 82567LM-4 Gigabit Network Connection
5210680SMin.Xu@Sun.COM * 82577LM Gigabit Network Connection
5310680SMin.Xu@Sun.COM * 82577LC Gigabit Network Connection
5410680SMin.Xu@Sun.COM * 82578DM Gigabit Network Connection
5510680SMin.Xu@Sun.COM * 82578DC Gigabit Network Connection
564919Sxy150489 */
574919Sxy150489
584919Sxy150489 #include "e1000_api.h"
594919Sxy150489
604919Sxy150489 static s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw);
6110680SMin.Xu@Sun.COM static s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw);
624919Sxy150489 static s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw);
634919Sxy150489 static s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw);
644919Sxy150489 static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw);
654919Sxy150489 static void e1000_release_swflag_ich8lan(struct e1000_hw *hw);
6610680SMin.Xu@Sun.COM static s32 e1000_acquire_nvm_ich8lan(struct e1000_hw *hw);
6710680SMin.Xu@Sun.COM static void e1000_release_nvm_ich8lan(struct e1000_hw *hw);
686735Scc210113 static bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw);
694919Sxy150489 static s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw);
704919Sxy150489 static s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw);
714919Sxy150489 static s32 e1000_get_phy_info_ich8lan(struct e1000_hw *hw);
7211020SMin.Xu@Sun.COM static s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active);
734919Sxy150489 static s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw,
746735Scc210113 bool active);
754919Sxy150489 static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw,
766735Scc210113 bool active);
774919Sxy150489 static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
784919Sxy150489 u16 words, u16 *data);
794919Sxy150489 static s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset,
804919Sxy150489 u16 words, u16 *data);
814919Sxy150489 static s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw);
824919Sxy150489 static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw);
834919Sxy150489 static s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw,
844919Sxy150489 u16 *data);
8510680SMin.Xu@Sun.COM static s32 e1000_id_led_init_pchlan(struct e1000_hw *hw);
864919Sxy150489 static s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw);
874919Sxy150489 static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw);
884919Sxy150489 static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw);
894919Sxy150489 static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw);
904919Sxy150489 static s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw);
914919Sxy150489 static s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw,
924919Sxy150489 u16 *speed, u16 *duplex);
934919Sxy150489 static s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw);
944919Sxy150489 static s32 e1000_led_on_ich8lan(struct e1000_hw *hw);
954919Sxy150489 static s32 e1000_led_off_ich8lan(struct e1000_hw *hw);
9611020SMin.Xu@Sun.COM static s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link);
9711020SMin.Xu@Sun.COM static s32 e1000_setup_led_pchlan(struct e1000_hw *hw);
9811020SMin.Xu@Sun.COM static s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw);
9911020SMin.Xu@Sun.COM static s32 e1000_led_on_pchlan(struct e1000_hw *hw);
10011020SMin.Xu@Sun.COM static s32 e1000_led_off_pchlan(struct e1000_hw *hw);
1014919Sxy150489 static void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw);
1024919Sxy150489 static s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank);
1034919Sxy150489 static s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout);
1044919Sxy150489 static s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw);
1054919Sxy150489 static s32 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw);
1064919Sxy150489 static void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw);
1074919Sxy150489 static s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw);
1087607STed.You@Sun.COM static s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw,
1098479SChenlu.Chen@Sun.COM u32 offset, u8 *data);
1104919Sxy150489 static s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1114919Sxy150489 u8 size, u16 *data);
1124919Sxy150489 static s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw,
1134919Sxy150489 u32 offset, u16 *data);
1144919Sxy150489 static s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
1154919Sxy150489 u32 offset, u8 byte);
1164919Sxy150489 static s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw,
1174919Sxy150489 u32 offset, u8 data);
1184919Sxy150489 static s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
1194919Sxy150489 u8 size, u16 data);
1204919Sxy150489 static s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw);
1216735Scc210113 static void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw);
12210680SMin.Xu@Sun.COM static s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw);
12311020SMin.Xu@Sun.COM static void e1000_lan_init_done_ich8lan(struct e1000_hw *hw);
12411020SMin.Xu@Sun.COM static s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw);
1254919Sxy150489
1264919Sxy150489 /* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */
1274919Sxy150489 /* Offset 04h HSFSTS */
1284919Sxy150489 union ich8_hws_flash_status {
1294919Sxy150489 struct ich8_hsfsts {
1304919Sxy150489 u16 flcdone:1; /* bit 0 Flash Cycle Done */
1314919Sxy150489 u16 flcerr:1; /* bit 1 Flash Cycle Error */
1324919Sxy150489 u16 dael:1; /* bit 2 Direct Access error Log */
1334919Sxy150489 u16 berasesz:2; /* bit 4:3 Sector Erase Size */
1344919Sxy150489 u16 flcinprog:1; /* bit 5 flash cycle in Progress */
1354919Sxy150489 u16 reserved1:2; /* bit 13:6 Reserved */
1364919Sxy150489 u16 reserved2:6; /* bit 13:6 Reserved */
1374919Sxy150489 u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */
1384919Sxy150489 u16 flockdn:1; /* bit 15 Flash Config Lock-Down */
1394919Sxy150489 } hsf_status;
1404919Sxy150489 u16 regval;
1414919Sxy150489 };
1424919Sxy150489
1434919Sxy150489 /* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */
1444919Sxy150489 /* Offset 06h FLCTL */
1454919Sxy150489 union ich8_hws_flash_ctrl {
1464919Sxy150489 struct ich8_hsflctl {
1474919Sxy150489 u16 flcgo:1; /* 0 Flash Cycle Go */
1484919Sxy150489 u16 flcycle:2; /* 2:1 Flash Cycle */
1494919Sxy150489 u16 reserved:5; /* 7:3 Reserved */
1504919Sxy150489 u16 fldbcount:2; /* 9:8 Flash Data Byte Count */
1514919Sxy150489 u16 flockdn:6; /* 15:10 Reserved */
1524919Sxy150489 } hsf_ctrl;
1534919Sxy150489 u16 regval;
1544919Sxy150489 };
1554919Sxy150489
1564919Sxy150489 /* ICH Flash Region Access Permissions */
1574919Sxy150489 union ich8_hws_flash_regacc {
1584919Sxy150489 struct ich8_flracc {
1594919Sxy150489 u32 grra:8; /* 0:7 GbE region Read Access */
1604919Sxy150489 u32 grwa:8; /* 8:15 GbE region Write Access */
1614919Sxy150489 u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */
1624919Sxy150489 u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */
1634919Sxy150489 } hsf_flregacc;
1644919Sxy150489 u16 regval;
1654919Sxy150489 };
1664919Sxy150489
1674919Sxy150489 /*
16810680SMin.Xu@Sun.COM * e1000_init_phy_params_pchlan - Initialize PHY function pointers
16910680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
17010680SMin.Xu@Sun.COM *
17110680SMin.Xu@Sun.COM * Initialize family-specific PHY parameters and function pointers.
17210680SMin.Xu@Sun.COM */
17310680SMin.Xu@Sun.COM static s32
e1000_init_phy_params_pchlan(struct e1000_hw * hw)17410680SMin.Xu@Sun.COM e1000_init_phy_params_pchlan(struct e1000_hw *hw)
17510680SMin.Xu@Sun.COM {
17610680SMin.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
17710680SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
17810680SMin.Xu@Sun.COM
17910680SMin.Xu@Sun.COM DEBUGFUNC("e1000_init_phy_params_pchlan");
18010680SMin.Xu@Sun.COM
18110680SMin.Xu@Sun.COM phy->addr = 1;
18210680SMin.Xu@Sun.COM phy->reset_delay_us = 100;
18310680SMin.Xu@Sun.COM
18410680SMin.Xu@Sun.COM phy->ops.acquire = e1000_acquire_swflag_ich8lan;
18510680SMin.Xu@Sun.COM phy->ops.check_polarity = e1000_check_polarity_ife;
18610680SMin.Xu@Sun.COM phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
18710680SMin.Xu@Sun.COM phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
18810680SMin.Xu@Sun.COM phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
18910680SMin.Xu@Sun.COM phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
19010680SMin.Xu@Sun.COM phy->ops.get_info = e1000_get_phy_info_ich8lan;
19110680SMin.Xu@Sun.COM phy->ops.read_reg = e1000_read_phy_reg_hv;
19211020SMin.Xu@Sun.COM phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked;
19310680SMin.Xu@Sun.COM phy->ops.release = e1000_release_swflag_ich8lan;
19410680SMin.Xu@Sun.COM phy->ops.reset = e1000_phy_hw_reset_ich8lan;
19511020SMin.Xu@Sun.COM phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan;
19611020SMin.Xu@Sun.COM phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan;
19710680SMin.Xu@Sun.COM phy->ops.write_reg = e1000_write_phy_reg_hv;
19811020SMin.Xu@Sun.COM phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked;
19910680SMin.Xu@Sun.COM phy->ops.power_up = e1000_power_up_phy_copper;
20010680SMin.Xu@Sun.COM phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
20110680SMin.Xu@Sun.COM phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
20210680SMin.Xu@Sun.COM
20310680SMin.Xu@Sun.COM phy->id = e1000_phy_unknown;
204*11143SGuoqing.Zhu@Sun.COM (void) e1000_get_phy_id(hw);
20510680SMin.Xu@Sun.COM phy->type = e1000_get_phy_type_from_id(phy->id);
20610680SMin.Xu@Sun.COM
20710680SMin.Xu@Sun.COM if (phy->type == e1000_phy_82577) {
20810680SMin.Xu@Sun.COM phy->ops.check_polarity = e1000_check_polarity_82577;
20910680SMin.Xu@Sun.COM phy->ops.force_speed_duplex =
21010680SMin.Xu@Sun.COM e1000_phy_force_speed_duplex_82577;
21110680SMin.Xu@Sun.COM phy->ops.get_cable_length = e1000_get_cable_length_82577;
21210680SMin.Xu@Sun.COM phy->ops.get_info = e1000_get_phy_info_82577;
21310680SMin.Xu@Sun.COM phy->ops.commit = e1000_phy_sw_reset_generic;
21410680SMin.Xu@Sun.COM }
21510680SMin.Xu@Sun.COM
21610680SMin.Xu@Sun.COM return (ret_val);
21710680SMin.Xu@Sun.COM }
21810680SMin.Xu@Sun.COM
21910680SMin.Xu@Sun.COM /*
2204919Sxy150489 * e1000_init_phy_params_ich8lan - Initialize PHY function pointers
2214919Sxy150489 * @hw: pointer to the HW structure
2224919Sxy150489 *
2234919Sxy150489 * Initialize family-specific PHY parameters and function pointers.
2244919Sxy150489 */
2254919Sxy150489 static s32
e1000_init_phy_params_ich8lan(struct e1000_hw * hw)2264919Sxy150489 e1000_init_phy_params_ich8lan(struct e1000_hw *hw)
2274919Sxy150489 {
2284919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
2294919Sxy150489 s32 ret_val = E1000_SUCCESS;
2304919Sxy150489 u16 i = 0;
2314919Sxy150489
2324919Sxy150489 DEBUGFUNC("e1000_init_phy_params_ich8lan");
2334919Sxy150489
2344919Sxy150489 phy->addr = 1;
2354919Sxy150489 phy->reset_delay_us = 100;
2364919Sxy150489
2376735Scc210113 phy->ops.acquire = e1000_acquire_swflag_ich8lan;
23810680SMin.Xu@Sun.COM phy->ops.check_polarity = e1000_check_polarity_ife;
2396735Scc210113 phy->ops.check_reset_block = e1000_check_reset_block_ich8lan;
24010680SMin.Xu@Sun.COM phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife;
2416735Scc210113 phy->ops.get_cable_length = e1000_get_cable_length_igp_2;
2426735Scc210113 phy->ops.get_cfg_done = e1000_get_cfg_done_ich8lan;
2436735Scc210113 phy->ops.get_info = e1000_get_phy_info_ich8lan;
2446735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_igp;
2456735Scc210113 phy->ops.release = e1000_release_swflag_ich8lan;
2466735Scc210113 phy->ops.reset = e1000_phy_hw_reset_ich8lan;
2476735Scc210113 phy->ops.set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan;
2486735Scc210113 phy->ops.set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan;
2496735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_igp;
2506735Scc210113 phy->ops.power_up = e1000_power_up_phy_copper;
2516735Scc210113 phy->ops.power_down = e1000_power_down_phy_copper_ich8lan;
2524919Sxy150489
2534919Sxy150489 /*
2544919Sxy150489 * We may need to do this twice - once for IGP and if that fails,
2554919Sxy150489 * we'll set BM func pointers and try again
2564919Sxy150489 */
2574919Sxy150489 ret_val = e1000_determine_phy_address(hw);
2584919Sxy150489 if (ret_val) {
2596735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_bm;
2606735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_bm;
2614919Sxy150489 ret_val = e1000_determine_phy_address(hw);
2624919Sxy150489 if (ret_val) {
2634919Sxy150489 DEBUGOUT("Can't determine PHY address. Erroring out\n");
2644919Sxy150489 goto out;
2654919Sxy150489 }
2664919Sxy150489 }
2674919Sxy150489
2684919Sxy150489 phy->id = 0;
2694919Sxy150489 while ((e1000_phy_unknown == e1000_get_phy_type_from_id(phy->id)) &&
2704919Sxy150489 (i++ < 100)) {
2714919Sxy150489 msec_delay(1);
2724919Sxy150489 ret_val = e1000_get_phy_id(hw);
2734919Sxy150489 if (ret_val)
2744919Sxy150489 goto out;
2754919Sxy150489 }
2764919Sxy150489
2774919Sxy150489 /* Verify phy id */
2784919Sxy150489 switch (phy->id) {
2794919Sxy150489 case IGP03E1000_E_PHY_ID:
2804919Sxy150489 phy->type = e1000_phy_igp_3;
2814919Sxy150489 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
28211020SMin.Xu@Sun.COM phy->ops.read_reg_locked = e1000_read_phy_reg_igp_locked;
28311020SMin.Xu@Sun.COM phy->ops.write_reg_locked = e1000_write_phy_reg_igp_locked;
2844919Sxy150489 break;
2854919Sxy150489 case IFE_E_PHY_ID:
2864919Sxy150489 case IFE_PLUS_E_PHY_ID:
2874919Sxy150489 case IFE_C_E_PHY_ID:
2884919Sxy150489 phy->type = e1000_phy_ife;
2894919Sxy150489 phy->autoneg_mask = E1000_ALL_NOT_GIG;
2904919Sxy150489 break;
2914919Sxy150489 case BME1000_E_PHY_ID:
2924919Sxy150489 phy->type = e1000_phy_bm;
2934919Sxy150489 phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT;
2946735Scc210113 phy->ops.read_reg = e1000_read_phy_reg_bm;
2956735Scc210113 phy->ops.write_reg = e1000_write_phy_reg_bm;
2966735Scc210113 phy->ops.commit = e1000_phy_sw_reset_generic;
2974919Sxy150489 break;
2984919Sxy150489 default:
2994919Sxy150489 ret_val = -E1000_ERR_PHY;
3004919Sxy150489 goto out;
3014919Sxy150489 }
3024919Sxy150489
3034919Sxy150489 out:
3044919Sxy150489 return (ret_val);
3054919Sxy150489 }
3064919Sxy150489
3074919Sxy150489 /*
3084919Sxy150489 * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers
3094919Sxy150489 * @hw: pointer to the HW structure
3104919Sxy150489 *
3114919Sxy150489 * Initialize family-specific NVM parameters and function
3124919Sxy150489 * pointers.
3134919Sxy150489 */
3144919Sxy150489 static s32
e1000_init_nvm_params_ich8lan(struct e1000_hw * hw)3154919Sxy150489 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw)
3164919Sxy150489 {
3174919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
3188479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
3194919Sxy150489 u32 gfpreg, sector_base_addr, sector_end_addr;
3204919Sxy150489 s32 ret_val = E1000_SUCCESS;
3214919Sxy150489 u16 i;
3224919Sxy150489
3234919Sxy150489 DEBUGFUNC("e1000_init_nvm_params_ich8lan");
3244919Sxy150489
3254919Sxy150489 /* Can't read flash registers if the register set isn't mapped. */
3264919Sxy150489 if (!hw->flash_address) {
3274919Sxy150489 DEBUGOUT("ERROR: Flash registers not mapped\n");
3284919Sxy150489 ret_val = -E1000_ERR_CONFIG;
3294919Sxy150489 goto out;
3304919Sxy150489 }
3314919Sxy150489
3324919Sxy150489 nvm->type = e1000_nvm_flash_sw;
3334919Sxy150489
3344919Sxy150489 gfpreg = E1000_READ_FLASH_REG(hw, ICH_FLASH_GFPREG);
3354919Sxy150489
3364919Sxy150489 /*
3374919Sxy150489 * sector_X_addr is a "sector"-aligned address (4096 bytes) Add 1 to
3384919Sxy150489 * sector_end_addr since this sector is included in the overall size.
3394919Sxy150489 */
3404919Sxy150489 sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK;
3414919Sxy150489 sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1;
3424919Sxy150489
3434919Sxy150489 /* flash_base_addr is byte-aligned */
3444919Sxy150489 nvm->flash_base_addr = sector_base_addr << FLASH_SECTOR_ADDR_SHIFT;
3454919Sxy150489
3464919Sxy150489 /*
3474919Sxy150489 * find total size of the NVM, then cut in half since the total size
3484919Sxy150489 * represents two separate NVM banks.
3494919Sxy150489 */
3504919Sxy150489 nvm->flash_bank_size = (sector_end_addr - sector_base_addr)
3514919Sxy150489 << FLASH_SECTOR_ADDR_SHIFT;
3524919Sxy150489 nvm->flash_bank_size /= 2;
3534919Sxy150489 /* Adjust to word count */
3544919Sxy150489 nvm->flash_bank_size /= sizeof (u16);
3554919Sxy150489
3564919Sxy150489 nvm->word_size = E1000_SHADOW_RAM_WORDS;
3574919Sxy150489
3584919Sxy150489 /* Clear shadow ram */
3594919Sxy150489 for (i = 0; i < nvm->word_size; i++) {
3607607STed.You@Sun.COM dev_spec->shadow_ram[i].modified = false;
3614919Sxy150489 dev_spec->shadow_ram[i].value = 0xFFFF;
3624919Sxy150489 }
3634919Sxy150489
36410680SMin.Xu@Sun.COM E1000_MUTEX_INIT(&dev_spec->nvm_mutex);
36510680SMin.Xu@Sun.COM E1000_MUTEX_INIT(&dev_spec->swflag_mutex);
36610680SMin.Xu@Sun.COM
3674919Sxy150489 /* Function Pointers */
36810680SMin.Xu@Sun.COM nvm->ops.acquire = e1000_acquire_nvm_ich8lan;
36910680SMin.Xu@Sun.COM nvm->ops.release = e1000_release_nvm_ich8lan;
3706735Scc210113 nvm->ops.read = e1000_read_nvm_ich8lan;
3716735Scc210113 nvm->ops.update = e1000_update_nvm_checksum_ich8lan;
3726735Scc210113 nvm->ops.valid_led_default = e1000_valid_led_default_ich8lan;
3736735Scc210113 nvm->ops.validate = e1000_validate_nvm_checksum_ich8lan;
3746735Scc210113 nvm->ops.write = e1000_write_nvm_ich8lan;
3754919Sxy150489
3764919Sxy150489 out:
3774919Sxy150489 return (ret_val);
3784919Sxy150489 }
3794919Sxy150489
3804919Sxy150489 /*
3814919Sxy150489 * e1000_init_mac_params_ich8lan - Initialize MAC function pointers
3824919Sxy150489 * @hw: pointer to the HW structure
3834919Sxy150489 *
3844919Sxy150489 * Initialize family-specific MAC parameters and function
3854919Sxy150489 * pointers.
3864919Sxy150489 */
3874919Sxy150489 static s32
e1000_init_mac_params_ich8lan(struct e1000_hw * hw)3884919Sxy150489 e1000_init_mac_params_ich8lan(struct e1000_hw *hw)
3894919Sxy150489 {
3904919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
3914919Sxy150489
3924919Sxy150489 DEBUGFUNC("e1000_init_mac_params_ich8lan");
3934919Sxy150489
3944919Sxy150489 /* Set media type function pointer */
3956735Scc210113 hw->phy.media_type = e1000_media_type_copper;
3964919Sxy150489
3974919Sxy150489 /* Set mta register count */
3984919Sxy150489 mac->mta_reg_count = 32;
3994919Sxy150489 /* Set rar entry count */
4004919Sxy150489 mac->rar_entry_count = E1000_ICH_RAR_ENTRIES;
4014919Sxy150489 if (mac->type == e1000_ich8lan)
4024919Sxy150489 mac->rar_entry_count--;
4034919Sxy150489 /* Set if part includes ASF firmware */
4047607STed.You@Sun.COM mac->asf_firmware_present = true;
4054919Sxy150489 /* Set if manageability features are enabled. */
4067607STed.You@Sun.COM mac->arc_subsystem_valid = true;
4074919Sxy150489
4084919Sxy150489 /* Function pointers */
4094919Sxy150489
4104919Sxy150489 /* bus type/speed/width */
4116735Scc210113 mac->ops.get_bus_info = e1000_get_bus_info_ich8lan;
41210680SMin.Xu@Sun.COM /* function id */
41310680SMin.Xu@Sun.COM mac->ops.set_lan_id = e1000_set_lan_id_single_port;
4144919Sxy150489 /* reset */
4156735Scc210113 mac->ops.reset_hw = e1000_reset_hw_ich8lan;
4164919Sxy150489 /* hw initialization */
4176735Scc210113 mac->ops.init_hw = e1000_init_hw_ich8lan;
4184919Sxy150489 /* link setup */
4196735Scc210113 mac->ops.setup_link = e1000_setup_link_ich8lan;
4204919Sxy150489 /* physical interface setup */
4216735Scc210113 mac->ops.setup_physical_interface = e1000_setup_copper_link_ich8lan;
4224919Sxy150489 /* check for link */
42310680SMin.Xu@Sun.COM mac->ops.check_for_link = e1000_check_for_copper_link_ich8lan;
4244919Sxy150489 /* check management mode */
4256735Scc210113 mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan;
4264919Sxy150489 /* link info */
4276735Scc210113 mac->ops.get_link_up_info = e1000_get_link_up_info_ich8lan;
4284919Sxy150489 /* multicast address update */
4296735Scc210113 mac->ops.update_mc_addr_list = e1000_update_mc_addr_list_generic;
4304919Sxy150489 /* setting MTA */
4316735Scc210113 mac->ops.mta_set = e1000_mta_set_generic;
4324919Sxy150489 /* clear hardware counters */
4336735Scc210113 mac->ops.clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan;
4344919Sxy150489
43510680SMin.Xu@Sun.COM /* LED operations */
43610680SMin.Xu@Sun.COM switch (mac->type) {
43710680SMin.Xu@Sun.COM case e1000_ich8lan:
43810680SMin.Xu@Sun.COM case e1000_ich9lan:
43910680SMin.Xu@Sun.COM case e1000_ich10lan:
44010680SMin.Xu@Sun.COM /* ID LED init */
44110680SMin.Xu@Sun.COM mac->ops.id_led_init = e1000_id_led_init_generic;
44210680SMin.Xu@Sun.COM /* blink LED */
44310680SMin.Xu@Sun.COM mac->ops.blink_led = e1000_blink_led_generic;
44410680SMin.Xu@Sun.COM /* setup LED */
44510680SMin.Xu@Sun.COM mac->ops.setup_led = e1000_setup_led_generic;
44610680SMin.Xu@Sun.COM /* cleanup LED */
44710680SMin.Xu@Sun.COM mac->ops.cleanup_led = e1000_cleanup_led_ich8lan;
44810680SMin.Xu@Sun.COM /* turn on/off LED */
44910680SMin.Xu@Sun.COM mac->ops.led_on = e1000_led_on_ich8lan;
45010680SMin.Xu@Sun.COM mac->ops.led_off = e1000_led_off_ich8lan;
45110680SMin.Xu@Sun.COM break;
45210680SMin.Xu@Sun.COM case e1000_pchlan:
45310680SMin.Xu@Sun.COM /* ID LED init */
45410680SMin.Xu@Sun.COM mac->ops.id_led_init = e1000_id_led_init_pchlan;
45510680SMin.Xu@Sun.COM /* setup LED */
45610680SMin.Xu@Sun.COM mac->ops.setup_led = e1000_setup_led_pchlan;
45710680SMin.Xu@Sun.COM /* cleanup LED */
45810680SMin.Xu@Sun.COM mac->ops.cleanup_led = e1000_cleanup_led_pchlan;
45910680SMin.Xu@Sun.COM /* turn on/off LED */
46010680SMin.Xu@Sun.COM mac->ops.led_on = e1000_led_on_pchlan;
46110680SMin.Xu@Sun.COM mac->ops.led_off = e1000_led_off_pchlan;
46210680SMin.Xu@Sun.COM break;
46310680SMin.Xu@Sun.COM default:
46410680SMin.Xu@Sun.COM break;
46510680SMin.Xu@Sun.COM }
46610680SMin.Xu@Sun.COM
4674919Sxy150489 /* Enable PCS Lock-loss workaround for ICH8 */
4684919Sxy150489 if (mac->type == e1000_ich8lan)
4697607STed.You@Sun.COM e1000_set_kmrn_lock_loss_workaround_ich8lan(hw, true);
4704919Sxy150489
4718479SChenlu.Chen@Sun.COM return (E1000_SUCCESS);
4724919Sxy150489 }
4734919Sxy150489
4744919Sxy150489 /*
47510680SMin.Xu@Sun.COM * e1000_check_for_copper_link_ich8lan - Check for link (Copper)
47610680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
47710680SMin.Xu@Sun.COM *
47810680SMin.Xu@Sun.COM * Checks to see of the link status of the hardware has changed. If a
47910680SMin.Xu@Sun.COM * change in link status has been detected, then we read the PHY registers
48010680SMin.Xu@Sun.COM * to get the current speed/duplex if link exists.
48110680SMin.Xu@Sun.COM */
48210680SMin.Xu@Sun.COM static s32
e1000_check_for_copper_link_ich8lan(struct e1000_hw * hw)48310680SMin.Xu@Sun.COM e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw)
48410680SMin.Xu@Sun.COM {
48510680SMin.Xu@Sun.COM struct e1000_mac_info *mac = &hw->mac;
48610680SMin.Xu@Sun.COM s32 ret_val;
48710680SMin.Xu@Sun.COM bool link;
48810680SMin.Xu@Sun.COM
48910680SMin.Xu@Sun.COM DEBUGFUNC("e1000_check_for_copper_link_ich8lan");
49010680SMin.Xu@Sun.COM
49110680SMin.Xu@Sun.COM /*
49210680SMin.Xu@Sun.COM * We only want to go out to the PHY registers to see if Auto-Neg
49310680SMin.Xu@Sun.COM * has completed and/or if our link status has changed. The
49410680SMin.Xu@Sun.COM * get_link_status flag is set upon receiving a Link Status
49510680SMin.Xu@Sun.COM * Change or Rx Sequence Error interrupt.
49610680SMin.Xu@Sun.COM */
49710680SMin.Xu@Sun.COM if (!mac->get_link_status) {
49810680SMin.Xu@Sun.COM ret_val = E1000_SUCCESS;
49910680SMin.Xu@Sun.COM goto out;
50010680SMin.Xu@Sun.COM }
50110680SMin.Xu@Sun.COM
50210680SMin.Xu@Sun.COM /*
50310680SMin.Xu@Sun.COM * First we want to see if the MII Status Register reports
50410680SMin.Xu@Sun.COM * link. If so, then we want to get the current speed/duplex
50510680SMin.Xu@Sun.COM * of the PHY.
50610680SMin.Xu@Sun.COM */
50710680SMin.Xu@Sun.COM ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
50810680SMin.Xu@Sun.COM if (ret_val)
50910680SMin.Xu@Sun.COM goto out;
51010680SMin.Xu@Sun.COM
51111020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan) {
51211020SMin.Xu@Sun.COM ret_val = e1000_k1_gig_workaround_hv(hw, link);
51311020SMin.Xu@Sun.COM if (ret_val)
51411020SMin.Xu@Sun.COM goto out;
51511020SMin.Xu@Sun.COM }
51611020SMin.Xu@Sun.COM
51710680SMin.Xu@Sun.COM if (!link)
51810680SMin.Xu@Sun.COM goto out; /* No link detected */
51910680SMin.Xu@Sun.COM
52010680SMin.Xu@Sun.COM mac->get_link_status = false;
52110680SMin.Xu@Sun.COM
52210680SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82578) {
52310680SMin.Xu@Sun.COM ret_val = e1000_link_stall_workaround_hv(hw);
52410680SMin.Xu@Sun.COM if (ret_val)
52510680SMin.Xu@Sun.COM goto out;
52610680SMin.Xu@Sun.COM }
52710680SMin.Xu@Sun.COM
52810680SMin.Xu@Sun.COM /*
52910680SMin.Xu@Sun.COM * Check if there was DownShift, must be checked
53010680SMin.Xu@Sun.COM * immediately after link-up
53110680SMin.Xu@Sun.COM */
532*11143SGuoqing.Zhu@Sun.COM (void) e1000_check_downshift_generic(hw);
53310680SMin.Xu@Sun.COM
53410680SMin.Xu@Sun.COM /*
53510680SMin.Xu@Sun.COM * If we are forcing speed/duplex, then we simply return since
53610680SMin.Xu@Sun.COM * we have already determined whether we have link or not.
53710680SMin.Xu@Sun.COM */
53810680SMin.Xu@Sun.COM if (!mac->autoneg) {
53910680SMin.Xu@Sun.COM ret_val = -E1000_ERR_CONFIG;
54010680SMin.Xu@Sun.COM goto out;
54110680SMin.Xu@Sun.COM }
54210680SMin.Xu@Sun.COM
54310680SMin.Xu@Sun.COM /*
54410680SMin.Xu@Sun.COM * Auto-Neg is enabled. Auto Speed Detection takes care
54510680SMin.Xu@Sun.COM * of MAC speed/duplex configuration. So we only need to
54610680SMin.Xu@Sun.COM * configure Collision Distance in the MAC.
54710680SMin.Xu@Sun.COM */
54810680SMin.Xu@Sun.COM e1000_config_collision_dist_generic(hw);
54910680SMin.Xu@Sun.COM
55010680SMin.Xu@Sun.COM /*
55110680SMin.Xu@Sun.COM * Configure Flow Control now that Auto-Neg has completed.
55210680SMin.Xu@Sun.COM * First, we need to restore the desired flow control
55310680SMin.Xu@Sun.COM * settings because we may have had to re-autoneg with a
55410680SMin.Xu@Sun.COM * different link partner.
55510680SMin.Xu@Sun.COM */
55610680SMin.Xu@Sun.COM ret_val = e1000_config_fc_after_link_up_generic(hw);
557*11143SGuoqing.Zhu@Sun.COM if (ret_val) {
558*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
55910680SMin.Xu@Sun.COM DEBUGOUT("Error configuring flow control\n");
560*11143SGuoqing.Zhu@Sun.COM }
56110680SMin.Xu@Sun.COM
56210680SMin.Xu@Sun.COM out:
56310680SMin.Xu@Sun.COM return (ret_val);
56410680SMin.Xu@Sun.COM }
56510680SMin.Xu@Sun.COM
56610680SMin.Xu@Sun.COM /*
5674919Sxy150489 * e1000_init_function_pointers_ich8lan - Initialize ICH8 function pointers
5684919Sxy150489 * @hw: pointer to the HW structure
5694919Sxy150489 *
5704919Sxy150489 * Initialize family-specific function pointers for PHY, MAC, and NVM.
5714919Sxy150489 */
5724919Sxy150489 void
e1000_init_function_pointers_ich8lan(struct e1000_hw * hw)5734919Sxy150489 e1000_init_function_pointers_ich8lan(struct e1000_hw *hw)
5744919Sxy150489 {
5754919Sxy150489 DEBUGFUNC("e1000_init_function_pointers_ich8lan");
5764919Sxy150489
5776735Scc210113 hw->mac.ops.init_params = e1000_init_mac_params_ich8lan;
5786735Scc210113 hw->nvm.ops.init_params = e1000_init_nvm_params_ich8lan;
57910680SMin.Xu@Sun.COM switch (hw->mac.type) {
58010680SMin.Xu@Sun.COM case e1000_ich8lan:
58110680SMin.Xu@Sun.COM case e1000_ich9lan:
58210680SMin.Xu@Sun.COM case e1000_ich10lan:
58310680SMin.Xu@Sun.COM hw->phy.ops.init_params = e1000_init_phy_params_ich8lan;
58410680SMin.Xu@Sun.COM break;
58510680SMin.Xu@Sun.COM case e1000_pchlan:
58610680SMin.Xu@Sun.COM hw->phy.ops.init_params = e1000_init_phy_params_pchlan;
58710680SMin.Xu@Sun.COM break;
58810680SMin.Xu@Sun.COM default:
58910680SMin.Xu@Sun.COM break;
59010680SMin.Xu@Sun.COM }
59110680SMin.Xu@Sun.COM }
59210680SMin.Xu@Sun.COM
59310680SMin.Xu@Sun.COM /*
59410680SMin.Xu@Sun.COM * e1000_acquire_nvm_ich8lan - Acquire NVM mutex
59510680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
59610680SMin.Xu@Sun.COM *
59710680SMin.Xu@Sun.COM * Acquires the mutex for performing NVM operations.
59810680SMin.Xu@Sun.COM */
59910680SMin.Xu@Sun.COM static s32
e1000_acquire_nvm_ich8lan(struct e1000_hw * hw)60010680SMin.Xu@Sun.COM e1000_acquire_nvm_ich8lan(struct e1000_hw *hw)
60110680SMin.Xu@Sun.COM {
60210680SMin.Xu@Sun.COM DEBUGFUNC("e1000_acquire_nvm_ich8lan");
60310680SMin.Xu@Sun.COM
60410680SMin.Xu@Sun.COM E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.nvm_mutex);
60510680SMin.Xu@Sun.COM
60610680SMin.Xu@Sun.COM return (E1000_SUCCESS);
60710680SMin.Xu@Sun.COM }
60810680SMin.Xu@Sun.COM
60910680SMin.Xu@Sun.COM /*
61010680SMin.Xu@Sun.COM * e1000_release_nvm_ich8lan - Release NVM mutex
61110680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
61210680SMin.Xu@Sun.COM *
61310680SMin.Xu@Sun.COM * Releases the mutex used while performing NVM operations.
61410680SMin.Xu@Sun.COM */
61510680SMin.Xu@Sun.COM static void
e1000_release_nvm_ich8lan(struct e1000_hw * hw)61610680SMin.Xu@Sun.COM e1000_release_nvm_ich8lan(struct e1000_hw *hw)
61710680SMin.Xu@Sun.COM {
61810680SMin.Xu@Sun.COM DEBUGFUNC("e1000_release_nvm_ich8lan");
61910680SMin.Xu@Sun.COM
62010680SMin.Xu@Sun.COM E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.nvm_mutex);
6214919Sxy150489 }
6224919Sxy150489
6234919Sxy150489 /*
6244919Sxy150489 * e1000_acquire_swflag_ich8lan - Acquire software control flag
6254919Sxy150489 * @hw: pointer to the HW structure
6264919Sxy150489 *
62711020SMin.Xu@Sun.COM * Acquires the software control flag for performing PHY and select
62811020SMin.Xu@Sun.COM * MAC CSR accesses.
6294919Sxy150489 */
6304919Sxy150489 static s32
e1000_acquire_swflag_ich8lan(struct e1000_hw * hw)6314919Sxy150489 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw)
6324919Sxy150489 {
6334919Sxy150489 u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT;
6344919Sxy150489 s32 ret_val = E1000_SUCCESS;
6354919Sxy150489
6364919Sxy150489 DEBUGFUNC("e1000_acquire_swflag_ich8lan");
6374919Sxy150489
63810680SMin.Xu@Sun.COM E1000_MUTEX_LOCK(&hw->dev_spec.ich8lan.swflag_mutex);
63910680SMin.Xu@Sun.COM
6404919Sxy150489 while (timeout) {
6414919Sxy150489 extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
64210680SMin.Xu@Sun.COM if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG))
6434919Sxy150489 break;
64410680SMin.Xu@Sun.COM
6454919Sxy150489 msec_delay_irq(1);
6464919Sxy150489 timeout--;
6474919Sxy150489 }
6484919Sxy150489
6494919Sxy150489 if (!timeout) {
65010680SMin.Xu@Sun.COM DEBUGOUT("SW/FW/HW has locked the resource for too long.\n");
65110680SMin.Xu@Sun.COM ret_val = -E1000_ERR_CONFIG;
65210680SMin.Xu@Sun.COM goto out;
65310680SMin.Xu@Sun.COM }
65410680SMin.Xu@Sun.COM
65510680SMin.Xu@Sun.COM /* In some cases, hardware will take up to 400ms to set the SW flag. */
65610680SMin.Xu@Sun.COM timeout = SW_FLAG_TIMEOUT;
65710680SMin.Xu@Sun.COM
65810680SMin.Xu@Sun.COM extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG;
65910680SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
66010680SMin.Xu@Sun.COM
66110680SMin.Xu@Sun.COM while (timeout) {
66211020SMin.Xu@Sun.COM extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
66311020SMin.Xu@Sun.COM if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)
66411020SMin.Xu@Sun.COM break;
66510680SMin.Xu@Sun.COM
66610680SMin.Xu@Sun.COM msec_delay_irq(1);
66710680SMin.Xu@Sun.COM timeout--;
66810680SMin.Xu@Sun.COM }
66910680SMin.Xu@Sun.COM
67010680SMin.Xu@Sun.COM if (!timeout) {
67110680SMin.Xu@Sun.COM DEBUGOUT("Failed to acquire the semaphore.\n");
6726735Scc210113 extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
6736735Scc210113 E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
6744919Sxy150489 ret_val = -E1000_ERR_CONFIG;
6754919Sxy150489 goto out;
6764919Sxy150489 }
6774919Sxy150489
6784919Sxy150489 out:
67910680SMin.Xu@Sun.COM if (ret_val)
68010680SMin.Xu@Sun.COM E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
68110680SMin.Xu@Sun.COM
6824919Sxy150489 return (ret_val);
6834919Sxy150489 }
6844919Sxy150489
6854919Sxy150489 /*
6864919Sxy150489 * e1000_release_swflag_ich8lan - Release software control flag
6874919Sxy150489 * @hw: pointer to the HW structure
6884919Sxy150489 *
68911020SMin.Xu@Sun.COM * Releases the software control flag for performing PHY and select
69011020SMin.Xu@Sun.COM * MAC CSR accesses.
6914919Sxy150489 */
6924919Sxy150489 static void
e1000_release_swflag_ich8lan(struct e1000_hw * hw)6934919Sxy150489 e1000_release_swflag_ich8lan(struct e1000_hw *hw)
6944919Sxy150489 {
6954919Sxy150489 u32 extcnf_ctrl;
6964919Sxy150489
6974919Sxy150489 DEBUGFUNC("e1000_release_swflag_ich8lan");
6984919Sxy150489
6994919Sxy150489 extcnf_ctrl = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
7004919Sxy150489 extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG;
7014919Sxy150489 E1000_WRITE_REG(hw, E1000_EXTCNF_CTRL, extcnf_ctrl);
70210680SMin.Xu@Sun.COM
70310680SMin.Xu@Sun.COM E1000_MUTEX_UNLOCK(&hw->dev_spec.ich8lan.swflag_mutex);
7044919Sxy150489 }
7054919Sxy150489
7064919Sxy150489 /*
7074919Sxy150489 * e1000_check_mng_mode_ich8lan - Checks management mode
7084919Sxy150489 * @hw: pointer to the HW structure
7094919Sxy150489 *
7104919Sxy150489 * This checks if the adapter has manageability enabled.
7114919Sxy150489 * This is a function pointer entry point only called by read/write
7124919Sxy150489 * routines for the PHY and NVM parts.
7134919Sxy150489 */
7146735Scc210113 static bool
e1000_check_mng_mode_ich8lan(struct e1000_hw * hw)7154919Sxy150489 e1000_check_mng_mode_ich8lan(struct e1000_hw *hw)
7164919Sxy150489 {
7174919Sxy150489 u32 fwsm;
7184919Sxy150489
7194919Sxy150489 DEBUGFUNC("e1000_check_mng_mode_ich8lan");
7204919Sxy150489
7214919Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM);
7224919Sxy150489
7234919Sxy150489 return ((fwsm & E1000_FWSM_MODE_MASK) ==
7244919Sxy150489 (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT));
7254919Sxy150489 }
7264919Sxy150489
7274919Sxy150489 /*
7284919Sxy150489 * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked
7294919Sxy150489 * @hw: pointer to the HW structure
7304919Sxy150489 *
7314919Sxy150489 * Checks if firmware is blocking the reset of the PHY.
7324919Sxy150489 * This is a function pointer entry point only called by
7334919Sxy150489 * reset routines.
7344919Sxy150489 */
7354919Sxy150489 static s32
e1000_check_reset_block_ich8lan(struct e1000_hw * hw)7364919Sxy150489 e1000_check_reset_block_ich8lan(struct e1000_hw *hw)
7374919Sxy150489 {
7384919Sxy150489 u32 fwsm;
7394919Sxy150489
7404919Sxy150489 DEBUGFUNC("e1000_check_reset_block_ich8lan");
7414919Sxy150489
7424919Sxy150489 fwsm = E1000_READ_REG(hw, E1000_FWSM);
7434919Sxy150489
7444919Sxy150489 return ((fwsm & E1000_ICH_FWSM_RSPCIPHY) ? E1000_SUCCESS
7454919Sxy150489 : E1000_BLK_PHY_RESET);
7464919Sxy150489 }
7474919Sxy150489
7484919Sxy150489 /*
74911020SMin.Xu@Sun.COM * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration
75011020SMin.Xu@Sun.COM * @hw: pointer to the HW structure
75111020SMin.Xu@Sun.COM *
75211020SMin.Xu@Sun.COM * SW should configure the LCD from the NVM extended configuration region
75311020SMin.Xu@Sun.COM * as a workaround for certain parts.
75411020SMin.Xu@Sun.COM */
75511020SMin.Xu@Sun.COM static s32
e1000_sw_lcd_config_ich8lan(struct e1000_hw * hw)75611020SMin.Xu@Sun.COM e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw)
75711020SMin.Xu@Sun.COM {
75811020SMin.Xu@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
75911020SMin.Xu@Sun.COM struct e1000_phy_info *phy = &hw->phy;
76011020SMin.Xu@Sun.COM u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask;
76111020SMin.Xu@Sun.COM s32 ret_val;
76211020SMin.Xu@Sun.COM u16 word_addr, reg_data, reg_addr, phy_page = 0;
76311020SMin.Xu@Sun.COM
76411020SMin.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
76511020SMin.Xu@Sun.COM if (ret_val)
76611020SMin.Xu@Sun.COM return (ret_val);
76711020SMin.Xu@Sun.COM
76811020SMin.Xu@Sun.COM /*
76911020SMin.Xu@Sun.COM * Initialize the PHY from the NVM on ICH platforms. This
77011020SMin.Xu@Sun.COM * is needed due to an issue where the NVM configuration is
77111020SMin.Xu@Sun.COM * not properly autoloaded after power transitions.
77211020SMin.Xu@Sun.COM * Therefore, after each PHY reset, we will load the
77311020SMin.Xu@Sun.COM * configuration data out of the NVM manually.
77411020SMin.Xu@Sun.COM */
77511020SMin.Xu@Sun.COM if ((hw->mac.type == e1000_ich8lan && phy->type == e1000_phy_igp_3) ||
77611020SMin.Xu@Sun.COM (hw->mac.type == e1000_pchlan)) {
77711020SMin.Xu@Sun.COM /* Check if SW needs to configure the PHY */
77811020SMin.Xu@Sun.COM if ((hw->device_id == E1000_DEV_ID_ICH8_IGP_M_AMT) ||
77911020SMin.Xu@Sun.COM (hw->device_id == E1000_DEV_ID_ICH8_IGP_M) ||
78011020SMin.Xu@Sun.COM (hw->mac.type == e1000_pchlan))
78111020SMin.Xu@Sun.COM sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M;
78211020SMin.Xu@Sun.COM else
78311020SMin.Xu@Sun.COM sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG;
78411020SMin.Xu@Sun.COM
78511020SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_FEXTNVM);
78611020SMin.Xu@Sun.COM if (!(data & sw_cfg_mask))
78711020SMin.Xu@Sun.COM goto out;
78811020SMin.Xu@Sun.COM
78911020SMin.Xu@Sun.COM /* Wait for basic configuration completes before proceeding */
79011020SMin.Xu@Sun.COM e1000_lan_init_done_ich8lan(hw);
79111020SMin.Xu@Sun.COM
79211020SMin.Xu@Sun.COM /*
79311020SMin.Xu@Sun.COM * Make sure HW does not configure LCD from PHY
79411020SMin.Xu@Sun.COM * extended configuration before SW configuration
79511020SMin.Xu@Sun.COM */
79611020SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
79711020SMin.Xu@Sun.COM if (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)
79811020SMin.Xu@Sun.COM goto out;
79911020SMin.Xu@Sun.COM
80011020SMin.Xu@Sun.COM cnf_size = E1000_READ_REG(hw, E1000_EXTCNF_SIZE);
80111020SMin.Xu@Sun.COM cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK;
80211020SMin.Xu@Sun.COM cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT;
80311020SMin.Xu@Sun.COM if (!cnf_size)
80411020SMin.Xu@Sun.COM goto out;
80511020SMin.Xu@Sun.COM
80611020SMin.Xu@Sun.COM cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK;
80711020SMin.Xu@Sun.COM cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT;
80811020SMin.Xu@Sun.COM
80911020SMin.Xu@Sun.COM if (!(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) &&
81011020SMin.Xu@Sun.COM hw->mac.type == e1000_pchlan) {
81111020SMin.Xu@Sun.COM /*
81211020SMin.Xu@Sun.COM * HW configures the SMBus address and LEDs when the
81311020SMin.Xu@Sun.COM * OEM and LCD Write Enable bits are set in the NVM.
81411020SMin.Xu@Sun.COM * When both NVM bits are cleared, SW will configure
81511020SMin.Xu@Sun.COM * them instead.
81611020SMin.Xu@Sun.COM */
81711020SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_STRAP);
81811020SMin.Xu@Sun.COM data &= E1000_STRAP_SMBUS_ADDRESS_MASK;
81911020SMin.Xu@Sun.COM reg_data = data >> E1000_STRAP_SMBUS_ADDRESS_SHIFT;
82011020SMin.Xu@Sun.COM reg_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID;
82111020SMin.Xu@Sun.COM ret_val = e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR,
82211020SMin.Xu@Sun.COM reg_data);
82311020SMin.Xu@Sun.COM if (ret_val)
82411020SMin.Xu@Sun.COM goto out;
82511020SMin.Xu@Sun.COM
82611020SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_LEDCTL);
82711020SMin.Xu@Sun.COM ret_val = e1000_write_phy_reg_hv_locked(hw,
82811020SMin.Xu@Sun.COM HV_LED_CONFIG, (u16)data);
82911020SMin.Xu@Sun.COM if (ret_val)
83011020SMin.Xu@Sun.COM goto out;
83111020SMin.Xu@Sun.COM
83211020SMin.Xu@Sun.COM dev_spec->nvm_lcd_config_enabled = true;
83311020SMin.Xu@Sun.COM }
83411020SMin.Xu@Sun.COM /* Configure LCD from extended configuration region. */
83511020SMin.Xu@Sun.COM
83611020SMin.Xu@Sun.COM /* cnf_base_addr is in DWORD */
83711020SMin.Xu@Sun.COM word_addr = (u16)(cnf_base_addr << 1);
83811020SMin.Xu@Sun.COM
83911020SMin.Xu@Sun.COM for (i = 0; i < cnf_size; i++) {
84011020SMin.Xu@Sun.COM ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2), 1,
84111020SMin.Xu@Sun.COM ®_data);
84211020SMin.Xu@Sun.COM if (ret_val)
84311020SMin.Xu@Sun.COM goto out;
84411020SMin.Xu@Sun.COM
84511020SMin.Xu@Sun.COM ret_val = hw->nvm.ops.read(hw, (word_addr + i * 2 + 1),
84611020SMin.Xu@Sun.COM 1, ®_addr);
84711020SMin.Xu@Sun.COM if (ret_val)
84811020SMin.Xu@Sun.COM goto out;
84911020SMin.Xu@Sun.COM
85011020SMin.Xu@Sun.COM /* Save off the PHY page for future writes. */
85111020SMin.Xu@Sun.COM if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) {
85211020SMin.Xu@Sun.COM phy_page = reg_data;
85311020SMin.Xu@Sun.COM continue;
85411020SMin.Xu@Sun.COM }
85511020SMin.Xu@Sun.COM /*
85611020SMin.Xu@Sun.COM * Bit 5 in the LCD config word contains the phy
85711020SMin.Xu@Sun.COM * address for PCH
85811020SMin.Xu@Sun.COM */
85911020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan) {
86011020SMin.Xu@Sun.COM phy->addr = 1;
86111020SMin.Xu@Sun.COM if (reg_addr & LCD_CFG_PHY_ADDR_BIT) {
86211020SMin.Xu@Sun.COM phy->addr = 2;
86311020SMin.Xu@Sun.COM reg_addr &= PHY_REG_MASK;
86411020SMin.Xu@Sun.COM }
86511020SMin.Xu@Sun.COM }
86611020SMin.Xu@Sun.COM
86711020SMin.Xu@Sun.COM reg_addr |= phy_page;
86811020SMin.Xu@Sun.COM
86911020SMin.Xu@Sun.COM ret_val = phy->ops.write_reg_locked(hw, (u32)reg_addr,
87011020SMin.Xu@Sun.COM reg_data);
87111020SMin.Xu@Sun.COM if (ret_val)
87211020SMin.Xu@Sun.COM goto out;
87311020SMin.Xu@Sun.COM }
87411020SMin.Xu@Sun.COM
87511020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
87611020SMin.Xu@Sun.COM dev_spec->nvm_lcd_config_enabled = false;
87711020SMin.Xu@Sun.COM }
87811020SMin.Xu@Sun.COM
87911020SMin.Xu@Sun.COM out:
88011020SMin.Xu@Sun.COM hw->phy.ops.release(hw);
88111020SMin.Xu@Sun.COM return (ret_val);
88211020SMin.Xu@Sun.COM }
88311020SMin.Xu@Sun.COM
88411020SMin.Xu@Sun.COM /*
88511020SMin.Xu@Sun.COM * e1000_k1_gig_workaround_hv - K1 Si workaround
88611020SMin.Xu@Sun.COM * @hw: pointer to the HW structure
88711020SMin.Xu@Sun.COM * @link: link up bool flag
88811020SMin.Xu@Sun.COM *
88911020SMin.Xu@Sun.COM * If K1 is enabled for 1Gbps, the MAC might stall when transitioning
89011020SMin.Xu@Sun.COM * from a lower speed. This workaround disables K1 whenever link is at 1Gig
89111020SMin.Xu@Sun.COM * If link is down, the function will restore the default K1 setting located
89211020SMin.Xu@Sun.COM * in the NVM.
89311020SMin.Xu@Sun.COM */
89411020SMin.Xu@Sun.COM static s32
e1000_k1_gig_workaround_hv(struct e1000_hw * hw,bool link)89511020SMin.Xu@Sun.COM e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link)
89611020SMin.Xu@Sun.COM {
89711020SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
89811020SMin.Xu@Sun.COM u16 status_reg = 0;
89911020SMin.Xu@Sun.COM bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled;
90011020SMin.Xu@Sun.COM
90111020SMin.Xu@Sun.COM DEBUGFUNC("e1000_k1_gig_workaround_hv");
90211020SMin.Xu@Sun.COM
90311020SMin.Xu@Sun.COM if (hw->mac.type != e1000_pchlan)
90411020SMin.Xu@Sun.COM goto out;
90511020SMin.Xu@Sun.COM
90611020SMin.Xu@Sun.COM /* Wrap the whole flow with the sw flag */
90711020SMin.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
90811020SMin.Xu@Sun.COM if (ret_val)
90911020SMin.Xu@Sun.COM goto out;
91011020SMin.Xu@Sun.COM
91111020SMin.Xu@Sun.COM /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */
91211020SMin.Xu@Sun.COM if (link) {
91311020SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82578) {
91411020SMin.Xu@Sun.COM ret_val = hw->phy.ops.read_reg_locked(hw, BM_CS_STATUS,
91511020SMin.Xu@Sun.COM &status_reg);
91611020SMin.Xu@Sun.COM if (ret_val)
91711020SMin.Xu@Sun.COM goto release;
91811020SMin.Xu@Sun.COM
91911020SMin.Xu@Sun.COM status_reg &= BM_CS_STATUS_LINK_UP |
92011020SMin.Xu@Sun.COM BM_CS_STATUS_RESOLVED |
92111020SMin.Xu@Sun.COM BM_CS_STATUS_SPEED_MASK;
92211020SMin.Xu@Sun.COM
92311020SMin.Xu@Sun.COM if (status_reg == (BM_CS_STATUS_LINK_UP |
92411020SMin.Xu@Sun.COM BM_CS_STATUS_RESOLVED |
92511020SMin.Xu@Sun.COM BM_CS_STATUS_SPEED_1000))
92611020SMin.Xu@Sun.COM k1_enable = false;
92711020SMin.Xu@Sun.COM }
92811020SMin.Xu@Sun.COM
92911020SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82577) {
93011020SMin.Xu@Sun.COM ret_val = hw->phy.ops.read_reg_locked(hw, HV_M_STATUS,
93111020SMin.Xu@Sun.COM &status_reg);
93211020SMin.Xu@Sun.COM if (ret_val)
93311020SMin.Xu@Sun.COM goto release;
93411020SMin.Xu@Sun.COM
93511020SMin.Xu@Sun.COM status_reg &= HV_M_STATUS_LINK_UP |
93611020SMin.Xu@Sun.COM HV_M_STATUS_AUTONEG_COMPLETE |
93711020SMin.Xu@Sun.COM HV_M_STATUS_SPEED_MASK;
93811020SMin.Xu@Sun.COM
93911020SMin.Xu@Sun.COM if (status_reg == (HV_M_STATUS_LINK_UP |
94011020SMin.Xu@Sun.COM HV_M_STATUS_AUTONEG_COMPLETE |
94111020SMin.Xu@Sun.COM HV_M_STATUS_SPEED_1000))
94211020SMin.Xu@Sun.COM k1_enable = false;
94311020SMin.Xu@Sun.COM }
94411020SMin.Xu@Sun.COM
94511020SMin.Xu@Sun.COM /* Link stall fix for link up */
94611020SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
94711020SMin.Xu@Sun.COM 0x0100);
94811020SMin.Xu@Sun.COM if (ret_val)
94911020SMin.Xu@Sun.COM goto release;
95011020SMin.Xu@Sun.COM
95111020SMin.Xu@Sun.COM } else {
95211020SMin.Xu@Sun.COM /* Link stall fix for link down */
95311020SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg_locked(hw, PHY_REG(770, 19),
95411020SMin.Xu@Sun.COM 0x4100);
95511020SMin.Xu@Sun.COM if (ret_val)
95611020SMin.Xu@Sun.COM goto release;
95711020SMin.Xu@Sun.COM }
95811020SMin.Xu@Sun.COM
95911020SMin.Xu@Sun.COM ret_val = e1000_configure_k1_ich8lan(hw, k1_enable);
96011020SMin.Xu@Sun.COM
96111020SMin.Xu@Sun.COM release:
96211020SMin.Xu@Sun.COM hw->phy.ops.release(hw);
96311020SMin.Xu@Sun.COM out:
96411020SMin.Xu@Sun.COM return (ret_val);
96511020SMin.Xu@Sun.COM }
96611020SMin.Xu@Sun.COM
96711020SMin.Xu@Sun.COM /*
96811020SMin.Xu@Sun.COM * e1000_configure_k1_ich8lan - Configure K1 power state
96911020SMin.Xu@Sun.COM * @hw: pointer to the HW structure
97011020SMin.Xu@Sun.COM * @enable: K1 state to configure
97111020SMin.Xu@Sun.COM *
97211020SMin.Xu@Sun.COM * Configure the K1 power state based on the provided parameter.
97311020SMin.Xu@Sun.COM * Assumes semaphore already acquired.
97411020SMin.Xu@Sun.COM *
97511020SMin.Xu@Sun.COM * Success returns 0, Failure returns -E1000_ERR_PHY (-2)
97611020SMin.Xu@Sun.COM */
97711020SMin.Xu@Sun.COM s32
e1000_configure_k1_ich8lan(struct e1000_hw * hw,bool k1_enable)97811020SMin.Xu@Sun.COM e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable)
97911020SMin.Xu@Sun.COM {
98011020SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
98111020SMin.Xu@Sun.COM u32 ctrl_reg = 0;
98211020SMin.Xu@Sun.COM u32 ctrl_ext = 0;
98311020SMin.Xu@Sun.COM u32 reg = 0;
98411020SMin.Xu@Sun.COM u16 kmrn_reg = 0;
98511020SMin.Xu@Sun.COM
98611020SMin.Xu@Sun.COM ret_val = e1000_read_kmrn_reg_locked(hw,
98711020SMin.Xu@Sun.COM E1000_KMRNCTRLSTA_K1_CONFIG,
98811020SMin.Xu@Sun.COM &kmrn_reg);
98911020SMin.Xu@Sun.COM if (ret_val)
99011020SMin.Xu@Sun.COM goto out;
99111020SMin.Xu@Sun.COM
99211020SMin.Xu@Sun.COM if (k1_enable)
99311020SMin.Xu@Sun.COM kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE;
99411020SMin.Xu@Sun.COM else
99511020SMin.Xu@Sun.COM kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE;
99611020SMin.Xu@Sun.COM
99711020SMin.Xu@Sun.COM ret_val = e1000_write_kmrn_reg_locked(hw,
99811020SMin.Xu@Sun.COM E1000_KMRNCTRLSTA_K1_CONFIG,
99911020SMin.Xu@Sun.COM kmrn_reg);
100011020SMin.Xu@Sun.COM if (ret_val)
100111020SMin.Xu@Sun.COM goto out;
100211020SMin.Xu@Sun.COM
100311020SMin.Xu@Sun.COM usec_delay(20);
100411020SMin.Xu@Sun.COM ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
100511020SMin.Xu@Sun.COM ctrl_reg = E1000_READ_REG(hw, E1000_CTRL);
100611020SMin.Xu@Sun.COM
100711020SMin.Xu@Sun.COM reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100);
100811020SMin.Xu@Sun.COM reg |= E1000_CTRL_FRCSPD;
100911020SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_CTRL, reg);
101011020SMin.Xu@Sun.COM
101111020SMin.Xu@Sun.COM E1000_WRITE_REG(hw,
101211020SMin.Xu@Sun.COM E1000_CTRL_EXT,
101311020SMin.Xu@Sun.COM ctrl_ext | E1000_CTRL_EXT_SPD_BYPS);
101411020SMin.Xu@Sun.COM usec_delay(20);
101511020SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_CTRL, ctrl_reg);
101611020SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
101711020SMin.Xu@Sun.COM usec_delay(20);
101811020SMin.Xu@Sun.COM
101911020SMin.Xu@Sun.COM out:
102011020SMin.Xu@Sun.COM return (ret_val);
102111020SMin.Xu@Sun.COM }
102211020SMin.Xu@Sun.COM
102311020SMin.Xu@Sun.COM /*
102411020SMin.Xu@Sun.COM * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration
102511020SMin.Xu@Sun.COM * @hw: pointer to the HW structure
102611020SMin.Xu@Sun.COM * @d0_state: boolean if entering d0 or d3 device state
102711020SMin.Xu@Sun.COM *
102811020SMin.Xu@Sun.COM * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are
102911020SMin.Xu@Sun.COM * collectively called OEM bits. The OEM Write Enable bit and SW Config bit
103011020SMin.Xu@Sun.COM * in NVM determines whether HW should configure LPLU and Gbe Disable.
103111020SMin.Xu@Sun.COM */
103211020SMin.Xu@Sun.COM s32
e1000_oem_bits_config_ich8lan(struct e1000_hw * hw,bool d0_state)103311020SMin.Xu@Sun.COM e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state)
103411020SMin.Xu@Sun.COM {
103511020SMin.Xu@Sun.COM s32 ret_val = 0;
103611020SMin.Xu@Sun.COM u32 mac_reg;
103711020SMin.Xu@Sun.COM u16 oem_reg;
103811020SMin.Xu@Sun.COM
103911020SMin.Xu@Sun.COM if (hw->mac.type != e1000_pchlan)
104011020SMin.Xu@Sun.COM return (ret_val);
104111020SMin.Xu@Sun.COM
104211020SMin.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
104311020SMin.Xu@Sun.COM if (ret_val)
104411020SMin.Xu@Sun.COM return (ret_val);
104511020SMin.Xu@Sun.COM
104611020SMin.Xu@Sun.COM mac_reg = E1000_READ_REG(hw, E1000_EXTCNF_CTRL);
104711020SMin.Xu@Sun.COM if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)
104811020SMin.Xu@Sun.COM goto out;
104911020SMin.Xu@Sun.COM
105011020SMin.Xu@Sun.COM mac_reg = E1000_READ_REG(hw, E1000_FEXTNVM);
105111020SMin.Xu@Sun.COM if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M))
105211020SMin.Xu@Sun.COM goto out;
105311020SMin.Xu@Sun.COM
105411020SMin.Xu@Sun.COM mac_reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
105511020SMin.Xu@Sun.COM
105611020SMin.Xu@Sun.COM ret_val = hw->phy.ops.read_reg_locked(hw, HV_OEM_BITS, &oem_reg);
105711020SMin.Xu@Sun.COM if (ret_val)
105811020SMin.Xu@Sun.COM goto out;
105911020SMin.Xu@Sun.COM
106011020SMin.Xu@Sun.COM oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU);
106111020SMin.Xu@Sun.COM
106211020SMin.Xu@Sun.COM if (d0_state) {
106311020SMin.Xu@Sun.COM if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE)
106411020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_GBE_DIS;
106511020SMin.Xu@Sun.COM
106611020SMin.Xu@Sun.COM if (mac_reg & E1000_PHY_CTRL_D0A_LPLU)
106711020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_LPLU;
106811020SMin.Xu@Sun.COM } else {
106911020SMin.Xu@Sun.COM if (mac_reg & E1000_PHY_CTRL_NOND0A_GBE_DISABLE)
107011020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_GBE_DIS;
107111020SMin.Xu@Sun.COM
107211020SMin.Xu@Sun.COM if (mac_reg & E1000_PHY_CTRL_NOND0A_LPLU)
107311020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_LPLU;
107411020SMin.Xu@Sun.COM }
107511020SMin.Xu@Sun.COM /* Restart auto-neg to activate the bits */
107611020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_RESTART_AN;
107711020SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg_locked(hw, HV_OEM_BITS, oem_reg);
107811020SMin.Xu@Sun.COM
107911020SMin.Xu@Sun.COM out:
108011020SMin.Xu@Sun.COM hw->phy.ops.release(hw);
108111020SMin.Xu@Sun.COM
108211020SMin.Xu@Sun.COM return (ret_val);
108311020SMin.Xu@Sun.COM }
108411020SMin.Xu@Sun.COM
108511020SMin.Xu@Sun.COM /*
108610680SMin.Xu@Sun.COM * e1000_hv_phy_workarounds_ich8lan - A series of Phy workarounds to be
108710680SMin.Xu@Sun.COM * done after every PHY reset.
10884919Sxy150489 */
10894919Sxy150489 static s32
e1000_hv_phy_workarounds_ich8lan(struct e1000_hw * hw)109010680SMin.Xu@Sun.COM e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw)
10914919Sxy150489 {
109210680SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
109310680SMin.Xu@Sun.COM
109410680SMin.Xu@Sun.COM if (hw->mac.type != e1000_pchlan)
109511020SMin.Xu@Sun.COM goto out;
109610680SMin.Xu@Sun.COM
109710680SMin.Xu@Sun.COM if (((hw->phy.type == e1000_phy_82577) &&
109810680SMin.Xu@Sun.COM ((hw->phy.revision == 1) || (hw->phy.revision == 2))) ||
109910680SMin.Xu@Sun.COM ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) {
110010680SMin.Xu@Sun.COM /* Disable generation of early preamble */
110110680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
110210680SMin.Xu@Sun.COM if (ret_val)
110311020SMin.Xu@Sun.COM goto out;
110410680SMin.Xu@Sun.COM
110510680SMin.Xu@Sun.COM /* Preamble tuning for SSC */
110610680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
110710680SMin.Xu@Sun.COM if (ret_val)
110811020SMin.Xu@Sun.COM goto out;
11094919Sxy150489 }
111010680SMin.Xu@Sun.COM
111110680SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82578) {
111210680SMin.Xu@Sun.COM /*
111310680SMin.Xu@Sun.COM * Return registers to default by doing a soft reset then
111410680SMin.Xu@Sun.COM * writing 0x3140 to the control register.
111510680SMin.Xu@Sun.COM */
111610680SMin.Xu@Sun.COM if (hw->phy.revision < 2) {
1117*11143SGuoqing.Zhu@Sun.COM (void) e1000_phy_sw_reset_generic(hw);
111810680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_CONTROL,
111910680SMin.Xu@Sun.COM 0x3140);
112010680SMin.Xu@Sun.COM }
112110680SMin.Xu@Sun.COM }
112210680SMin.Xu@Sun.COM
112310680SMin.Xu@Sun.COM /* Select page 0 */
112410680SMin.Xu@Sun.COM ret_val = hw->phy.ops.acquire(hw);
11254919Sxy150489 if (ret_val)
112611020SMin.Xu@Sun.COM goto out;
112710680SMin.Xu@Sun.COM
112810680SMin.Xu@Sun.COM hw->phy.addr = 1;
112911020SMin.Xu@Sun.COM ret_val = e1000_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0);
113011020SMin.Xu@Sun.COM if (ret_val)
113111020SMin.Xu@Sun.COM goto out;
113210680SMin.Xu@Sun.COM hw->phy.ops.release(hw);
113310680SMin.Xu@Sun.COM
113411020SMin.Xu@Sun.COM /*
113511020SMin.Xu@Sun.COM * Configure the K1 Si workaround during phy reset assuming there is
113611020SMin.Xu@Sun.COM * link so that it disables K1 if link is in 1Gbps.
113711020SMin.Xu@Sun.COM */
113811020SMin.Xu@Sun.COM ret_val = e1000_k1_gig_workaround_hv(hw, true);
113911020SMin.Xu@Sun.COM
114011020SMin.Xu@Sun.COM out:
114110680SMin.Xu@Sun.COM return (ret_val);
114210680SMin.Xu@Sun.COM }
114310680SMin.Xu@Sun.COM
114410680SMin.Xu@Sun.COM /*
114510680SMin.Xu@Sun.COM * e1000_hv_phy_tuning_workaround_ich8lan - This is a Phy tuning work around
114610680SMin.Xu@Sun.COM * needed for Nahum3 + Hanksville testing, requested by HW team
114710680SMin.Xu@Sun.COM */
114810680SMin.Xu@Sun.COM static s32
e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw * hw)114910680SMin.Xu@Sun.COM e1000_hv_phy_tuning_workaround_ich8lan(struct e1000_hw *hw)
115010680SMin.Xu@Sun.COM {
115110680SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
115210680SMin.Xu@Sun.COM
115310680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_REG(769, 25), 0x4431);
11544919Sxy150489 if (ret_val)
11554919Sxy150489 goto out;
11564919Sxy150489
115710680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, PHY_REG(770, 16), 0xA204);
11584919Sxy150489 if (ret_val)
11594919Sxy150489 goto out;
11604919Sxy150489
116110680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x29, 0x66C0);
116210680SMin.Xu@Sun.COM if (ret_val)
116310680SMin.Xu@Sun.COM goto out;
116410680SMin.Xu@Sun.COM
116510680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, (1 << 6) | 0x1E, 0xFFFF);
11664919Sxy150489
11674919Sxy150489 out:
11684919Sxy150489 return (ret_val);
11694919Sxy150489 }
11704919Sxy150489
11714919Sxy150489 /*
117210680SMin.Xu@Sun.COM * e1000_lan_init_done_ich8lan - Check for PHY config completion
117310680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
117410680SMin.Xu@Sun.COM *
117510680SMin.Xu@Sun.COM * Check the appropriate indication the MAC has finished configuring the
117610680SMin.Xu@Sun.COM * PHY after a software reset.
117710680SMin.Xu@Sun.COM */
117810680SMin.Xu@Sun.COM static void
e1000_lan_init_done_ich8lan(struct e1000_hw * hw)117910680SMin.Xu@Sun.COM e1000_lan_init_done_ich8lan(struct e1000_hw *hw)
118010680SMin.Xu@Sun.COM {
118110680SMin.Xu@Sun.COM u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT;
118210680SMin.Xu@Sun.COM
118310680SMin.Xu@Sun.COM DEBUGFUNC("e1000_lan_init_done_ich8lan");
118410680SMin.Xu@Sun.COM
118510680SMin.Xu@Sun.COM /* Wait for basic configuration completes before proceeding */
118610680SMin.Xu@Sun.COM do {
118710680SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_STATUS);
118810680SMin.Xu@Sun.COM data &= E1000_STATUS_LAN_INIT_DONE;
118910680SMin.Xu@Sun.COM usec_delay(100);
119010680SMin.Xu@Sun.COM } while ((!data) && --loop);
119110680SMin.Xu@Sun.COM
119210680SMin.Xu@Sun.COM /*
119310680SMin.Xu@Sun.COM * If basic configuration is incomplete before the above loop
119410680SMin.Xu@Sun.COM * count reaches 0, loading the configuration from NVM will
119510680SMin.Xu@Sun.COM * leave the PHY in a bad state possibly resulting in no link.
119610680SMin.Xu@Sun.COM */
1197*11143SGuoqing.Zhu@Sun.COM if (loop == 0) {
1198*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
119910680SMin.Xu@Sun.COM DEBUGOUT("LAN_INIT_DONE not set, increase timeout\n");
1200*11143SGuoqing.Zhu@Sun.COM }
120110680SMin.Xu@Sun.COM
120210680SMin.Xu@Sun.COM /* Clear the Init Done bit for the next init event */
120310680SMin.Xu@Sun.COM data = E1000_READ_REG(hw, E1000_STATUS);
120410680SMin.Xu@Sun.COM data &= ~E1000_STATUS_LAN_INIT_DONE;
120510680SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_STATUS, data);
120610680SMin.Xu@Sun.COM }
120710680SMin.Xu@Sun.COM
120810680SMin.Xu@Sun.COM /*
12094919Sxy150489 * e1000_phy_hw_reset_ich8lan - Performs a PHY reset
12104919Sxy150489 * @hw: pointer to the HW structure
12114919Sxy150489 *
12124919Sxy150489 * Resets the PHY
12134919Sxy150489 * This is a function pointer entry point called by drivers
12144919Sxy150489 * or other shared routines.
12154919Sxy150489 */
12164919Sxy150489 static s32
e1000_phy_hw_reset_ich8lan(struct e1000_hw * hw)12174919Sxy150489 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw)
12184919Sxy150489 {
121911020SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
122011020SMin.Xu@Sun.COM u16 reg;
12214919Sxy150489
12224919Sxy150489 DEBUGFUNC("e1000_phy_hw_reset_ich8lan");
12234919Sxy150489
12244919Sxy150489 ret_val = e1000_phy_hw_reset_generic(hw);
12254919Sxy150489 if (ret_val)
12264919Sxy150489 goto out;
12274919Sxy150489
122810680SMin.Xu@Sun.COM /* Allow time for h/w to get to a quiescent state after reset */
122910680SMin.Xu@Sun.COM msec_delay(10);
123010680SMin.Xu@Sun.COM
123110680SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan) {
123210680SMin.Xu@Sun.COM ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
123310680SMin.Xu@Sun.COM if (ret_val)
123410680SMin.Xu@Sun.COM goto out;
123510680SMin.Xu@Sun.COM }
123610680SMin.Xu@Sun.COM
123710680SMin.Xu@Sun.COM if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE) {
123810680SMin.Xu@Sun.COM ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw);
123910680SMin.Xu@Sun.COM if (ret_val)
124010680SMin.Xu@Sun.COM goto out;
124110680SMin.Xu@Sun.COM }
124210680SMin.Xu@Sun.COM
124311020SMin.Xu@Sun.COM /* Dummy read to clear the phy wakeup bit after lcd reset */
124411020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
124511020SMin.Xu@Sun.COM hw->phy.ops.read_reg(hw, BM_WUC, ®);
124611020SMin.Xu@Sun.COM
124711020SMin.Xu@Sun.COM /* Configure the LCD with the extended configuration region in NVM */
124811020SMin.Xu@Sun.COM ret_val = e1000_sw_lcd_config_ich8lan(hw);
124911020SMin.Xu@Sun.COM if (ret_val)
125011020SMin.Xu@Sun.COM goto out;
125111020SMin.Xu@Sun.COM
125211020SMin.Xu@Sun.COM /* Configure the LCD with the OEM bits in NVM */
125311020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
125411020SMin.Xu@Sun.COM ret_val = e1000_oem_bits_config_ich8lan(hw, true);
12554919Sxy150489
12564919Sxy150489 out:
12574919Sxy150489 return (ret_val);
12584919Sxy150489 }
12594919Sxy150489 /*
12604919Sxy150489 * e1000_get_phy_info_ich8lan - Calls appropriate PHY type get_phy_info
12614919Sxy150489 * @hw: pointer to the HW structure
12624919Sxy150489 *
12634919Sxy150489 * Wrapper for calling the get_phy_info routines for the appropriate phy type.
12644919Sxy150489 */
12654919Sxy150489 static s32
e1000_get_phy_info_ich8lan(struct e1000_hw * hw)12664919Sxy150489 e1000_get_phy_info_ich8lan(struct e1000_hw *hw)
12674919Sxy150489 {
12684919Sxy150489 s32 ret_val = -E1000_ERR_PHY_TYPE;
12694919Sxy150489
12704919Sxy150489 DEBUGFUNC("e1000_get_phy_info_ich8lan");
12714919Sxy150489
12724919Sxy150489 switch (hw->phy.type) {
12734919Sxy150489 case e1000_phy_ife:
12744919Sxy150489 ret_val = e1000_get_phy_info_ife_ich8lan(hw);
12754919Sxy150489 break;
12764919Sxy150489 case e1000_phy_igp_3:
12774919Sxy150489 case e1000_phy_bm:
127810680SMin.Xu@Sun.COM case e1000_phy_82578:
127910680SMin.Xu@Sun.COM case e1000_phy_82577:
12804919Sxy150489 ret_val = e1000_get_phy_info_igp(hw);
12814919Sxy150489 break;
12824919Sxy150489 default:
12834919Sxy150489 break;
12844919Sxy150489 }
12854919Sxy150489
12864919Sxy150489 return (ret_val);
12874919Sxy150489 }
12884919Sxy150489
12894919Sxy150489 /*
12904919Sxy150489 * e1000_get_phy_info_ife_ich8lan - Retrieves various IFE PHY states
12914919Sxy150489 * @hw: pointer to the HW structure
12924919Sxy150489 *
12934919Sxy150489 * Populates "phy" structure with various feature states.
12944919Sxy150489 * This function is only called by other family-specific
12954919Sxy150489 * routines.
12964919Sxy150489 */
12974919Sxy150489 static s32
e1000_get_phy_info_ife_ich8lan(struct e1000_hw * hw)12984919Sxy150489 e1000_get_phy_info_ife_ich8lan(struct e1000_hw *hw)
12994919Sxy150489 {
13004919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
13014919Sxy150489 s32 ret_val;
13024919Sxy150489 u16 data;
13036735Scc210113 bool link;
13044919Sxy150489
13054919Sxy150489 DEBUGFUNC("e1000_get_phy_info_ife_ich8lan");
13064919Sxy150489
13074919Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
13084919Sxy150489 if (ret_val)
13094919Sxy150489 goto out;
13104919Sxy150489
13114919Sxy150489 if (!link) {
13124919Sxy150489 DEBUGOUT("Phy info is only valid if link is up\n");
13134919Sxy150489 ret_val = -E1000_ERR_CONFIG;
13144919Sxy150489 goto out;
13154919Sxy150489 }
13164919Sxy150489
13176735Scc210113 ret_val = phy->ops.read_reg(hw, IFE_PHY_SPECIAL_CONTROL, &data);
13184919Sxy150489 if (ret_val)
13194919Sxy150489 goto out;
13204919Sxy150489 phy->polarity_correction = (data & IFE_PSC_AUTO_POLARITY_DISABLE)
13217607STed.You@Sun.COM ? false : true;
13224919Sxy150489
13234919Sxy150489 if (phy->polarity_correction) {
132410680SMin.Xu@Sun.COM ret_val = e1000_check_polarity_ife(hw);
13254919Sxy150489 if (ret_val)
13264919Sxy150489 goto out;
13274919Sxy150489 } else {
13284919Sxy150489 /* Polarity is forced */
13294919Sxy150489 phy->cable_polarity = (data & IFE_PSC_FORCE_POLARITY)
13304919Sxy150489 ? e1000_rev_polarity_reversed
13314919Sxy150489 : e1000_rev_polarity_normal;
13324919Sxy150489 }
13334919Sxy150489
13346735Scc210113 ret_val = phy->ops.read_reg(hw, IFE_PHY_MDIX_CONTROL, &data);
13354919Sxy150489 if (ret_val)
13364919Sxy150489 goto out;
13374919Sxy150489
13387607STed.You@Sun.COM phy->is_mdix = (data & IFE_PMC_MDIX_STATUS) ? true : false;
13394919Sxy150489
13404919Sxy150489 /* The following parameters are undefined for 10/100 operation. */
13414919Sxy150489 phy->cable_length = E1000_CABLE_LENGTH_UNDEFINED;
13424919Sxy150489 phy->local_rx = e1000_1000t_rx_status_undefined;
13434919Sxy150489 phy->remote_rx = e1000_1000t_rx_status_undefined;
13444919Sxy150489
13454919Sxy150489 out:
13464919Sxy150489 return (ret_val);
13474919Sxy150489 }
13484919Sxy150489
13494919Sxy150489 /*
135011020SMin.Xu@Sun.COM * e1000_set_lplu_state_pchlan - Set Low Power Link Up state
135111020SMin.Xu@Sun.COM * @hw: pointer to the HW structure
135211020SMin.Xu@Sun.COM * @active: true to enable LPLU, false to disable
135311020SMin.Xu@Sun.COM *
135411020SMin.Xu@Sun.COM * Sets the LPLU state according to the active flag. For PCH, if OEM write
135511020SMin.Xu@Sun.COM * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set
135611020SMin.Xu@Sun.COM * the phy speed. This function will manually set the LPLU bit and restart
135711020SMin.Xu@Sun.COM * auto-neg as hw would do. D3 and D0 LPLU will call the same function
135811020SMin.Xu@Sun.COM * since it configures the same bit.
135911020SMin.Xu@Sun.COM */
136011020SMin.Xu@Sun.COM static s32
e1000_set_lplu_state_pchlan(struct e1000_hw * hw,bool active)136111020SMin.Xu@Sun.COM e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active)
136211020SMin.Xu@Sun.COM {
136311020SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
136411020SMin.Xu@Sun.COM u16 oem_reg;
136511020SMin.Xu@Sun.COM
136611020SMin.Xu@Sun.COM DEBUGFUNC("e1000_set_lplu_state_pchlan");
136711020SMin.Xu@Sun.COM
136811020SMin.Xu@Sun.COM ret_val = hw->phy.ops.read_reg(hw, HV_OEM_BITS, &oem_reg);
136911020SMin.Xu@Sun.COM if (ret_val)
137011020SMin.Xu@Sun.COM goto out;
137111020SMin.Xu@Sun.COM
137211020SMin.Xu@Sun.COM if (active)
137311020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_LPLU;
137411020SMin.Xu@Sun.COM else
137511020SMin.Xu@Sun.COM oem_reg &= ~HV_OEM_BITS_LPLU;
137611020SMin.Xu@Sun.COM
137711020SMin.Xu@Sun.COM oem_reg |= HV_OEM_BITS_RESTART_AN;
137811020SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw, HV_OEM_BITS, oem_reg);
137911020SMin.Xu@Sun.COM
138011020SMin.Xu@Sun.COM out:
138111020SMin.Xu@Sun.COM return (ret_val);
138211020SMin.Xu@Sun.COM }
138311020SMin.Xu@Sun.COM
138411020SMin.Xu@Sun.COM /*
13854919Sxy150489 * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state
13864919Sxy150489 * @hw: pointer to the HW structure
13877607STed.You@Sun.COM * @active: true to enable LPLU, false to disable
13884919Sxy150489 *
13894919Sxy150489 * Sets the LPLU D0 state according to the active flag. When
13904919Sxy150489 * activating LPLU this function also disables smart speed
13914919Sxy150489 * and vice versa. LPLU will not be activated unless the
13924919Sxy150489 * device autonegotiation advertisement meets standards of
13934919Sxy150489 * either 10 or 10/100 or 10/100/1000 at all duplexes.
13944919Sxy150489 * This is a function pointer entry point only called by
13954919Sxy150489 * PHY setup routines.
13964919Sxy150489 */
13974919Sxy150489 static s32
e1000_set_d0_lplu_state_ich8lan(struct e1000_hw * hw,bool active)13988479SChenlu.Chen@Sun.COM e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
13994919Sxy150489 {
14004919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
14014919Sxy150489 u32 phy_ctrl;
14024919Sxy150489 s32 ret_val = E1000_SUCCESS;
14034919Sxy150489 u16 data;
14044919Sxy150489
14054919Sxy150489 DEBUGFUNC("e1000_set_d0_lplu_state_ich8lan");
14064919Sxy150489
14076735Scc210113 if (phy->type == e1000_phy_ife)
14084919Sxy150489 goto out;
14094919Sxy150489
14104919Sxy150489 phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
14114919Sxy150489
14124919Sxy150489 if (active) {
14134919Sxy150489 phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU;
14144919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
14154919Sxy150489
141610680SMin.Xu@Sun.COM if (phy->type != e1000_phy_igp_3)
141710680SMin.Xu@Sun.COM goto out;
141810680SMin.Xu@Sun.COM
14194919Sxy150489 /*
14204919Sxy150489 * Call gig speed drop workaround on LPLU before accessing any
14214919Sxy150489 * PHY registers
14224919Sxy150489 */
142310680SMin.Xu@Sun.COM if (hw->mac.type == e1000_ich8lan)
14244919Sxy150489 e1000_gig_downshift_workaround_ich8lan(hw);
14254919Sxy150489
14264919Sxy150489 /* When LPLU is enabled, we should disable SmartSpeed */
14276735Scc210113 ret_val = phy->ops.read_reg(hw,
14284919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14294919Sxy150489 &data);
14304919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
14316735Scc210113 ret_val = phy->ops.write_reg(hw,
14324919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14334919Sxy150489 data);
14344919Sxy150489 if (ret_val)
14354919Sxy150489 goto out;
14364919Sxy150489 } else {
14374919Sxy150489 phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU;
14384919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
14394919Sxy150489
144010680SMin.Xu@Sun.COM if (phy->type != e1000_phy_igp_3)
144110680SMin.Xu@Sun.COM goto out;
144210680SMin.Xu@Sun.COM
14434919Sxy150489 /*
14444919Sxy150489 * LPLU and SmartSpeed are mutually exclusive. LPLU is used
14454919Sxy150489 * during Dx states where the power conservation is most
14464919Sxy150489 * important. During driver activity we should enable
14474919Sxy150489 * SmartSpeed, so performance is maintained.
14484919Sxy150489 */
14494919Sxy150489 if (phy->smart_speed == e1000_smart_speed_on) {
14506735Scc210113 ret_val = phy->ops.read_reg(hw,
14514919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14524919Sxy150489 &data);
14534919Sxy150489 if (ret_val)
14544919Sxy150489 goto out;
14554919Sxy150489
14564919Sxy150489 data |= IGP01E1000_PSCFR_SMART_SPEED;
14576735Scc210113 ret_val = phy->ops.write_reg(hw,
14584919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14594919Sxy150489 data);
14604919Sxy150489 if (ret_val)
14614919Sxy150489 goto out;
14624919Sxy150489 } else if (phy->smart_speed == e1000_smart_speed_off) {
14636735Scc210113 ret_val = phy->ops.read_reg(hw,
14644919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14654919Sxy150489 &data);
14664919Sxy150489 if (ret_val)
14674919Sxy150489 goto out;
14684919Sxy150489
14694919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
14706735Scc210113 ret_val = phy->ops.write_reg(hw,
14714919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
14724919Sxy150489 data);
14734919Sxy150489 if (ret_val)
14744919Sxy150489 goto out;
14754919Sxy150489 }
14764919Sxy150489 }
14774919Sxy150489
14784919Sxy150489 out:
14794919Sxy150489 return (ret_val);
14804919Sxy150489 }
14814919Sxy150489
14824919Sxy150489 /*
14834919Sxy150489 * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state
14844919Sxy150489 * @hw: pointer to the HW structure
14857607STed.You@Sun.COM * @active: true to enable LPLU, false to disable
14864919Sxy150489 *
14874919Sxy150489 * Sets the LPLU D3 state according to the active flag. When
14884919Sxy150489 * activating LPLU this function also disables smart speed
14894919Sxy150489 * and vice versa. LPLU will not be activated unless the
14904919Sxy150489 * device autonegotiation advertisement meets standards of
14914919Sxy150489 * either 10 or 10/100 or 10/100/1000 at all duplexes.
14924919Sxy150489 * This is a function pointer entry point only called by
14934919Sxy150489 * PHY setup routines.
14944919Sxy150489 */
14954919Sxy150489 static s32
e1000_set_d3_lplu_state_ich8lan(struct e1000_hw * hw,bool active)14968479SChenlu.Chen@Sun.COM e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active)
14974919Sxy150489 {
14984919Sxy150489 struct e1000_phy_info *phy = &hw->phy;
14994919Sxy150489 u32 phy_ctrl;
15004919Sxy150489 s32 ret_val = E1000_SUCCESS;
15014919Sxy150489 u16 data;
15024919Sxy150489
15034919Sxy150489 DEBUGFUNC("e1000_set_d3_lplu_state_ich8lan");
15044919Sxy150489
15054919Sxy150489 phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
15064919Sxy150489
15074919Sxy150489 if (!active) {
15084919Sxy150489 phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU;
15094919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
151010680SMin.Xu@Sun.COM
151110680SMin.Xu@Sun.COM if (phy->type != e1000_phy_igp_3)
151210680SMin.Xu@Sun.COM goto out;
151310680SMin.Xu@Sun.COM
15144919Sxy150489 /*
15154919Sxy150489 * LPLU and SmartSpeed are mutually exclusive. LPLU is used
15164919Sxy150489 * during Dx states where the power conservation is most
15174919Sxy150489 * important. During driver activity we should enable
15184919Sxy150489 * SmartSpeed, so performance is maintained.
15194919Sxy150489 */
15204919Sxy150489 if (phy->smart_speed == e1000_smart_speed_on) {
15216735Scc210113 ret_val = phy->ops.read_reg(hw,
15224919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15234919Sxy150489 &data);
15244919Sxy150489 if (ret_val)
15254919Sxy150489 goto out;
15264919Sxy150489
15274919Sxy150489 data |= IGP01E1000_PSCFR_SMART_SPEED;
15286735Scc210113 ret_val = phy->ops.write_reg(hw,
15294919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15304919Sxy150489 data);
15314919Sxy150489 if (ret_val)
15324919Sxy150489 goto out;
15334919Sxy150489 } else if (phy->smart_speed == e1000_smart_speed_off) {
15346735Scc210113 ret_val = phy->ops.read_reg(hw,
15354919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15364919Sxy150489 &data);
15374919Sxy150489 if (ret_val)
15384919Sxy150489 goto out;
15394919Sxy150489
15404919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
15416735Scc210113 ret_val = phy->ops.write_reg(hw,
15424919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15434919Sxy150489 data);
15444919Sxy150489 if (ret_val)
15454919Sxy150489 goto out;
15464919Sxy150489 }
15474919Sxy150489 } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) ||
15484919Sxy150489 (phy->autoneg_advertised == E1000_ALL_NOT_GIG) ||
15494919Sxy150489 (phy->autoneg_advertised == E1000_ALL_10_SPEED)) {
15504919Sxy150489 phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU;
15514919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
15524919Sxy150489
155310680SMin.Xu@Sun.COM if (phy->type != e1000_phy_igp_3)
155410680SMin.Xu@Sun.COM goto out;
155510680SMin.Xu@Sun.COM
15564919Sxy150489 /*
15574919Sxy150489 * Call gig speed drop workaround on LPLU before accessing any
15584919Sxy150489 * PHY registers
15594919Sxy150489 */
156010680SMin.Xu@Sun.COM if (hw->mac.type == e1000_ich8lan)
15614919Sxy150489 e1000_gig_downshift_workaround_ich8lan(hw);
15624919Sxy150489
15634919Sxy150489 /* When LPLU is enabled, we should disable SmartSpeed */
15646735Scc210113 ret_val = phy->ops.read_reg(hw,
15654919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15664919Sxy150489 &data);
15674919Sxy150489 if (ret_val)
15684919Sxy150489 goto out;
15694919Sxy150489
15704919Sxy150489 data &= ~IGP01E1000_PSCFR_SMART_SPEED;
15716735Scc210113 ret_val = phy->ops.write_reg(hw,
15724919Sxy150489 IGP01E1000_PHY_PORT_CONFIG,
15734919Sxy150489 data);
15744919Sxy150489 }
15754919Sxy150489
15764919Sxy150489 out:
15774919Sxy150489 return (ret_val);
15784919Sxy150489 }
15794919Sxy150489
15804919Sxy150489 /*
15816735Scc210113 * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1
15826735Scc210113 * @hw: pointer to the HW structure
15836735Scc210113 * @bank: pointer to the variable that returns the active bank
15846735Scc210113 *
15856735Scc210113 * Reads signature byte from the NVM using the flash access registers.
158610680SMin.Xu@Sun.COM * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank.
15876735Scc210113 */
15886735Scc210113 static s32
e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw * hw,u32 * bank)15896735Scc210113 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank)
15906735Scc210113 {
159110680SMin.Xu@Sun.COM u32 eecd;
15927607STed.You@Sun.COM struct e1000_nvm_info *nvm = &hw->nvm;
15937607STed.You@Sun.COM u32 bank1_offset = nvm->flash_bank_size * sizeof (u16);
15947607STed.You@Sun.COM u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1;
159510680SMin.Xu@Sun.COM u8 sig_byte = 0;
159610680SMin.Xu@Sun.COM s32 ret_val = E1000_SUCCESS;
159710680SMin.Xu@Sun.COM
159810680SMin.Xu@Sun.COM switch (hw->mac.type) {
159910680SMin.Xu@Sun.COM case e1000_ich8lan:
160010680SMin.Xu@Sun.COM case e1000_ich9lan:
160110680SMin.Xu@Sun.COM eecd = E1000_READ_REG(hw, E1000_EECD);
160210680SMin.Xu@Sun.COM if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) ==
160310680SMin.Xu@Sun.COM E1000_EECD_SEC1VAL_VALID_MASK) {
160410680SMin.Xu@Sun.COM if (eecd & E1000_EECD_SEC1VAL)
160510680SMin.Xu@Sun.COM *bank = 1;
160610680SMin.Xu@Sun.COM else
160710680SMin.Xu@Sun.COM *bank = 0;
160810680SMin.Xu@Sun.COM
160910680SMin.Xu@Sun.COM goto out;
161010680SMin.Xu@Sun.COM }
161110680SMin.Xu@Sun.COM DEBUGOUT("Unable to determine valid NVM bank via EEC - "
161210680SMin.Xu@Sun.COM "reading flash signature\n");
161310680SMin.Xu@Sun.COM /* fall-thru */
161410680SMin.Xu@Sun.COM default:
161510680SMin.Xu@Sun.COM /* set bank to 0 in case flash read fails */
161610680SMin.Xu@Sun.COM *bank = 0;
161710680SMin.Xu@Sun.COM
161810680SMin.Xu@Sun.COM /* Check bank 0 */
161910680SMin.Xu@Sun.COM ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset,
162010680SMin.Xu@Sun.COM &sig_byte);
162110680SMin.Xu@Sun.COM if (ret_val)
162210680SMin.Xu@Sun.COM goto out;
162310680SMin.Xu@Sun.COM if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
162410680SMin.Xu@Sun.COM E1000_ICH_NVM_SIG_VALUE) {
16257607STed.You@Sun.COM *bank = 0;
162610680SMin.Xu@Sun.COM goto out;
16277607STed.You@Sun.COM }
162810680SMin.Xu@Sun.COM
162910680SMin.Xu@Sun.COM /* Check bank 1 */
163010680SMin.Xu@Sun.COM ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset +
163110680SMin.Xu@Sun.COM bank1_offset, &sig_byte);
163210680SMin.Xu@Sun.COM if (ret_val)
163310680SMin.Xu@Sun.COM goto out;
163410680SMin.Xu@Sun.COM if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) ==
163510680SMin.Xu@Sun.COM E1000_ICH_NVM_SIG_VALUE) {
163610680SMin.Xu@Sun.COM *bank = 1;
163710680SMin.Xu@Sun.COM goto out;
163810680SMin.Xu@Sun.COM }
163910680SMin.Xu@Sun.COM
164010680SMin.Xu@Sun.COM DEBUGOUT("ERROR: No valid NVM bank present\n");
164110680SMin.Xu@Sun.COM ret_val = -E1000_ERR_NVM;
164210680SMin.Xu@Sun.COM break;
16437607STed.You@Sun.COM }
164410680SMin.Xu@Sun.COM out:
16456735Scc210113 return (ret_val);
16466735Scc210113 }
16476735Scc210113
16486735Scc210113 /*
16494919Sxy150489 * e1000_read_nvm_ich8lan - Read word(s) from the NVM
16504919Sxy150489 * @hw: pointer to the HW structure
16514919Sxy150489 * @offset: The offset (in bytes) of the word(s) to read.
16524919Sxy150489 * @words: Size of data to read in words
16534919Sxy150489 * @data: Pointer to the word(s) to read at offset.
16544919Sxy150489 *
16554919Sxy150489 * Reads a word(s) from the NVM using the flash access registers.
16564919Sxy150489 */
16574919Sxy150489 static s32
e1000_read_nvm_ich8lan(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)16586735Scc210113 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words,
16596735Scc210113 u16 *data)
16604919Sxy150489 {
16614919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
16628479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
16634919Sxy150489 u32 act_offset;
16644919Sxy150489 s32 ret_val = E1000_SUCCESS;
16656735Scc210113 u32 bank = 0;
16664919Sxy150489 u16 i, word;
16674919Sxy150489
16684919Sxy150489 DEBUGFUNC("e1000_read_nvm_ich8lan");
16694919Sxy150489
16704919Sxy150489 if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
16714919Sxy150489 (words == 0)) {
16724919Sxy150489 DEBUGOUT("nvm parameter(s) out of bounds\n");
16734919Sxy150489 ret_val = -E1000_ERR_NVM;
16744919Sxy150489 goto out;
16754919Sxy150489 }
16764919Sxy150489
167710680SMin.Xu@Sun.COM nvm->ops.acquire(hw);
16784919Sxy150489
16796735Scc210113 ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
168010680SMin.Xu@Sun.COM if (ret_val != E1000_SUCCESS) {
168110680SMin.Xu@Sun.COM DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
168210680SMin.Xu@Sun.COM bank = 0;
168310680SMin.Xu@Sun.COM }
16846735Scc210113
16856735Scc210113 act_offset = (bank) ? nvm->flash_bank_size : 0;
16864919Sxy150489 act_offset += offset;
16874919Sxy150489
168810680SMin.Xu@Sun.COM ret_val = E1000_SUCCESS;
16894919Sxy150489 for (i = 0; i < words; i++) {
16904919Sxy150489 if ((dev_spec->shadow_ram) &&
16914919Sxy150489 (dev_spec->shadow_ram[offset + i].modified)) {
16924919Sxy150489 data[i] = dev_spec->shadow_ram[offset + i].value;
16934919Sxy150489 } else {
16944919Sxy150489 ret_val = e1000_read_flash_word_ich8lan(hw,
16954919Sxy150489 act_offset + i,
16964919Sxy150489 &word);
16974919Sxy150489 if (ret_val)
16984919Sxy150489 break;
16994919Sxy150489 data[i] = word;
17004919Sxy150489 }
17014919Sxy150489 }
17024919Sxy150489
17036735Scc210113 nvm->ops.release(hw);
17044919Sxy150489
17054919Sxy150489 out:
1706*11143SGuoqing.Zhu@Sun.COM if (ret_val) {
1707*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
170810680SMin.Xu@Sun.COM DEBUGOUT1("NVM read error: %d\n", ret_val);
1709*11143SGuoqing.Zhu@Sun.COM }
171010680SMin.Xu@Sun.COM
17114919Sxy150489 return (ret_val);
17124919Sxy150489 }
17134919Sxy150489
17144919Sxy150489 /*
17154919Sxy150489 * e1000_flash_cycle_init_ich8lan - Initialize flash
17164919Sxy150489 * @hw: pointer to the HW structure
17174919Sxy150489 *
17184919Sxy150489 * This function does initial flash setup so that a new read/write/erase cycle
17194919Sxy150489 * can be started.
17204919Sxy150489 */
17214919Sxy150489 static s32
e1000_flash_cycle_init_ich8lan(struct e1000_hw * hw)17224919Sxy150489 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw)
17234919Sxy150489 {
17244919Sxy150489 union ich8_hws_flash_status hsfsts;
17254919Sxy150489 s32 ret_val = -E1000_ERR_NVM;
17264919Sxy150489 s32 i = 0;
17274919Sxy150489
17284919Sxy150489 DEBUGFUNC("e1000_flash_cycle_init_ich8lan");
17294919Sxy150489
17304919Sxy150489 hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
17314919Sxy150489
17324919Sxy150489 /* Check if the flash descriptor is valid */
17334919Sxy150489 if (hsfsts.hsf_status.fldesvalid == 0) {
17344919Sxy150489 DEBUGOUT("Flash descriptor invalid. "
17354919Sxy150489 "SW Sequencing must be used.");
17364919Sxy150489 goto out;
17374919Sxy150489 }
17384919Sxy150489
17394919Sxy150489 /* Clear FCERR and DAEL in hw status by writing 1 */
17404919Sxy150489 hsfsts.hsf_status.flcerr = 1;
17414919Sxy150489 hsfsts.hsf_status.dael = 1;
17424919Sxy150489
17434919Sxy150489 E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
17444919Sxy150489
17454919Sxy150489 /*
17464919Sxy150489 * Either we should have a hardware SPI cycle in progress bit to check
17474919Sxy150489 * against, in order to start a new cycle or FDONE bit should be
17486735Scc210113 * changed in the hardware so that it is 1 after hardware reset, which
17494919Sxy150489 * can then be used as an indication whether a cycle is in progress or
17504919Sxy150489 * has been completed.
17514919Sxy150489 */
17524919Sxy150489
17534919Sxy150489 if (hsfsts.hsf_status.flcinprog == 0) {
17544919Sxy150489 /*
17554919Sxy150489 * There is no cycle running at present, so we can start a
17564919Sxy150489 * cycle. Begin by setting Flash Cycle Done.
17574919Sxy150489 */
17584919Sxy150489 hsfsts.hsf_status.flcdone = 1;
17594919Sxy150489 E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFSTS, hsfsts.regval);
17604919Sxy150489 ret_val = E1000_SUCCESS;
17614919Sxy150489 } else {
17624919Sxy150489 /*
17634919Sxy150489 * Otherwise poll for sometime so the current cycle has a
17644919Sxy150489 * chance to end before giving up.
17654919Sxy150489 */
17664919Sxy150489 for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) {
17674919Sxy150489 hsfsts.regval = E1000_READ_FLASH_REG16(hw,
17684919Sxy150489 ICH_FLASH_HSFSTS);
17694919Sxy150489 if (hsfsts.hsf_status.flcinprog == 0) {
17704919Sxy150489 ret_val = E1000_SUCCESS;
17714919Sxy150489 break;
17724919Sxy150489 }
17734919Sxy150489 usec_delay(1);
17744919Sxy150489 }
17754919Sxy150489 if (ret_val == E1000_SUCCESS) {
17764919Sxy150489 /*
17774919Sxy150489 * Successful in waiting for previous cycle to
17784919Sxy150489 * timeout, now set the Flash Cycle Done.
17794919Sxy150489 */
17804919Sxy150489 hsfsts.hsf_status.flcdone = 1;
17814919Sxy150489 E1000_WRITE_FLASH_REG16(hw,
17824919Sxy150489 ICH_FLASH_HSFSTS,
17834919Sxy150489 hsfsts.regval);
17844919Sxy150489 } else {
1785*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
17864919Sxy150489 DEBUGOUT("Flash controller busy, cannot get access");
17874919Sxy150489 }
17884919Sxy150489 }
17894919Sxy150489
17904919Sxy150489 out:
17914919Sxy150489 return (ret_val);
17924919Sxy150489 }
17934919Sxy150489
17944919Sxy150489 /*
17954919Sxy150489 * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase)
17964919Sxy150489 * @hw: pointer to the HW structure
17974919Sxy150489 * @timeout: maximum time to wait for completion
17984919Sxy150489 *
17994919Sxy150489 * This function starts a flash cycle and waits for its completion.
18004919Sxy150489 */
18014919Sxy150489 static s32
e1000_flash_cycle_ich8lan(struct e1000_hw * hw,u32 timeout)18024919Sxy150489 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout)
18034919Sxy150489 {
18044919Sxy150489 union ich8_hws_flash_ctrl hsflctl;
18054919Sxy150489 union ich8_hws_flash_status hsfsts;
18064919Sxy150489 s32 ret_val = -E1000_ERR_NVM;
18074919Sxy150489 u32 i = 0;
18084919Sxy150489
18094919Sxy150489 DEBUGFUNC("e1000_flash_cycle_ich8lan");
18104919Sxy150489
18114919Sxy150489 /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */
18124919Sxy150489 hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
18134919Sxy150489 hsflctl.hsf_ctrl.flcgo = 1;
18144919Sxy150489 E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
18154919Sxy150489
18164919Sxy150489 /* wait till FDONE bit is set to 1 */
18174919Sxy150489 do {
18184919Sxy150489 hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
18194919Sxy150489 if (hsfsts.hsf_status.flcdone == 1)
18204919Sxy150489 break;
18214919Sxy150489 usec_delay(1);
18224919Sxy150489 } while (i++ < timeout);
18234919Sxy150489
18244919Sxy150489 if (hsfsts.hsf_status.flcdone == 1 && hsfsts.hsf_status.flcerr == 0)
18254919Sxy150489 ret_val = E1000_SUCCESS;
18264919Sxy150489
18274919Sxy150489 return (ret_val);
18284919Sxy150489 }
18294919Sxy150489
18304919Sxy150489 /*
18314919Sxy150489 * e1000_read_flash_word_ich8lan - Read word from flash
18324919Sxy150489 * @hw: pointer to the HW structure
18334919Sxy150489 * @offset: offset to data location
18344919Sxy150489 * @data: pointer to the location for storing the data
18354919Sxy150489 *
18364919Sxy150489 * Reads the flash word at offset into data. Offset is converted
18374919Sxy150489 * to bytes before read.
18384919Sxy150489 */
18394919Sxy150489 static s32
e1000_read_flash_word_ich8lan(struct e1000_hw * hw,u32 offset,u16 * data)18404919Sxy150489 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, u16 *data)
18414919Sxy150489 {
18424919Sxy150489 s32 ret_val;
18434919Sxy150489
18444919Sxy150489 DEBUGFUNC("e1000_read_flash_word_ich8lan");
18454919Sxy150489
18464919Sxy150489 if (!data) {
18474919Sxy150489 ret_val = -E1000_ERR_NVM;
18484919Sxy150489 goto out;
18494919Sxy150489 }
18504919Sxy150489
18514919Sxy150489 /* Must convert offset into bytes. */
18524919Sxy150489 offset <<= 1;
18534919Sxy150489
18544919Sxy150489 ret_val = e1000_read_flash_data_ich8lan(hw, offset, 2, data);
18554919Sxy150489
18564919Sxy150489 out:
18574919Sxy150489 return (ret_val);
18584919Sxy150489 }
18594919Sxy150489
18604919Sxy150489 /*
18617607STed.You@Sun.COM * e1000_read_flash_byte_ich8lan - Read byte from flash
18627607STed.You@Sun.COM * @hw: pointer to the HW structure
18637607STed.You@Sun.COM * @offset: The offset of the byte to read.
18647607STed.You@Sun.COM * @data: Pointer to a byte to store the value read.
18657607STed.You@Sun.COM *
18667607STed.You@Sun.COM * Reads a single byte from the NVM using the flash access registers.
18677607STed.You@Sun.COM */
18687607STed.You@Sun.COM static s32
e1000_read_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 * data)18697607STed.You@Sun.COM e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, u8 *data)
18707607STed.You@Sun.COM {
18717607STed.You@Sun.COM s32 ret_val = E1000_SUCCESS;
18727607STed.You@Sun.COM u16 word = 0;
18737607STed.You@Sun.COM
18747607STed.You@Sun.COM ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word);
18757607STed.You@Sun.COM if (ret_val)
18767607STed.You@Sun.COM goto out;
18777607STed.You@Sun.COM
18787607STed.You@Sun.COM *data = (u8)word;
18797607STed.You@Sun.COM
18807607STed.You@Sun.COM out:
18817607STed.You@Sun.COM return (ret_val);
18827607STed.You@Sun.COM }
18837607STed.You@Sun.COM
18847607STed.You@Sun.COM /*
18854919Sxy150489 * e1000_read_flash_data_ich8lan - Read byte or word from NVM
18864919Sxy150489 * @hw: pointer to the HW structure
18874919Sxy150489 * @offset: The offset (in bytes) of the byte or word to read.
18884919Sxy150489 * @size: Size of data to read, 1=byte 2=word
18894919Sxy150489 * @data: Pointer to the word to store the value read.
18904919Sxy150489 *
18914919Sxy150489 * Reads a byte or word from the NVM using the flash access registers.
18924919Sxy150489 */
18934919Sxy150489 static s32
e1000_read_flash_data_ich8lan(struct e1000_hw * hw,u32 offset,u8 size,u16 * data)18944919Sxy150489 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
18954919Sxy150489 u8 size, u16 *data)
18964919Sxy150489 {
18974919Sxy150489 union ich8_hws_flash_status hsfsts;
18984919Sxy150489 union ich8_hws_flash_ctrl hsflctl;
18994919Sxy150489 u32 flash_linear_addr;
19004919Sxy150489 u32 flash_data = 0;
19014919Sxy150489 s32 ret_val = -E1000_ERR_NVM;
19024919Sxy150489 u8 count = 0;
19034919Sxy150489
19044919Sxy150489 DEBUGFUNC("e1000_read_flash_data_ich8lan");
19054919Sxy150489
19066735Scc210113 if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK)
19074919Sxy150489 goto out;
19084919Sxy150489
19094919Sxy150489 flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
19104919Sxy150489 hw->nvm.flash_base_addr;
19114919Sxy150489
19124919Sxy150489 do {
19134919Sxy150489 usec_delay(1);
19144919Sxy150489 /* Steps */
19154919Sxy150489 ret_val = e1000_flash_cycle_init_ich8lan(hw);
19164919Sxy150489 if (ret_val != E1000_SUCCESS)
19174919Sxy150489 break;
19184919Sxy150489
19194919Sxy150489 hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
19204919Sxy150489 /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
19214919Sxy150489 hsflctl.hsf_ctrl.fldbcount = size - 1;
19224919Sxy150489 hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ;
19234919Sxy150489 E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
19244919Sxy150489
19254919Sxy150489 E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
19264919Sxy150489
19274919Sxy150489 ret_val = e1000_flash_cycle_ich8lan(hw,
19284919Sxy150489 ICH_FLASH_READ_COMMAND_TIMEOUT);
19294919Sxy150489
19304919Sxy150489 /*
19314919Sxy150489 * Check if FCERR is set to 1, if set to 1, clear it and try
19324919Sxy150489 * the whole sequence a few more times, else read in (shift
19334919Sxy150489 * in) the Flash Data0, the order is least significant byte
19344919Sxy150489 * first msb to lsb
19354919Sxy150489 */
19364919Sxy150489 if (ret_val == E1000_SUCCESS) {
19374919Sxy150489 flash_data = E1000_READ_FLASH_REG(hw, ICH_FLASH_FDATA0);
19388479SChenlu.Chen@Sun.COM if (size == 1)
19394919Sxy150489 *data = (u8)(flash_data & 0x000000FF);
19408479SChenlu.Chen@Sun.COM else if (size == 2)
19414919Sxy150489 *data = (u16)(flash_data & 0x0000FFFF);
19424919Sxy150489 break;
19434919Sxy150489 } else {
19444919Sxy150489 /*
19454919Sxy150489 * If we've gotten here, then things are probably
19464919Sxy150489 * completely hosed, but if the error condition is
19474919Sxy150489 * detected, it won't hurt to give it another try...
19484919Sxy150489 * ICH_FLASH_CYCLE_REPEAT_COUNT times.
19494919Sxy150489 */
19504919Sxy150489 hsfsts.regval = E1000_READ_FLASH_REG16(hw,
19514919Sxy150489 ICH_FLASH_HSFSTS);
19524919Sxy150489 if (hsfsts.hsf_status.flcerr == 1) {
19534919Sxy150489 /* Repeat for some time before giving up. */
19544919Sxy150489 continue;
19554919Sxy150489 } else if (hsfsts.hsf_status.flcdone == 0) {
19564919Sxy150489 DEBUGOUT("Timeout error - flash cycle "
19574919Sxy150489 "did not complete.");
19584919Sxy150489 break;
19594919Sxy150489 }
19604919Sxy150489 }
19614919Sxy150489 } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
19624919Sxy150489
19634919Sxy150489 out:
19644919Sxy150489 return (ret_val);
19654919Sxy150489 }
19664919Sxy150489
19674919Sxy150489 /*
19684919Sxy150489 * e1000_write_nvm_ich8lan - Write word(s) to the NVM
19694919Sxy150489 * @hw: pointer to the HW structure
19704919Sxy150489 * @offset: The offset (in bytes) of the word(s) to write.
19714919Sxy150489 * @words: Size of data to write in words
19724919Sxy150489 * @data: Pointer to the word(s) to write at offset.
19734919Sxy150489 *
19744919Sxy150489 * Writes a byte or word to the NVM using the flash access registers.
19754919Sxy150489 */
19764919Sxy150489 static s32
e1000_write_nvm_ich8lan(struct e1000_hw * hw,u16 offset,u16 words,u16 * data)19774919Sxy150489 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, u16 *data)
19784919Sxy150489 {
19794919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
19808479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
19814919Sxy150489 s32 ret_val = E1000_SUCCESS;
19824919Sxy150489 u16 i;
19834919Sxy150489
19844919Sxy150489 DEBUGFUNC("e1000_write_nvm_ich8lan");
19854919Sxy150489
19864919Sxy150489 if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) ||
19874919Sxy150489 (words == 0)) {
19884919Sxy150489 DEBUGOUT("nvm parameter(s) out of bounds\n");
19894919Sxy150489 ret_val = -E1000_ERR_NVM;
19904919Sxy150489 goto out;
19914919Sxy150489 }
19924919Sxy150489
199310680SMin.Xu@Sun.COM nvm->ops.acquire(hw);
19944919Sxy150489
19954919Sxy150489 for (i = 0; i < words; i++) {
19967607STed.You@Sun.COM dev_spec->shadow_ram[offset + i].modified = true;
19974919Sxy150489 dev_spec->shadow_ram[offset + i].value = data[i];
19984919Sxy150489 }
19994919Sxy150489
20006735Scc210113 nvm->ops.release(hw);
20014919Sxy150489
20024919Sxy150489 out:
20034919Sxy150489 return (ret_val);
20044919Sxy150489 }
20054919Sxy150489
20064919Sxy150489 /*
20074919Sxy150489 * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM
20084919Sxy150489 * @hw: pointer to the HW structure
20094919Sxy150489 *
20104919Sxy150489 * The NVM checksum is updated by calling the generic update_nvm_checksum,
20114919Sxy150489 * which writes the checksum to the shadow ram. The changes in the shadow
20124919Sxy150489 * ram are then committed to the EEPROM by processing each bank at a time
20134919Sxy150489 * checking for the modified bit and writing only the pending changes.
20146735Scc210113 * After a successful commit, the shadow ram is cleared and is ready for
20154919Sxy150489 * future writes.
20164919Sxy150489 */
20174919Sxy150489 static s32
e1000_update_nvm_checksum_ich8lan(struct e1000_hw * hw)20184919Sxy150489 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw)
20194919Sxy150489 {
20204919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
20218479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
20226735Scc210113 u32 i, act_offset, new_bank_offset, old_bank_offset, bank;
20234919Sxy150489 s32 ret_val;
20244919Sxy150489 u16 data;
20254919Sxy150489
20264919Sxy150489 DEBUGFUNC("e1000_update_nvm_checksum_ich8lan");
20274919Sxy150489
20284919Sxy150489 ret_val = e1000_update_nvm_checksum_generic(hw);
20294919Sxy150489 if (ret_val)
20304919Sxy150489 goto out;
20314919Sxy150489
20324919Sxy150489 if (nvm->type != e1000_nvm_flash_sw)
20334919Sxy150489 goto out;
20344919Sxy150489
203510680SMin.Xu@Sun.COM nvm->ops.acquire(hw);
20364919Sxy150489
20374919Sxy150489 /*
20384919Sxy150489 * We're writing to the opposite bank so if we're on bank 1, write to
20394919Sxy150489 * bank 0 etc. We also need to erase the segment that is going to be
20404919Sxy150489 * written
20414919Sxy150489 */
20426735Scc210113 ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank);
204310680SMin.Xu@Sun.COM if (ret_val != E1000_SUCCESS) {
204410680SMin.Xu@Sun.COM DEBUGOUT("Could not detect valid bank, assuming bank 0\n");
204510680SMin.Xu@Sun.COM bank = 0;
204610680SMin.Xu@Sun.COM }
20476735Scc210113
20486735Scc210113 if (bank == 0) {
20494919Sxy150489 new_bank_offset = nvm->flash_bank_size;
20504919Sxy150489 old_bank_offset = 0;
205110680SMin.Xu@Sun.COM ret_val = e1000_erase_flash_bank_ich8lan(hw, 1);
205210680SMin.Xu@Sun.COM if (ret_val) {
205310680SMin.Xu@Sun.COM nvm->ops.release(hw);
205410680SMin.Xu@Sun.COM goto out;
205510680SMin.Xu@Sun.COM }
20564919Sxy150489 } else {
20574919Sxy150489 old_bank_offset = nvm->flash_bank_size;
20584919Sxy150489 new_bank_offset = 0;
205910680SMin.Xu@Sun.COM ret_val = e1000_erase_flash_bank_ich8lan(hw, 0);
206010680SMin.Xu@Sun.COM if (ret_val) {
206110680SMin.Xu@Sun.COM nvm->ops.release(hw);
206210680SMin.Xu@Sun.COM goto out;
206310680SMin.Xu@Sun.COM }
20644919Sxy150489 }
20654919Sxy150489
20664919Sxy150489 for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
20674919Sxy150489 /*
20684919Sxy150489 * Determine whether to write the value stored in the other
20694919Sxy150489 * NVM bank or a modified value stored in the shadow RAM
20704919Sxy150489 */
20714919Sxy150489 if (dev_spec->shadow_ram[i].modified) {
20724919Sxy150489 data = dev_spec->shadow_ram[i].value;
20734919Sxy150489 } else {
207410680SMin.Xu@Sun.COM ret_val = e1000_read_flash_word_ich8lan(hw,
20754919Sxy150489 i + old_bank_offset,
20764919Sxy150489 &data);
207710680SMin.Xu@Sun.COM if (ret_val)
207810680SMin.Xu@Sun.COM break;
20794919Sxy150489 }
20804919Sxy150489
20814919Sxy150489 /*
20824919Sxy150489 * If the word is 0x13, then make sure the signature bits
20834919Sxy150489 * (15:14) are 11b until the commit has completed. This will
20844919Sxy150489 * allow us to write 10b which indicates the signature is
20854919Sxy150489 * valid. We want to do this after the write has completed so
20864919Sxy150489 * that we don't mark the segment valid while the write is
20874919Sxy150489 * still in progress
20884919Sxy150489 */
20894919Sxy150489 if (i == E1000_ICH_NVM_SIG_WORD)
20904919Sxy150489 data |= E1000_ICH_NVM_SIG_MASK;
20914919Sxy150489
20924919Sxy150489 /* Convert offset to bytes. */
20934919Sxy150489 act_offset = (i + new_bank_offset) << 1;
20944919Sxy150489
20954919Sxy150489 usec_delay(100);
20964919Sxy150489 /* Write the bytes to the new bank. */
20974919Sxy150489 ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
20984919Sxy150489 act_offset,
20994919Sxy150489 (u8)data);
21004919Sxy150489 if (ret_val)
21014919Sxy150489 break;
21024919Sxy150489
21034919Sxy150489 usec_delay(100);
21044919Sxy150489 ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
21054919Sxy150489 act_offset + 1,
21064919Sxy150489 (u8)(data >> 8));
21074919Sxy150489 if (ret_val)
21084919Sxy150489 break;
21094919Sxy150489 }
21104919Sxy150489
21114919Sxy150489 /*
21124919Sxy150489 * Don't bother writing the segment valid bits if sector programming
21134919Sxy150489 * failed.
21144919Sxy150489 */
21154919Sxy150489 if (ret_val) {
21164919Sxy150489 DEBUGOUT("Flash commit failed.\n");
21176735Scc210113 nvm->ops.release(hw);
21184919Sxy150489 goto out;
21194919Sxy150489 }
21204919Sxy150489
21214919Sxy150489 /*
21224919Sxy150489 * Finally validate the new segment by setting bit 15:14 to 10b in
21234919Sxy150489 * word 0x13 , this can be done without an erase as well since these
21244919Sxy150489 * bits are 11 to start with and we need to change bit 14 to 0b
21254919Sxy150489 */
21264919Sxy150489 act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD;
212710680SMin.Xu@Sun.COM ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data);
212810680SMin.Xu@Sun.COM if (ret_val) {
212910680SMin.Xu@Sun.COM nvm->ops.release(hw);
213010680SMin.Xu@Sun.COM goto out;
213110680SMin.Xu@Sun.COM }
213210680SMin.Xu@Sun.COM
21334919Sxy150489 data &= 0xBFFF;
21344919Sxy150489 ret_val = e1000_retry_write_flash_byte_ich8lan(hw,
21354919Sxy150489 act_offset * 2 + 1,
21364919Sxy150489 (u8)(data >> 8));
21374919Sxy150489 if (ret_val) {
21386735Scc210113 nvm->ops.release(hw);
21394919Sxy150489 goto out;
21404919Sxy150489 }
21414919Sxy150489
21424919Sxy150489 /*
21434919Sxy150489 * And invalidate the previously valid segment by setting its
21444919Sxy150489 * signature word (0x13) high_byte to 0b. This can be done without an
21454919Sxy150489 * erase because flash erase sets all bits to 1's. We can write 1's to
21464919Sxy150489 * 0's without an erase
21474919Sxy150489 */
21484919Sxy150489 act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1;
21494919Sxy150489 ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0);
21504919Sxy150489 if (ret_val) {
21516735Scc210113 nvm->ops.release(hw);
21524919Sxy150489 goto out;
21534919Sxy150489 }
21546735Scc210113
21554919Sxy150489 /* Great! Everything worked, we can now clear the cached entries. */
21564919Sxy150489 for (i = 0; i < E1000_SHADOW_RAM_WORDS; i++) {
21577607STed.You@Sun.COM dev_spec->shadow_ram[i].modified = false;
21584919Sxy150489 dev_spec->shadow_ram[i].value = 0xFFFF;
21594919Sxy150489 }
21604919Sxy150489
21616735Scc210113 nvm->ops.release(hw);
21624919Sxy150489
21634919Sxy150489 /*
21644919Sxy150489 * Reload the EEPROM, or else modifications will not appear until
21654919Sxy150489 * after the next adapter reset.
21664919Sxy150489 */
21676735Scc210113 nvm->ops.reload(hw);
21684919Sxy150489 msec_delay(10);
21694919Sxy150489
21704919Sxy150489 out:
2171*11143SGuoqing.Zhu@Sun.COM if (ret_val) {
2172*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
217310680SMin.Xu@Sun.COM DEBUGOUT1("NVM update error: %d\n", ret_val);
2174*11143SGuoqing.Zhu@Sun.COM }
217510680SMin.Xu@Sun.COM
21764919Sxy150489 return (ret_val);
21774919Sxy150489 }
21784919Sxy150489
21794919Sxy150489 /*
21804919Sxy150489 * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum
21814919Sxy150489 * @hw: pointer to the HW structure
21824919Sxy150489 *
21834919Sxy150489 * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19.
21848479SChenlu.Chen@Sun.COM * If the bit is 0, that the EEPROM had been modified, but the checksum was not
21858479SChenlu.Chen@Sun.COM * calculated, in which case we need to calculate the checksum and set bit 6.
21864919Sxy150489 */
21874919Sxy150489 static s32
e1000_validate_nvm_checksum_ich8lan(struct e1000_hw * hw)21884919Sxy150489 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw)
21894919Sxy150489 {
21904919Sxy150489 s32 ret_val = E1000_SUCCESS;
21914919Sxy150489 u16 data;
21924919Sxy150489
21934919Sxy150489 DEBUGFUNC("e1000_validate_nvm_checksum_ich8lan");
21944919Sxy150489
21954919Sxy150489 /*
21964919Sxy150489 * Read 0x19 and check bit 6. If this bit is 0, the checksum needs to
21974919Sxy150489 * be fixed. This bit is an indication that the NVM was prepared by
21984919Sxy150489 * OEM software and did not calculate the checksum...a likely
21994919Sxy150489 * scenario.
22004919Sxy150489 */
22016735Scc210113 ret_val = hw->nvm.ops.read(hw, 0x19, 1, &data);
22024919Sxy150489 if (ret_val)
22034919Sxy150489 goto out;
22044919Sxy150489
22054919Sxy150489 if ((data & 0x40) == 0) {
22064919Sxy150489 data |= 0x40;
22076735Scc210113 ret_val = hw->nvm.ops.write(hw, 0x19, 1, &data);
22084919Sxy150489 if (ret_val)
22094919Sxy150489 goto out;
22106735Scc210113 ret_val = hw->nvm.ops.update(hw);
22114919Sxy150489 if (ret_val)
22124919Sxy150489 goto out;
22134919Sxy150489 }
22144919Sxy150489
22154919Sxy150489 ret_val = e1000_validate_nvm_checksum_generic(hw);
22164919Sxy150489
22174919Sxy150489 out:
22184919Sxy150489 return (ret_val);
22194919Sxy150489 }
22204919Sxy150489
22214919Sxy150489 /*
22224919Sxy150489 * e1000_write_flash_data_ich8lan - Writes bytes to the NVM
22234919Sxy150489 * @hw: pointer to the HW structure
22244919Sxy150489 * @offset: The offset (in bytes) of the byte/word to read.
22254919Sxy150489 * @size: Size of data to read, 1=byte 2=word
22264919Sxy150489 * @data: The byte(s) to write to the NVM.
22274919Sxy150489 *
22284919Sxy150489 * Writes one/two bytes to the NVM using the flash access registers.
22294919Sxy150489 */
22304919Sxy150489 static s32
e1000_write_flash_data_ich8lan(struct e1000_hw * hw,u32 offset,u8 size,u16 data)22314919Sxy150489 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset,
22324919Sxy150489 u8 size, u16 data)
22334919Sxy150489 {
22344919Sxy150489 union ich8_hws_flash_status hsfsts;
22354919Sxy150489 union ich8_hws_flash_ctrl hsflctl;
22364919Sxy150489 u32 flash_linear_addr;
22374919Sxy150489 u32 flash_data = 0;
22384919Sxy150489 s32 ret_val = -E1000_ERR_NVM;
22394919Sxy150489 u8 count = 0;
22404919Sxy150489
22414919Sxy150489 DEBUGFUNC("e1000_write_ich8_data");
22424919Sxy150489
22434919Sxy150489 if (size < 1 || size > 2 || data > size * 0xff ||
22444919Sxy150489 offset > ICH_FLASH_LINEAR_ADDR_MASK)
22454919Sxy150489 goto out;
22464919Sxy150489
22474919Sxy150489 flash_linear_addr = (ICH_FLASH_LINEAR_ADDR_MASK & offset) +
22484919Sxy150489 hw->nvm.flash_base_addr;
22494919Sxy150489
22504919Sxy150489 do {
22514919Sxy150489 usec_delay(1);
22524919Sxy150489 /* Steps */
22534919Sxy150489 ret_val = e1000_flash_cycle_init_ich8lan(hw);
22544919Sxy150489 if (ret_val != E1000_SUCCESS)
22554919Sxy150489 break;
22564919Sxy150489
22574919Sxy150489 hsflctl.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFCTL);
22584919Sxy150489 /* 0b/1b corresponds to 1 or 2 byte size, respectively. */
22594919Sxy150489 hsflctl.hsf_ctrl.fldbcount = size - 1;
22604919Sxy150489 hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE;
22614919Sxy150489 E1000_WRITE_FLASH_REG16(hw, ICH_FLASH_HSFCTL, hsflctl.regval);
22624919Sxy150489
22634919Sxy150489 E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FADDR, flash_linear_addr);
22644919Sxy150489
22654919Sxy150489 if (size == 1)
22664919Sxy150489 flash_data = (u32)data & 0x00FF;
22674919Sxy150489 else
22684919Sxy150489 flash_data = (u32)data;
22694919Sxy150489
22704919Sxy150489 E1000_WRITE_FLASH_REG(hw, ICH_FLASH_FDATA0, flash_data);
22714919Sxy150489
22724919Sxy150489 /*
22734919Sxy150489 * check if FCERR is set to 1 , if set to 1, clear it and try
22744919Sxy150489 * the whole sequence a few more times else done
22754919Sxy150489 */
22764919Sxy150489 ret_val = e1000_flash_cycle_ich8lan(hw,
22774919Sxy150489 ICH_FLASH_WRITE_COMMAND_TIMEOUT);
22788479SChenlu.Chen@Sun.COM if (ret_val == E1000_SUCCESS)
22794919Sxy150489 break;
22808479SChenlu.Chen@Sun.COM
22818479SChenlu.Chen@Sun.COM /*
22828479SChenlu.Chen@Sun.COM * If we're here, then things are most likely
22838479SChenlu.Chen@Sun.COM * completely hosed, but if the error condition is
22848479SChenlu.Chen@Sun.COM * detected, it won't hurt to give it another
22858479SChenlu.Chen@Sun.COM * try...ICH_FLASH_CYCLE_REPEAT_COUNT times.
22868479SChenlu.Chen@Sun.COM */
22878479SChenlu.Chen@Sun.COM hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
22888479SChenlu.Chen@Sun.COM if (hsfsts.hsf_status.flcerr == 1) {
22898479SChenlu.Chen@Sun.COM /* Repeat for some time before giving up. */
22908479SChenlu.Chen@Sun.COM continue;
22918479SChenlu.Chen@Sun.COM } else if (hsfsts.hsf_status.flcdone == 0) {
22928479SChenlu.Chen@Sun.COM DEBUGOUT("Timeout error - flash cycle "
22938479SChenlu.Chen@Sun.COM "did not complete.");
22948479SChenlu.Chen@Sun.COM break;
22954919Sxy150489 }
22964919Sxy150489 } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT);
22974919Sxy150489
22984919Sxy150489 out:
22994919Sxy150489 return (ret_val);
23004919Sxy150489 }
23014919Sxy150489
23024919Sxy150489 /*
23034919Sxy150489 * e1000_write_flash_byte_ich8lan - Write a single byte to NVM
23044919Sxy150489 * @hw: pointer to the HW structure
23054919Sxy150489 * @offset: The index of the byte to read.
23064919Sxy150489 * @data: The byte to write to the NVM.
23074919Sxy150489 *
23084919Sxy150489 * Writes a single byte to the NVM using the flash access registers.
23094919Sxy150489 */
23104919Sxy150489 static s32
e1000_write_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 data)23114919Sxy150489 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, u8 data)
23124919Sxy150489 {
23134919Sxy150489 u16 word = (u16)data;
23144919Sxy150489
23154919Sxy150489 DEBUGFUNC("e1000_write_flash_byte_ich8lan");
23164919Sxy150489
23174919Sxy150489 return (e1000_write_flash_data_ich8lan(hw, offset, 1, word));
23184919Sxy150489 }
23194919Sxy150489
23204919Sxy150489 /*
23214919Sxy150489 * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM
23224919Sxy150489 * @hw: pointer to the HW structure
23234919Sxy150489 * @offset: The offset of the byte to write.
23244919Sxy150489 * @byte: The byte to write to the NVM.
23254919Sxy150489 *
23264919Sxy150489 * Writes a single byte to the NVM using the flash access registers.
23274919Sxy150489 * Goes through a retry algorithm before giving up.
23284919Sxy150489 */
23294919Sxy150489 static s32
e1000_retry_write_flash_byte_ich8lan(struct e1000_hw * hw,u32 offset,u8 byte)23306735Scc210113 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw,
23316735Scc210113 u32 offset, u8 byte)
23324919Sxy150489 {
23334919Sxy150489 s32 ret_val;
23344919Sxy150489 u16 program_retries;
23354919Sxy150489
23364919Sxy150489 DEBUGFUNC("e1000_retry_write_flash_byte_ich8lan");
23374919Sxy150489
23384919Sxy150489 ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
23394919Sxy150489 if (ret_val == E1000_SUCCESS)
23404919Sxy150489 goto out;
23414919Sxy150489
23424919Sxy150489 for (program_retries = 0; program_retries < 100; program_retries++) {
23434919Sxy150489 DEBUGOUT2("Retrying Byte %2.2X at offset %u\n", byte, offset);
23444919Sxy150489 usec_delay(100);
23454919Sxy150489 ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte);
23464919Sxy150489 if (ret_val == E1000_SUCCESS)
23474919Sxy150489 break;
23484919Sxy150489 }
23494919Sxy150489 if (program_retries == 100) {
23504919Sxy150489 ret_val = -E1000_ERR_NVM;
23514919Sxy150489 goto out;
23524919Sxy150489 }
23534919Sxy150489
23544919Sxy150489 out:
23554919Sxy150489 return (ret_val);
23564919Sxy150489 }
23574919Sxy150489
23584919Sxy150489 /*
23594919Sxy150489 * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM
23604919Sxy150489 * @hw: pointer to the HW structure
23614919Sxy150489 * @bank: 0 for first bank, 1 for second bank, etc.
23624919Sxy150489 *
23634919Sxy150489 * Erases the bank specified. Each bank is a 4k block. Banks are 0 based.
23644919Sxy150489 * bank N is 4096 * N + flash_reg_addr.
23654919Sxy150489 */
23664919Sxy150489 static s32
e1000_erase_flash_bank_ich8lan(struct e1000_hw * hw,u32 bank)23674919Sxy150489 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank)
23684919Sxy150489 {
23694919Sxy150489 struct e1000_nvm_info *nvm = &hw->nvm;
23704919Sxy150489 union ich8_hws_flash_status hsfsts;
23714919Sxy150489 union ich8_hws_flash_ctrl hsflctl;
23724919Sxy150489 u32 flash_linear_addr;
23734919Sxy150489
23744919Sxy150489 /* bank size is in 16bit words - adjust to bytes */
23754919Sxy150489 u32 flash_bank_size = nvm->flash_bank_size * 2;
23764919Sxy150489 s32 ret_val = E1000_SUCCESS;
23774919Sxy150489 s32 count = 0;
23784919Sxy150489 s32 j, iteration, sector_size;
23794919Sxy150489
23804919Sxy150489 DEBUGFUNC("e1000_erase_flash_bank_ich8lan");
23814919Sxy150489
23824919Sxy150489 hsfsts.regval = E1000_READ_FLASH_REG16(hw, ICH_FLASH_HSFSTS);
23834919Sxy150489
23844919Sxy150489 /*
23854919Sxy150489 * Determine HW Sector size: Read BERASE bits of hw flash status
23864919Sxy150489 * register
23874919Sxy150489 * 00: The Hw sector is 256 bytes, hence we need to erase 16
23884919Sxy150489 * consecutive sectors. The start index for the nth Hw sector
23894919Sxy150489 * can be calculated as = bank * 4096 + n * 256
23904919Sxy150489 * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector.
23914919Sxy150489 * The start index for the nth Hw sector can be calculated
23924919Sxy150489 * as = bank * 4096
23934919Sxy150489 * 10: The Hw sector is 8K bytes, nth sector = bank * 8192
23944919Sxy150489 * (ich9 only, otherwise error condition)
23954919Sxy150489 * 11: The Hw sector is 64K bytes, nth sector = bank * 65536
23964919Sxy150489 */
23974919Sxy150489 switch (hsfsts.hsf_status.berasesz) {
23984919Sxy150489 case 0:
23994919Sxy150489 /* Hw sector size 256 */
24004919Sxy150489 sector_size = ICH_FLASH_SEG_SIZE_256;
24014919Sxy150489 iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256;
24024919Sxy150489 break;
24034919Sxy150489 case 1:
24044919Sxy150489 sector_size = ICH_FLASH_SEG_SIZE_4K;
240510680SMin.Xu@Sun.COM iteration = 1;
24064919Sxy150489 break;
24074919Sxy150489 case 2:
24084919Sxy150489 sector_size = ICH_FLASH_SEG_SIZE_8K;
240910680SMin.Xu@Sun.COM iteration = 1;
24104919Sxy150489 break;
24114919Sxy150489 case 3:
24124919Sxy150489 sector_size = ICH_FLASH_SEG_SIZE_64K;
241310680SMin.Xu@Sun.COM iteration = 1;
24144919Sxy150489 break;
24154919Sxy150489 default:
24164919Sxy150489 ret_val = -E1000_ERR_NVM;
24174919Sxy150489 goto out;
24184919Sxy150489 }
24194919Sxy150489
24204919Sxy150489 /* Start with the base address, then add the sector offset. */
24214919Sxy150489 flash_linear_addr = hw->nvm.flash_base_addr;
242210680SMin.Xu@Sun.COM flash_linear_addr += (bank) ? flash_bank_size : 0;
24234919Sxy150489
24244919Sxy150489 for (j = 0; j < iteration; j++) {
24254919Sxy150489 do {
24264919Sxy150489 /* Steps */
24274919Sxy150489 ret_val = e1000_flash_cycle_init_ich8lan(hw);
24284919Sxy150489 if (ret_val)
24294919Sxy150489 goto out;
24304919Sxy150489
24314919Sxy150489 /*
24324919Sxy150489 * Write a value 11 (block Erase) in Flash Cycle field
24334919Sxy150489 * in hw flash control
24344919Sxy150489 */
24354919Sxy150489 hsflctl.regval = E1000_READ_FLASH_REG16(hw,
24364919Sxy150489 ICH_FLASH_HSFCTL);
24374919Sxy150489 hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE;
24384919Sxy150489 E1000_WRITE_FLASH_REG16(hw,
24394919Sxy150489 ICH_FLASH_HSFCTL,
24404919Sxy150489 hsflctl.regval);
24414919Sxy150489
24424919Sxy150489 /*
24434919Sxy150489 * Write the last 24 bits of an index within the block
24444919Sxy150489 * into Flash Linear address field in Flash Address.
24454919Sxy150489 */
24464919Sxy150489 flash_linear_addr += (j * sector_size);
24474919Sxy150489 E1000_WRITE_FLASH_REG(hw,
24484919Sxy150489 ICH_FLASH_FADDR,
24494919Sxy150489 flash_linear_addr);
24504919Sxy150489
24514919Sxy150489 ret_val = e1000_flash_cycle_ich8lan(hw,
24524919Sxy150489 ICH_FLASH_ERASE_COMMAND_TIMEOUT);
24538479SChenlu.Chen@Sun.COM if (ret_val == E1000_SUCCESS)
24544919Sxy150489 break;
24558479SChenlu.Chen@Sun.COM
24568479SChenlu.Chen@Sun.COM /*
24578479SChenlu.Chen@Sun.COM * Check if FCERR is set to 1. If 1,
24588479SChenlu.Chen@Sun.COM * clear it and try the whole sequence
24598479SChenlu.Chen@Sun.COM * a few more times else Done
24608479SChenlu.Chen@Sun.COM */
24618479SChenlu.Chen@Sun.COM hsfsts.regval = E1000_READ_FLASH_REG16(hw,
24628479SChenlu.Chen@Sun.COM ICH_FLASH_HSFSTS);
24638479SChenlu.Chen@Sun.COM if (hsfsts.hsf_status.flcerr == 1)
24648479SChenlu.Chen@Sun.COM /* repeat for some time before giving up */
24658479SChenlu.Chen@Sun.COM continue;
24668479SChenlu.Chen@Sun.COM else if (hsfsts.hsf_status.flcdone == 0)
24678479SChenlu.Chen@Sun.COM goto out;
24684919Sxy150489 } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT);
24694919Sxy150489 }
24704919Sxy150489
24714919Sxy150489 out:
24724919Sxy150489 return (ret_val);
24734919Sxy150489 }
24744919Sxy150489
24754919Sxy150489 /*
24764919Sxy150489 * e1000_valid_led_default_ich8lan - Set the default LED settings
24774919Sxy150489 * @hw: pointer to the HW structure
24784919Sxy150489 * @data: Pointer to the LED settings
24794919Sxy150489 *
24804919Sxy150489 * Reads the LED default settings from the NVM to data. If the NVM LED
24814919Sxy150489 * settings is all 0's or F's, set the LED default to a valid LED default
24824919Sxy150489 * setting.
24834919Sxy150489 */
24844919Sxy150489 static s32
e1000_valid_led_default_ich8lan(struct e1000_hw * hw,u16 * data)24856735Scc210113 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data)
24864919Sxy150489 {
24874919Sxy150489 s32 ret_val;
24884919Sxy150489
24894919Sxy150489 DEBUGFUNC("e1000_valid_led_default_ich8lan");
24904919Sxy150489
24916735Scc210113 ret_val = hw->nvm.ops.read(hw, NVM_ID_LED_SETTINGS, 1, data);
24924919Sxy150489 if (ret_val) {
24934919Sxy150489 DEBUGOUT("NVM Read Error\n");
24944919Sxy150489 goto out;
24954919Sxy150489 }
24964919Sxy150489
24974919Sxy150489 if (*data == ID_LED_RESERVED_0000 ||
24984919Sxy150489 *data == ID_LED_RESERVED_FFFF)
24994919Sxy150489 *data = ID_LED_DEFAULT_ICH8LAN;
25004919Sxy150489
25014919Sxy150489 out:
25024919Sxy150489 return (ret_val);
25034919Sxy150489 }
25044919Sxy150489
25054919Sxy150489 /*
250610680SMin.Xu@Sun.COM * e1000_id_led_init_pchlan - store LED configurations
250710680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
250810680SMin.Xu@Sun.COM *
250910680SMin.Xu@Sun.COM * PCH does not control LEDs via the LEDCTL register, rather it uses
251010680SMin.Xu@Sun.COM * the PHY LED configuration register.
251110680SMin.Xu@Sun.COM *
251210680SMin.Xu@Sun.COM * PCH also does not have an "always on" or "always off" mode which
251310680SMin.Xu@Sun.COM * complicates the ID feature. Instead of using the "on" mode to indicate
251410680SMin.Xu@Sun.COM * in ledctl_mode2 the LEDs to use for ID (see e1000_id_led_init_generic()),
251510680SMin.Xu@Sun.COM * use "link_up" mode. The LEDs will still ID on request if there is no
251610680SMin.Xu@Sun.COM * link based on logic in e1000_led_[on|off]_pchlan().
251710680SMin.Xu@Sun.COM */
251810680SMin.Xu@Sun.COM static s32
e1000_id_led_init_pchlan(struct e1000_hw * hw)251910680SMin.Xu@Sun.COM e1000_id_led_init_pchlan(struct e1000_hw *hw)
252010680SMin.Xu@Sun.COM {
252110680SMin.Xu@Sun.COM struct e1000_mac_info *mac = &hw->mac;
252210680SMin.Xu@Sun.COM s32 ret_val;
252310680SMin.Xu@Sun.COM const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP;
252410680SMin.Xu@Sun.COM const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT;
252510680SMin.Xu@Sun.COM u16 data, i, temp, shift;
252610680SMin.Xu@Sun.COM
252710680SMin.Xu@Sun.COM DEBUGFUNC("e1000_id_led_init_pchlan");
252810680SMin.Xu@Sun.COM
252910680SMin.Xu@Sun.COM /* Get default ID LED modes */
253010680SMin.Xu@Sun.COM ret_val = hw->nvm.ops.valid_led_default(hw, &data);
253110680SMin.Xu@Sun.COM if (ret_val)
253210680SMin.Xu@Sun.COM goto out;
253310680SMin.Xu@Sun.COM
253410680SMin.Xu@Sun.COM mac->ledctl_default = E1000_READ_REG(hw, E1000_LEDCTL);
253510680SMin.Xu@Sun.COM mac->ledctl_mode1 = mac->ledctl_default;
253610680SMin.Xu@Sun.COM mac->ledctl_mode2 = mac->ledctl_default;
253710680SMin.Xu@Sun.COM
253810680SMin.Xu@Sun.COM for (i = 0; i < 4; i++) {
253910680SMin.Xu@Sun.COM temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK;
254010680SMin.Xu@Sun.COM shift = (i * 5);
254110680SMin.Xu@Sun.COM switch (temp) {
254210680SMin.Xu@Sun.COM case ID_LED_ON1_DEF2:
254310680SMin.Xu@Sun.COM case ID_LED_ON1_ON2:
254410680SMin.Xu@Sun.COM case ID_LED_ON1_OFF2:
254510680SMin.Xu@Sun.COM mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
254610680SMin.Xu@Sun.COM mac->ledctl_mode1 |= (ledctl_on << shift);
254710680SMin.Xu@Sun.COM break;
254810680SMin.Xu@Sun.COM case ID_LED_OFF1_DEF2:
254910680SMin.Xu@Sun.COM case ID_LED_OFF1_ON2:
255010680SMin.Xu@Sun.COM case ID_LED_OFF1_OFF2:
255110680SMin.Xu@Sun.COM mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift);
255210680SMin.Xu@Sun.COM mac->ledctl_mode1 |= (ledctl_off << shift);
255310680SMin.Xu@Sun.COM break;
255410680SMin.Xu@Sun.COM default:
255510680SMin.Xu@Sun.COM /* Do nothing */
255610680SMin.Xu@Sun.COM break;
255710680SMin.Xu@Sun.COM }
255810680SMin.Xu@Sun.COM switch (temp) {
255910680SMin.Xu@Sun.COM case ID_LED_DEF1_ON2:
256010680SMin.Xu@Sun.COM case ID_LED_ON1_ON2:
256110680SMin.Xu@Sun.COM case ID_LED_OFF1_ON2:
256210680SMin.Xu@Sun.COM mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
256310680SMin.Xu@Sun.COM mac->ledctl_mode2 |= (ledctl_on << shift);
256410680SMin.Xu@Sun.COM break;
256510680SMin.Xu@Sun.COM case ID_LED_DEF1_OFF2:
256610680SMin.Xu@Sun.COM case ID_LED_ON1_OFF2:
256710680SMin.Xu@Sun.COM case ID_LED_OFF1_OFF2:
256810680SMin.Xu@Sun.COM mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift);
256910680SMin.Xu@Sun.COM mac->ledctl_mode2 |= (ledctl_off << shift);
257010680SMin.Xu@Sun.COM break;
257110680SMin.Xu@Sun.COM default:
257210680SMin.Xu@Sun.COM /* Do nothing */
257310680SMin.Xu@Sun.COM break;
257410680SMin.Xu@Sun.COM }
257510680SMin.Xu@Sun.COM }
257610680SMin.Xu@Sun.COM
257710680SMin.Xu@Sun.COM out:
257810680SMin.Xu@Sun.COM return (ret_val);
257910680SMin.Xu@Sun.COM }
258010680SMin.Xu@Sun.COM
258110680SMin.Xu@Sun.COM /*
25824919Sxy150489 * e1000_get_bus_info_ich8lan - Get/Set the bus type and width
25834919Sxy150489 * @hw: pointer to the HW structure
25844919Sxy150489 *
25854919Sxy150489 * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability
25864919Sxy150489 * register, so the the bus width is hard coded.
25874919Sxy150489 */
25884919Sxy150489 static s32
e1000_get_bus_info_ich8lan(struct e1000_hw * hw)25894919Sxy150489 e1000_get_bus_info_ich8lan(struct e1000_hw *hw)
25904919Sxy150489 {
25914919Sxy150489 struct e1000_bus_info *bus = &hw->bus;
25924919Sxy150489 s32 ret_val;
25934919Sxy150489
25944919Sxy150489 DEBUGFUNC("e1000_get_bus_info_ich8lan");
25954919Sxy150489
25964919Sxy150489 ret_val = e1000_get_bus_info_pcie_generic(hw);
25974919Sxy150489
25984919Sxy150489 /*
25994919Sxy150489 * ICH devices are "PCI Express"-ish. They have a configuration
26004919Sxy150489 * space, but do not contain PCI Express Capability registers, so bus
26014919Sxy150489 * width must be hardcoded.
26024919Sxy150489 */
26034919Sxy150489 if (bus->width == e1000_bus_width_unknown)
26044919Sxy150489 bus->width = e1000_bus_width_pcie_x1;
26054919Sxy150489
26064919Sxy150489 return (ret_val);
26074919Sxy150489 }
26084919Sxy150489
26094919Sxy150489 /*
26104919Sxy150489 * e1000_reset_hw_ich8lan - Reset the hardware
26114919Sxy150489 * @hw: pointer to the HW structure
26124919Sxy150489 *
26134919Sxy150489 * Does a full reset of the hardware which includes a reset of the PHY and
26144919Sxy150489 * MAC.
26154919Sxy150489 */
26164919Sxy150489 static s32
e1000_reset_hw_ich8lan(struct e1000_hw * hw)26174919Sxy150489 e1000_reset_hw_ich8lan(struct e1000_hw *hw)
26184919Sxy150489 {
261911020SMin.Xu@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
262011020SMin.Xu@Sun.COM u16 reg;
26217426SChenliang.Xu@Sun.COM u32 ctrl, kab;
26224919Sxy150489 s32 ret_val;
26234919Sxy150489
26244919Sxy150489 DEBUGFUNC("e1000_reset_hw_ich8lan");
26254919Sxy150489
26264919Sxy150489 /*
26274919Sxy150489 * Prevent the PCI-E bus from sticking if there is no TLP connection
26284919Sxy150489 * on the last TLP read/write transaction when MAC is reset.
26294919Sxy150489 */
26304919Sxy150489 ret_val = e1000_disable_pcie_master_generic(hw);
2631*11143SGuoqing.Zhu@Sun.COM if (ret_val) {
2632*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
26334919Sxy150489 DEBUGOUT("PCI-E Master disable polling has failed.\n");
2634*11143SGuoqing.Zhu@Sun.COM }
26354919Sxy150489
26364919Sxy150489 DEBUGOUT("Masking off all interrupts\n");
26374919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
26384919Sxy150489
26394919Sxy150489 /*
26404919Sxy150489 * Disable the Transmit and Receive units. Then delay to allow any
26414919Sxy150489 * pending transactions to complete before we hit the MAC with the
26424919Sxy150489 * global reset.
26434919Sxy150489 */
26444919Sxy150489 E1000_WRITE_REG(hw, E1000_RCTL, 0);
26454919Sxy150489 E1000_WRITE_REG(hw, E1000_TCTL, E1000_TCTL_PSP);
26464919Sxy150489 E1000_WRITE_FLUSH(hw);
26474919Sxy150489
26484919Sxy150489 msec_delay(10);
26494919Sxy150489
26504919Sxy150489 /* Workaround for ICH8 bit corruption issue in FIFO memory */
26514919Sxy150489 if (hw->mac.type == e1000_ich8lan) {
26524919Sxy150489 /* Set Tx and Rx buffer allocation to 8k apiece. */
26534919Sxy150489 E1000_WRITE_REG(hw, E1000_PBA, E1000_PBA_8K);
26544919Sxy150489 /* Set Packet Buffer Size to 16k. */
26554919Sxy150489 E1000_WRITE_REG(hw, E1000_PBS, E1000_PBS_16K);
26564919Sxy150489 }
26576735Scc210113
265811020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan) {
265911020SMin.Xu@Sun.COM /* Save the NVM K1 bit setting */
266011020SMin.Xu@Sun.COM ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, ®);
266111020SMin.Xu@Sun.COM if (ret_val)
266211020SMin.Xu@Sun.COM return (ret_val);
266311020SMin.Xu@Sun.COM
266411020SMin.Xu@Sun.COM if (reg & E1000_NVM_K1_ENABLE)
266511020SMin.Xu@Sun.COM dev_spec->nvm_k1_enabled = true;
266611020SMin.Xu@Sun.COM else
266711020SMin.Xu@Sun.COM dev_spec->nvm_k1_enabled = false;
266811020SMin.Xu@Sun.COM }
266911020SMin.Xu@Sun.COM
26704919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
26714919Sxy150489
26726735Scc210113 if (!hw->phy.ops.check_reset_block(hw) && !hw->phy.reset_disable) {
267310680SMin.Xu@Sun.COM /* Clear PHY Reset Asserted bit */
267410680SMin.Xu@Sun.COM if (hw->mac.type >= e1000_pchlan) {
267510680SMin.Xu@Sun.COM u32 status = E1000_READ_REG(hw, E1000_STATUS);
267610680SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_STATUS, status &
267710680SMin.Xu@Sun.COM ~E1000_STATUS_PHYRA);
267810680SMin.Xu@Sun.COM }
267910680SMin.Xu@Sun.COM
26804919Sxy150489 /*
26814919Sxy150489 * PHY HW reset requires MAC CORE reset at the same time to
26824919Sxy150489 * make sure the interface between MAC and the external PHY is
26834919Sxy150489 * reset.
26844919Sxy150489 */
26854919Sxy150489 ctrl |= E1000_CTRL_PHY_RST;
26864919Sxy150489 }
26874919Sxy150489
26884919Sxy150489 ret_val = e1000_acquire_swflag_ich8lan(hw);
268910680SMin.Xu@Sun.COM
269010680SMin.Xu@Sun.COM DEBUGOUT("Issuing a global reset to ich8lan\n");
26914919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, (ctrl | E1000_CTRL_RST));
26924919Sxy150489 msec_delay(20);
26934919Sxy150489
269410680SMin.Xu@Sun.COM if (!ret_val)
269510680SMin.Xu@Sun.COM e1000_release_swflag_ich8lan(hw);
269610680SMin.Xu@Sun.COM
269710680SMin.Xu@Sun.COM if (ctrl & E1000_CTRL_PHY_RST)
269810680SMin.Xu@Sun.COM ret_val = hw->phy.ops.get_cfg_done(hw);
269910680SMin.Xu@Sun.COM
270010680SMin.Xu@Sun.COM if (hw->mac.type >= e1000_ich10lan) {
270110680SMin.Xu@Sun.COM e1000_lan_init_done_ich8lan(hw);
270210680SMin.Xu@Sun.COM } else {
270310680SMin.Xu@Sun.COM ret_val = e1000_get_auto_rd_done_generic(hw);
270410680SMin.Xu@Sun.COM if (ret_val) {
2705*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
270610680SMin.Xu@Sun.COM /*
270710680SMin.Xu@Sun.COM * When auto config read does not complete, do not
270810680SMin.Xu@Sun.COM * return with an error. This can happen in situations
270910680SMin.Xu@Sun.COM * where there is no eeprom and prevents getting link.
271010680SMin.Xu@Sun.COM */
271110680SMin.Xu@Sun.COM DEBUGOUT("Auto Read Done did not complete\n");
271210680SMin.Xu@Sun.COM }
27134919Sxy150489 }
27146735Scc210113
271511020SMin.Xu@Sun.COM /* Dummy read to clear the phy wakeup bit after lcd reset */
271611020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
271711020SMin.Xu@Sun.COM hw->phy.ops.read_reg(hw, BM_WUC, ®);
271811020SMin.Xu@Sun.COM
271911020SMin.Xu@Sun.COM ret_val = e1000_sw_lcd_config_ich8lan(hw);
272011020SMin.Xu@Sun.COM if (ret_val)
272111020SMin.Xu@Sun.COM goto out;
272211020SMin.Xu@Sun.COM
272311020SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan) {
272411020SMin.Xu@Sun.COM ret_val = e1000_oem_bits_config_ich8lan(hw, true);
272511020SMin.Xu@Sun.COM if (ret_val)
272611020SMin.Xu@Sun.COM goto out;
272711020SMin.Xu@Sun.COM }
272811020SMin.Xu@Sun.COM
272910680SMin.Xu@Sun.COM /*
273010680SMin.Xu@Sun.COM * For PCH, this write will make sure that any noise
273110680SMin.Xu@Sun.COM * will be detected as a CRC error and be dropped rather than show up
273210680SMin.Xu@Sun.COM * as a bad packet to the DMA engine.
273310680SMin.Xu@Sun.COM */
273410680SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
273510680SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_CRC_OFFSET, 0x65656565);
273610680SMin.Xu@Sun.COM
27374919Sxy150489 E1000_WRITE_REG(hw, E1000_IMC, 0xffffffff);
27387426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ICR);
27394919Sxy150489
27404919Sxy150489 kab = E1000_READ_REG(hw, E1000_KABGTXD);
27414919Sxy150489 kab |= E1000_KABGTXD_BGSQLBIAS;
27424919Sxy150489 E1000_WRITE_REG(hw, E1000_KABGTXD, kab);
27434919Sxy150489
274410680SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
274510680SMin.Xu@Sun.COM ret_val = e1000_hv_phy_workarounds_ich8lan(hw);
274610680SMin.Xu@Sun.COM
274710680SMin.Xu@Sun.COM if (ret_val)
274810680SMin.Xu@Sun.COM goto out;
274910680SMin.Xu@Sun.COM
275010680SMin.Xu@Sun.COM if (hw->device_id == E1000_DEV_ID_ICH10_HANKSVILLE)
275110680SMin.Xu@Sun.COM ret_val = e1000_hv_phy_tuning_workaround_ich8lan(hw);
275210680SMin.Xu@Sun.COM
275310680SMin.Xu@Sun.COM out:
27544919Sxy150489 return (ret_val);
27554919Sxy150489 }
27564919Sxy150489
27574919Sxy150489 /*
27584919Sxy150489 * e1000_init_hw_ich8lan - Initialize the hardware
27594919Sxy150489 * @hw: pointer to the HW structure
27604919Sxy150489 *
27614919Sxy150489 * Prepares the hardware for transmit and receive by doing the following:
276210680SMin.Xu@Sun.COM * - initialize hardware bits
276310680SMin.Xu@Sun.COM * - initialize LED identification
276410680SMin.Xu@Sun.COM * - setup receive address registers
276510680SMin.Xu@Sun.COM * - setup flow control
276610680SMin.Xu@Sun.COM * - setup transmit descriptors
276710680SMin.Xu@Sun.COM * - clear statistics
27684919Sxy150489 */
27694919Sxy150489 static s32
e1000_init_hw_ich8lan(struct e1000_hw * hw)27704919Sxy150489 e1000_init_hw_ich8lan(struct e1000_hw *hw)
27714919Sxy150489 {
27724919Sxy150489 struct e1000_mac_info *mac = &hw->mac;
27734919Sxy150489 u32 ctrl_ext, txdctl, snoop;
27744919Sxy150489 s32 ret_val;
27754919Sxy150489 u16 i;
27764919Sxy150489
27774919Sxy150489 DEBUGFUNC("e1000_init_hw_ich8lan");
27784919Sxy150489
27794919Sxy150489 e1000_initialize_hw_bits_ich8lan(hw);
27804919Sxy150489
27814919Sxy150489 /* Initialize identification LED */
278210680SMin.Xu@Sun.COM ret_val = mac->ops.id_led_init(hw);
2783*11143SGuoqing.Zhu@Sun.COM if (ret_val) {
2784*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
278510680SMin.Xu@Sun.COM /* This is not fatal and we should not stop init due to this */
27864919Sxy150489 DEBUGOUT("Error initializing identification LED\n");
2787*11143SGuoqing.Zhu@Sun.COM }
27884919Sxy150489
27894919Sxy150489 /* Setup the receive address. */
27904919Sxy150489 e1000_init_rx_addrs_generic(hw, mac->rar_entry_count);
27914919Sxy150489
27924919Sxy150489 /* Zero out the Multicast HASH table */
27934919Sxy150489 DEBUGOUT("Zeroing the MTA\n");
27944919Sxy150489 for (i = 0; i < mac->mta_reg_count; i++)
27954919Sxy150489 E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0);
27964919Sxy150489
279710680SMin.Xu@Sun.COM /*
279810680SMin.Xu@Sun.COM * The 82578 Rx buffer will stall if wakeup is enabled in host and
279910680SMin.Xu@Sun.COM * the ME. Reading the BM_WUC register will clear the host wakeup bit.
280010680SMin.Xu@Sun.COM * Reset the phy after disabling host wakeup to reset the Rx buffer.
280110680SMin.Xu@Sun.COM */
280210680SMin.Xu@Sun.COM if (hw->phy.type == e1000_phy_82578) {
280310680SMin.Xu@Sun.COM hw->phy.ops.read_reg(hw, BM_WUC, &i);
280410680SMin.Xu@Sun.COM ret_val = e1000_phy_hw_reset_ich8lan(hw);
280510680SMin.Xu@Sun.COM if (ret_val)
280610680SMin.Xu@Sun.COM return (ret_val);
280710680SMin.Xu@Sun.COM }
280810680SMin.Xu@Sun.COM
28094919Sxy150489 /* Setup link and flow control */
28106735Scc210113 ret_val = mac->ops.setup_link(hw);
28114919Sxy150489
28124919Sxy150489 /* Set the transmit descriptor write-back policy for both queues */
28136735Scc210113 txdctl = E1000_READ_REG(hw, E1000_TXDCTL(0));
28144919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
28154919Sxy150489 E1000_TXDCTL_FULL_TX_DESC_WB;
28164919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
28174919Sxy150489 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
28186735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(0), txdctl);
28196735Scc210113 txdctl = E1000_READ_REG(hw, E1000_TXDCTL(1));
28204919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_WTHRESH) |
28214919Sxy150489 E1000_TXDCTL_FULL_TX_DESC_WB;
28224919Sxy150489 txdctl = (txdctl & ~E1000_TXDCTL_PTHRESH) |
28234919Sxy150489 E1000_TXDCTL_MAX_TX_DESC_PREFETCH;
28246735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(1), txdctl);
28254919Sxy150489
28264919Sxy150489 /*
28274919Sxy150489 * ICH8 has opposite polarity of no_snoop bits. By default, we should
28284919Sxy150489 * use snoop behavior.
28294919Sxy150489 */
28304919Sxy150489 if (mac->type == e1000_ich8lan)
28314919Sxy150489 snoop = PCIE_ICH8_SNOOP_ALL;
28324919Sxy150489 else
28334919Sxy150489 snoop = (u32)~(PCIE_NO_SNOOP_ALL);
28344919Sxy150489 e1000_set_pcie_no_snoop_generic(hw, snoop);
28354919Sxy150489
28364919Sxy150489 ctrl_ext = E1000_READ_REG(hw, E1000_CTRL_EXT);
28374919Sxy150489 ctrl_ext |= E1000_CTRL_EXT_RO_DIS;
28384919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, ctrl_ext);
28394919Sxy150489
28404919Sxy150489 /*
28414919Sxy150489 * Clear all of the statistics registers (clear on read). It is
28424919Sxy150489 * important that we do this after we have tried to establish link
28434919Sxy150489 * because the symbol error count will increment wildly if there
28444919Sxy150489 * is no link.
28454919Sxy150489 */
28464919Sxy150489 e1000_clear_hw_cntrs_ich8lan(hw);
28474919Sxy150489
28484919Sxy150489 return (ret_val);
28494919Sxy150489 }
28504919Sxy150489
28514919Sxy150489 /*
28524919Sxy150489 * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits
28534919Sxy150489 * @hw: pointer to the HW structure
28544919Sxy150489 *
28554919Sxy150489 * Sets/Clears required hardware bits necessary for correctly setting up the
28564919Sxy150489 * hardware for transmit and receive.
28574919Sxy150489 */
28584919Sxy150489 static void
e1000_initialize_hw_bits_ich8lan(struct e1000_hw * hw)28594919Sxy150489 e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw)
28604919Sxy150489 {
28614919Sxy150489 u32 reg;
28624919Sxy150489
28634919Sxy150489 DEBUGFUNC("e1000_initialize_hw_bits_ich8lan");
28644919Sxy150489
28654919Sxy150489 /* Extended Device Control */
28664919Sxy150489 reg = E1000_READ_REG(hw, E1000_CTRL_EXT);
28674919Sxy150489 reg |= (1 << 22);
286810680SMin.Xu@Sun.COM /* Enable PHY low-power state when MAC is at D3 w/o WoL */
286910680SMin.Xu@Sun.COM if (hw->mac.type >= e1000_pchlan)
287010680SMin.Xu@Sun.COM reg |= E1000_CTRL_EXT_PHYPDEN;
28714919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL_EXT, reg);
28724919Sxy150489
28734919Sxy150489 /* Transmit Descriptor Control 0 */
28746735Scc210113 reg = E1000_READ_REG(hw, E1000_TXDCTL(0));
28754919Sxy150489 reg |= (1 << 22);
28766735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(0), reg);
28774919Sxy150489
28784919Sxy150489 /* Transmit Descriptor Control 1 */
28796735Scc210113 reg = E1000_READ_REG(hw, E1000_TXDCTL(1));
28804919Sxy150489 reg |= (1 << 22);
28816735Scc210113 E1000_WRITE_REG(hw, E1000_TXDCTL(1), reg);
28824919Sxy150489
28834919Sxy150489 /* Transmit Arbitration Control 0 */
28846735Scc210113 reg = E1000_READ_REG(hw, E1000_TARC(0));
28854919Sxy150489 if (hw->mac.type == e1000_ich8lan)
28864919Sxy150489 reg |= (1 << 28) | (1 << 29);
28874919Sxy150489 reg |= (1 << 23) | (1 << 24) | (1 << 26) | (1 << 27);
28886735Scc210113 E1000_WRITE_REG(hw, E1000_TARC(0), reg);
28894919Sxy150489
28904919Sxy150489 /* Transmit Arbitration Control 1 */
28916735Scc210113 reg = E1000_READ_REG(hw, E1000_TARC(1));
28924919Sxy150489 if (E1000_READ_REG(hw, E1000_TCTL) & E1000_TCTL_MULR)
28934919Sxy150489 reg &= ~(1 << 28);
28944919Sxy150489 else
28954919Sxy150489 reg |= (1 << 28);
28964919Sxy150489 reg |= (1 << 24) | (1 << 26) | (1 << 30);
28976735Scc210113 E1000_WRITE_REG(hw, E1000_TARC(1), reg);
28984919Sxy150489
28994919Sxy150489 /* Device Status */
29004919Sxy150489 if (hw->mac.type == e1000_ich8lan) {
29014919Sxy150489 reg = E1000_READ_REG(hw, E1000_STATUS);
29024919Sxy150489 reg &= ~((u32)1 << 31);
29034919Sxy150489 E1000_WRITE_REG(hw, E1000_STATUS, reg);
29044919Sxy150489 }
29054919Sxy150489 }
29064919Sxy150489
29074919Sxy150489 /*
29084919Sxy150489 * e1000_setup_link_ich8lan - Setup flow control and link settings
29094919Sxy150489 * @hw: pointer to the HW structure
29104919Sxy150489 *
29114919Sxy150489 * Determines which flow control settings to use, then configures flow
29124919Sxy150489 * control. Calls the appropriate media-specific link configuration
29134919Sxy150489 * function. Assuming the adapter has a valid link partner, a valid link
29144919Sxy150489 * should be established. Assumes the hardware has previously been reset
29154919Sxy150489 * and the transmitter and receiver are not enabled.
29164919Sxy150489 */
29174919Sxy150489 static s32
e1000_setup_link_ich8lan(struct e1000_hw * hw)29184919Sxy150489 e1000_setup_link_ich8lan(struct e1000_hw *hw)
29194919Sxy150489 {
29204919Sxy150489 s32 ret_val = E1000_SUCCESS;
29214919Sxy150489
29224919Sxy150489 DEBUGFUNC("e1000_setup_link_ich8lan");
29234919Sxy150489
29246735Scc210113 if (hw->phy.ops.check_reset_block(hw))
29254919Sxy150489 goto out;
29264919Sxy150489
29274919Sxy150489 /*
29284919Sxy150489 * ICH parts do not have a word in the NVM to determine the default
29294919Sxy150489 * flow control setting, so we explicitly set it to full.
29304919Sxy150489 */
29318539SChenlu.Chen@Sun.COM if (hw->fc.requested_mode == e1000_fc_default)
29328539SChenlu.Chen@Sun.COM hw->fc.requested_mode = e1000_fc_full;
29334919Sxy150489
29348479SChenlu.Chen@Sun.COM /*
29358479SChenlu.Chen@Sun.COM * Save off the requested flow control mode for use later. Depending
29368479SChenlu.Chen@Sun.COM * on the link partner's capabilities, we may or may not use this mode.
29378479SChenlu.Chen@Sun.COM */
29388539SChenlu.Chen@Sun.COM hw->fc.current_mode = hw->fc.requested_mode;
29398479SChenlu.Chen@Sun.COM DEBUGOUT1("After fix-ups FlowControl is now = %x\n",
29408479SChenlu.Chen@Sun.COM hw->fc.current_mode);
29414919Sxy150489
29424919Sxy150489 /* Continue to configure the copper link. */
29436735Scc210113 ret_val = hw->mac.ops.setup_physical_interface(hw);
29444919Sxy150489 if (ret_val)
29454919Sxy150489 goto out;
29464919Sxy150489
29476735Scc210113 E1000_WRITE_REG(hw, E1000_FCTTV, hw->fc.pause_time);
294810680SMin.Xu@Sun.COM if ((hw->phy.type == e1000_phy_82578) ||
294910680SMin.Xu@Sun.COM (hw->phy.type == e1000_phy_82577)) {
295010680SMin.Xu@Sun.COM ret_val = hw->phy.ops.write_reg(hw,
295110680SMin.Xu@Sun.COM PHY_REG(BM_PORT_CTRL_PAGE, 27),
295210680SMin.Xu@Sun.COM hw->fc.pause_time);
295310680SMin.Xu@Sun.COM if (ret_val)
295410680SMin.Xu@Sun.COM goto out;
295510680SMin.Xu@Sun.COM }
29564919Sxy150489
29574919Sxy150489 ret_val = e1000_set_fc_watermarks_generic(hw);
29584919Sxy150489
29594919Sxy150489 out:
29604919Sxy150489 return (ret_val);
29614919Sxy150489 }
29624919Sxy150489
29634919Sxy150489 /*
29644919Sxy150489 * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface
29654919Sxy150489 * @hw: pointer to the HW structure
29664919Sxy150489 *
29674919Sxy150489 * Configures the kumeran interface to the PHY to wait the appropriate time
29684919Sxy150489 * when polling the PHY, then call the generic setup_copper_link to finish
29694919Sxy150489 * configuring the copper link.
29704919Sxy150489 */
29714919Sxy150489 static s32
e1000_setup_copper_link_ich8lan(struct e1000_hw * hw)29724919Sxy150489 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw)
29734919Sxy150489 {
29744919Sxy150489 u32 ctrl;
29754919Sxy150489 s32 ret_val;
29764919Sxy150489 u16 reg_data;
29774919Sxy150489
29784919Sxy150489 DEBUGFUNC("e1000_setup_copper_link_ich8lan");
29794919Sxy150489
29804919Sxy150489 ctrl = E1000_READ_REG(hw, E1000_CTRL);
29814919Sxy150489 ctrl |= E1000_CTRL_SLU;
29824919Sxy150489 ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX);
29834919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, ctrl);
29844919Sxy150489
29854919Sxy150489 /*
29864919Sxy150489 * Set the mac to wait the maximum time between each iteration and
29874919Sxy150489 * increase the max iterations when polling the phy; this fixes
29884919Sxy150489 * erroneous timeouts at 10Mbps.
29894919Sxy150489 */
299010680SMin.Xu@Sun.COM ret_val = e1000_write_kmrn_reg_generic(hw,
299110680SMin.Xu@Sun.COM E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF);
29924919Sxy150489 if (ret_val)
29934919Sxy150489 goto out;
299410680SMin.Xu@Sun.COM ret_val = e1000_read_kmrn_reg_generic(hw,
299510680SMin.Xu@Sun.COM E1000_KMRNCTRLSTA_INBAND_PARAM, ®_data);
29964919Sxy150489 if (ret_val)
29974919Sxy150489 goto out;
29984919Sxy150489 reg_data |= 0x3F;
299910680SMin.Xu@Sun.COM ret_val = e1000_write_kmrn_reg_generic(hw,
300010680SMin.Xu@Sun.COM E1000_KMRNCTRLSTA_INBAND_PARAM, reg_data);
30014919Sxy150489 if (ret_val)
30024919Sxy150489 goto out;
30034919Sxy150489
300410680SMin.Xu@Sun.COM switch (hw->phy.type) {
300510680SMin.Xu@Sun.COM case e1000_phy_igp_3:
30064919Sxy150489 ret_val = e1000_copper_link_setup_igp(hw);
30074919Sxy150489 if (ret_val)
30084919Sxy150489 goto out;
300910680SMin.Xu@Sun.COM break;
301010680SMin.Xu@Sun.COM case e1000_phy_bm:
301110680SMin.Xu@Sun.COM case e1000_phy_82578:
30124919Sxy150489 ret_val = e1000_copper_link_setup_m88(hw);
30134919Sxy150489 if (ret_val)
30144919Sxy150489 goto out;
301510680SMin.Xu@Sun.COM break;
301610680SMin.Xu@Sun.COM case e1000_phy_82577:
301710680SMin.Xu@Sun.COM ret_val = e1000_copper_link_setup_82577(hw);
301810680SMin.Xu@Sun.COM if (ret_val)
301910680SMin.Xu@Sun.COM goto out;
302010680SMin.Xu@Sun.COM break;
302110680SMin.Xu@Sun.COM case e1000_phy_ife:
30226735Scc210113 ret_val = hw->phy.ops.read_reg(hw, IFE_PHY_MDIX_CONTROL,
30236735Scc210113 ®_data);
30246735Scc210113 if (ret_val)
30256735Scc210113 goto out;
30266735Scc210113
30276735Scc210113 reg_data &= ~IFE_PMC_AUTO_MDIX;
30286735Scc210113
30296735Scc210113 switch (hw->phy.mdix) {
30306735Scc210113 case 1:
30316735Scc210113 reg_data &= ~IFE_PMC_FORCE_MDIX;
30326735Scc210113 break;
30336735Scc210113 case 2:
30346735Scc210113 reg_data |= IFE_PMC_FORCE_MDIX;
30356735Scc210113 break;
30366735Scc210113 case 0:
30376735Scc210113 default:
30386735Scc210113 reg_data |= IFE_PMC_AUTO_MDIX;
30396735Scc210113 break;
30406735Scc210113 }
30416735Scc210113 ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_MDIX_CONTROL,
30426735Scc210113 reg_data);
30436735Scc210113 if (ret_val)
30446735Scc210113 goto out;
304510680SMin.Xu@Sun.COM break;
304610680SMin.Xu@Sun.COM default:
304710680SMin.Xu@Sun.COM break;
30486735Scc210113 }
30494919Sxy150489 ret_val = e1000_setup_copper_link_generic(hw);
30504919Sxy150489
30514919Sxy150489 out:
30524919Sxy150489 return (ret_val);
30534919Sxy150489 }
30544919Sxy150489
30554919Sxy150489 /*
30564919Sxy150489 * e1000_get_link_up_info_ich8lan - Get current link speed and duplex
30574919Sxy150489 * @hw: pointer to the HW structure
30584919Sxy150489 * @speed: pointer to store current link speed
30594919Sxy150489 * @duplex: pointer to store the current link duplex
30604919Sxy150489 *
30616735Scc210113 * Calls the generic get_speed_and_duplex to retrieve the current link
30624919Sxy150489 * information and then calls the Kumeran lock loss workaround for links at
30634919Sxy150489 * gigabit speeds.
30644919Sxy150489 */
30654919Sxy150489 static s32
e1000_get_link_up_info_ich8lan(struct e1000_hw * hw,u16 * speed,u16 * duplex)30664919Sxy150489 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, u16 *duplex)
30674919Sxy150489 {
30684919Sxy150489 s32 ret_val;
30694919Sxy150489
30704919Sxy150489 DEBUGFUNC("e1000_get_link_up_info_ich8lan");
30714919Sxy150489
30724919Sxy150489 ret_val = e1000_get_speed_and_duplex_copper_generic(hw, speed, duplex);
30734919Sxy150489 if (ret_val)
30744919Sxy150489 goto out;
30754919Sxy150489
30764919Sxy150489 if ((hw->mac.type == e1000_ich8lan) &&
30774919Sxy150489 (hw->phy.type == e1000_phy_igp_3) &&
30784919Sxy150489 (*speed == SPEED_1000)) {
30794919Sxy150489 ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw);
30804919Sxy150489 }
30814919Sxy150489
30824919Sxy150489 out:
30834919Sxy150489 return (ret_val);
30844919Sxy150489 }
30854919Sxy150489
30864919Sxy150489 /*
30874919Sxy150489 * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround
30884919Sxy150489 * @hw: pointer to the HW structure
30894919Sxy150489 *
30904919Sxy150489 * Work-around for 82566 Kumeran PCS lock loss:
30914919Sxy150489 * On link status change (i.e. PCI reset, speed change) and link is up and
30924919Sxy150489 * speed is gigabit-
309310680SMin.Xu@Sun.COM * 0) if workaround is optionally disabled do nothing
309410680SMin.Xu@Sun.COM * 1) wait 1ms for Kumeran link to come up
309510680SMin.Xu@Sun.COM * 2) check Kumeran Diagnostic register PCS lock loss bit
309610680SMin.Xu@Sun.COM * 3) if not set the link is locked (all is good), otherwise...
309710680SMin.Xu@Sun.COM * 4) reset the PHY
309810680SMin.Xu@Sun.COM * 5) repeat up to 10 times
30994919Sxy150489 * Note: this is only called for IGP3 copper when speed is 1gb.
31004919Sxy150489 */
31014919Sxy150489 static s32
e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw * hw)31024919Sxy150489 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw)
31034919Sxy150489 {
31048479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
31054919Sxy150489 u32 phy_ctrl;
31064919Sxy150489 s32 ret_val = E1000_SUCCESS;
31074919Sxy150489 u16 i, data;
31086735Scc210113 bool link;
31094919Sxy150489
31104919Sxy150489 DEBUGFUNC("e1000_kmrn_lock_loss_workaround_ich8lan");
31114919Sxy150489
31124919Sxy150489 if (!(dev_spec->kmrn_lock_loss_workaround_enabled))
31134919Sxy150489 goto out;
31144919Sxy150489
31154919Sxy150489 /*
31164919Sxy150489 * Make sure link is up before proceeding. If not just return.
31174919Sxy150489 * Attempting this while link is negotiating fouled up link stability
31184919Sxy150489 */
31194919Sxy150489 ret_val = e1000_phy_has_link_generic(hw, 1, 0, &link);
31204919Sxy150489 if (!link) {
31214919Sxy150489 ret_val = E1000_SUCCESS;
31224919Sxy150489 goto out;
31234919Sxy150489 }
31244919Sxy150489
31254919Sxy150489 for (i = 0; i < 10; i++) {
31264919Sxy150489 /* read once to clear */
31276735Scc210113 ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
31284919Sxy150489 if (ret_val)
31294919Sxy150489 goto out;
31304919Sxy150489 /* and again to get new status */
31316735Scc210113 ret_val = hw->phy.ops.read_reg(hw, IGP3_KMRN_DIAG, &data);
31324919Sxy150489 if (ret_val)
31334919Sxy150489 goto out;
31344919Sxy150489
31354919Sxy150489 /* check for PCS lock */
31364919Sxy150489 if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) {
31374919Sxy150489 ret_val = E1000_SUCCESS;
31384919Sxy150489 goto out;
31394919Sxy150489 }
31404919Sxy150489
31414919Sxy150489 /* Issue PHY reset */
31426735Scc210113 hw->phy.ops.reset(hw);
31434919Sxy150489 msec_delay_irq(5);
31444919Sxy150489 }
31454919Sxy150489 /* Disable GigE link negotiation */
31464919Sxy150489 phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
31474919Sxy150489 phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE |
31484919Sxy150489 E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
31494919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
31504919Sxy150489
31514919Sxy150489 /*
31526735Scc210113 * Call gig speed drop workaround on Gig disable before accessing any
31534919Sxy150489 * PHY registers
31544919Sxy150489 */
31554919Sxy150489 e1000_gig_downshift_workaround_ich8lan(hw);
31564919Sxy150489
31574919Sxy150489 /* unable to acquire PCS lock */
31584919Sxy150489 ret_val = -E1000_ERR_PHY;
31594919Sxy150489
31604919Sxy150489 out:
31614919Sxy150489 return (ret_val);
31624919Sxy150489 }
31634919Sxy150489
31644919Sxy150489 /*
31656735Scc210113 * e1000_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state
31664919Sxy150489 * @hw: pointer to the HW structure
31676735Scc210113 * @state: boolean value used to set the current Kumeran workaround state
31684919Sxy150489 *
31697607STed.You@Sun.COM * If ICH8, set the current Kumeran workaround state (enabled - true
31707607STed.You@Sun.COM * /disabled - false).
31714919Sxy150489 */
31724919Sxy150489 void
e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw * hw,bool state)31734919Sxy150489 e1000_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw,
31746735Scc210113 bool state)
31754919Sxy150489 {
31768479SChenlu.Chen@Sun.COM struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan;
31774919Sxy150489
31784919Sxy150489 DEBUGFUNC("e1000_set_kmrn_lock_loss_workaround_ich8lan");
31794919Sxy150489
31804919Sxy150489 if (hw->mac.type != e1000_ich8lan) {
31814919Sxy150489 DEBUGOUT("Workaround applies to ICH8 only.\n");
31824919Sxy150489 return;
31834919Sxy150489 }
31844919Sxy150489
31854919Sxy150489 dev_spec->kmrn_lock_loss_workaround_enabled = state;
31864919Sxy150489 }
31874919Sxy150489
31884919Sxy150489 /*
31894919Sxy150489 * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3
31904919Sxy150489 * @hw: pointer to the HW structure
31914919Sxy150489 *
31924919Sxy150489 * Workaround for 82566 power-down on D3 entry:
319310680SMin.Xu@Sun.COM * 1) disable gigabit link
319410680SMin.Xu@Sun.COM * 2) write VR power-down enable
319510680SMin.Xu@Sun.COM * 3) read it back
31964919Sxy150489 * Continue if successful, else issue LCD reset and repeat
31974919Sxy150489 */
31984919Sxy150489 void
e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw * hw)31994919Sxy150489 e1000_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw)
32004919Sxy150489 {
32014919Sxy150489 u32 reg;
32024919Sxy150489 u16 data;
32034919Sxy150489 u8 retry = 0;
32044919Sxy150489
32054919Sxy150489 DEBUGFUNC("e1000_igp3_phy_powerdown_workaround_ich8lan");
32064919Sxy150489
32074919Sxy150489 if (hw->phy.type != e1000_phy_igp_3)
32084919Sxy150489 return;
32094919Sxy150489
32104919Sxy150489 /* Try the workaround twice (if needed) */
32114919Sxy150489 do {
32124919Sxy150489 /* Disable link */
32134919Sxy150489 reg = E1000_READ_REG(hw, E1000_PHY_CTRL);
32144919Sxy150489 reg |= (E1000_PHY_CTRL_GBE_DISABLE |
32154919Sxy150489 E1000_PHY_CTRL_NOND0A_GBE_DISABLE);
32164919Sxy150489 E1000_WRITE_REG(hw, E1000_PHY_CTRL, reg);
32174919Sxy150489
32184919Sxy150489 /*
32196735Scc210113 * Call gig speed drop workaround on Gig disable before
32204919Sxy150489 * accessing any PHY registers
32214919Sxy150489 */
32224919Sxy150489 if (hw->mac.type == e1000_ich8lan)
32234919Sxy150489 e1000_gig_downshift_workaround_ich8lan(hw);
32244919Sxy150489
32254919Sxy150489 /* Write VR power-down enable */
32266735Scc210113 hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
32274919Sxy150489 data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
32288479SChenlu.Chen@Sun.COM hw->phy.ops.write_reg(hw, IGP3_VR_CTRL,
32294919Sxy150489 data | IGP3_VR_CTRL_MODE_SHUTDOWN);
32304919Sxy150489
32314919Sxy150489 /* Read it back and test */
32326735Scc210113 hw->phy.ops.read_reg(hw, IGP3_VR_CTRL, &data);
32334919Sxy150489 data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK;
32344919Sxy150489 if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry)
32354919Sxy150489 break;
32364919Sxy150489
32374919Sxy150489 /* Issue PHY reset and repeat at most one more time */
32384919Sxy150489 reg = E1000_READ_REG(hw, E1000_CTRL);
32394919Sxy150489 E1000_WRITE_REG(hw, E1000_CTRL, reg | E1000_CTRL_PHY_RST);
32404919Sxy150489 retry++;
32414919Sxy150489 } while (retry);
32424919Sxy150489 }
32434919Sxy150489
32444919Sxy150489 /*
32454919Sxy150489 * e1000_gig_downshift_workaround_ich8lan - WoL from S5 stops working
32464919Sxy150489 * @hw: pointer to the HW structure
32474919Sxy150489 *
32484919Sxy150489 * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC),
32496735Scc210113 * LPLU, Gig disable, MDIC PHY reset):
325010680SMin.Xu@Sun.COM * 1) Set Kumeran Near-end loopback
325110680SMin.Xu@Sun.COM * 2) Clear Kumeran Near-end loopback
32524919Sxy150489 * Should only be called for ICH8[m] devices with IGP_3 Phy.
32534919Sxy150489 */
32544919Sxy150489 void
e1000_gig_downshift_workaround_ich8lan(struct e1000_hw * hw)32554919Sxy150489 e1000_gig_downshift_workaround_ich8lan(struct e1000_hw *hw)
32564919Sxy150489 {
32574919Sxy150489 s32 ret_val = E1000_SUCCESS;
32584919Sxy150489 u16 reg_data;
32594919Sxy150489
32604919Sxy150489 DEBUGFUNC("e1000_gig_downshift_workaround_ich8lan");
32614919Sxy150489
32624919Sxy150489 if ((hw->mac.type != e1000_ich8lan) ||
32634919Sxy150489 (hw->phy.type != e1000_phy_igp_3))
32644919Sxy150489 return;
32654919Sxy150489
32667607STed.You@Sun.COM ret_val = e1000_read_kmrn_reg_generic(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET,
32674919Sxy150489 ®_data);
32684919Sxy150489 if (ret_val)
32694919Sxy150489 return;
32704919Sxy150489 reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK;
32717607STed.You@Sun.COM ret_val = e1000_write_kmrn_reg_generic(hw,
32727607STed.You@Sun.COM E1000_KMRNCTRLSTA_DIAG_OFFSET,
32734919Sxy150489 reg_data);
32744919Sxy150489 if (ret_val)
32754919Sxy150489 return;
32764919Sxy150489 reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK;
32777607STed.You@Sun.COM ret_val = e1000_write_kmrn_reg_generic(hw,
32787607STed.You@Sun.COM E1000_KMRNCTRLSTA_DIAG_OFFSET,
32794919Sxy150489 reg_data);
32804919Sxy150489 }
32814919Sxy150489
32824919Sxy150489 /*
32836735Scc210113 * e1000_disable_gig_wol_ich8lan - disable gig during WoL
32846735Scc210113 * @hw: pointer to the HW structure
32856735Scc210113 *
32866735Scc210113 * During S0 to Sx transition, it is possible the link remains at gig
32876735Scc210113 * instead of negotiating to a lower speed. Before going to Sx, set
32886735Scc210113 * 'LPLU Enabled' and 'Gig Disable' to force link speed negotiation
32896735Scc210113 * to a lower speed.
32906735Scc210113 *
329110680SMin.Xu@Sun.COM * Should only be called for applicable parts.
32926735Scc210113 */
32936735Scc210113 void
e1000_disable_gig_wol_ich8lan(struct e1000_hw * hw)32946735Scc210113 e1000_disable_gig_wol_ich8lan(struct e1000_hw *hw)
32956735Scc210113 {
32966735Scc210113 u32 phy_ctrl;
32976735Scc210113
329810680SMin.Xu@Sun.COM switch (hw->mac.type) {
329910680SMin.Xu@Sun.COM case e1000_ich9lan:
330010680SMin.Xu@Sun.COM case e1000_ich10lan:
330110680SMin.Xu@Sun.COM case e1000_pchlan:
33026735Scc210113 phy_ctrl = E1000_READ_REG(hw, E1000_PHY_CTRL);
33036735Scc210113 phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU |
33046735Scc210113 E1000_PHY_CTRL_GBE_DISABLE;
33056735Scc210113 E1000_WRITE_REG(hw, E1000_PHY_CTRL, phy_ctrl);
330610680SMin.Xu@Sun.COM
330710680SMin.Xu@Sun.COM if (hw->mac.type == e1000_pchlan)
3308*11143SGuoqing.Zhu@Sun.COM (void) e1000_phy_hw_reset_ich8lan(hw);
330910680SMin.Xu@Sun.COM default:
331010680SMin.Xu@Sun.COM break;
33116735Scc210113 }
33126735Scc210113 }
33136735Scc210113
33146735Scc210113 /*
33154919Sxy150489 * e1000_cleanup_led_ich8lan - Restore the default LED operation
33164919Sxy150489 * @hw: pointer to the HW structure
33174919Sxy150489 *
33184919Sxy150489 * Return the LED back to the default configuration.
33194919Sxy150489 */
33204919Sxy150489 static s32
e1000_cleanup_led_ich8lan(struct e1000_hw * hw)33214919Sxy150489 e1000_cleanup_led_ich8lan(struct e1000_hw *hw)
33224919Sxy150489 {
33234919Sxy150489 s32 ret_val = E1000_SUCCESS;
33244919Sxy150489
33254919Sxy150489 DEBUGFUNC("e1000_cleanup_led_ich8lan");
33264919Sxy150489
33274919Sxy150489 if (hw->phy.type == e1000_phy_ife)
33286735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
33294919Sxy150489 IFE_PHY_SPECIAL_CONTROL_LED,
33304919Sxy150489 0);
33314919Sxy150489 else
33324919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_default);
33334919Sxy150489
33344919Sxy150489 return (ret_val);
33354919Sxy150489 }
33364919Sxy150489
33374919Sxy150489 /*
33386735Scc210113 * e1000_led_on_ich8lan - Turn LEDs on
33394919Sxy150489 * @hw: pointer to the HW structure
33404919Sxy150489 *
33416735Scc210113 * Turn on the LEDs.
33424919Sxy150489 */
33434919Sxy150489 static s32
e1000_led_on_ich8lan(struct e1000_hw * hw)33444919Sxy150489 e1000_led_on_ich8lan(struct e1000_hw *hw)
33454919Sxy150489 {
33464919Sxy150489 s32 ret_val = E1000_SUCCESS;
33474919Sxy150489
33484919Sxy150489 DEBUGFUNC("e1000_led_on_ich8lan");
33494919Sxy150489
33504919Sxy150489 if (hw->phy.type == e1000_phy_ife)
33518479SChenlu.Chen@Sun.COM ret_val = hw->phy.ops.write_reg(hw, IFE_PHY_SPECIAL_CONTROL_LED,
33524919Sxy150489 (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON));
33534919Sxy150489 else
33544919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode2);
33554919Sxy150489
33564919Sxy150489 return (ret_val);
33574919Sxy150489 }
33584919Sxy150489
33594919Sxy150489 /*
33606735Scc210113 * e1000_led_off_ich8lan - Turn LEDs off
33614919Sxy150489 * @hw: pointer to the HW structure
33624919Sxy150489 *
33636735Scc210113 * Turn off the LEDs.
33644919Sxy150489 */
33654919Sxy150489 static s32
e1000_led_off_ich8lan(struct e1000_hw * hw)33664919Sxy150489 e1000_led_off_ich8lan(struct e1000_hw *hw)
33674919Sxy150489 {
33684919Sxy150489 s32 ret_val = E1000_SUCCESS;
33694919Sxy150489
33704919Sxy150489 DEBUGFUNC("e1000_led_off_ich8lan");
33714919Sxy150489
33724919Sxy150489 if (hw->phy.type == e1000_phy_ife)
33736735Scc210113 ret_val = hw->phy.ops.write_reg(hw,
33744919Sxy150489 IFE_PHY_SPECIAL_CONTROL_LED,
33754919Sxy150489 (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_OFF));
33764919Sxy150489 else
33774919Sxy150489 E1000_WRITE_REG(hw, E1000_LEDCTL, hw->mac.ledctl_mode1);
33784919Sxy150489
33794919Sxy150489 return (ret_val);
33804919Sxy150489 }
33814919Sxy150489
33824919Sxy150489 /*
338310680SMin.Xu@Sun.COM * e1000_setup_led_pchlan - Configures SW controllable LED
338410680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
338510680SMin.Xu@Sun.COM *
338610680SMin.Xu@Sun.COM * This prepares the SW controllable LED for use.
338710680SMin.Xu@Sun.COM */
338810680SMin.Xu@Sun.COM static s32
e1000_setup_led_pchlan(struct e1000_hw * hw)338910680SMin.Xu@Sun.COM e1000_setup_led_pchlan(struct e1000_hw *hw)
339010680SMin.Xu@Sun.COM {
339110680SMin.Xu@Sun.COM DEBUGFUNC("e1000_setup_led_pchlan");
339210680SMin.Xu@Sun.COM
339310680SMin.Xu@Sun.COM return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
339410680SMin.Xu@Sun.COM (u16)hw->mac.ledctl_mode1));
339510680SMin.Xu@Sun.COM }
339610680SMin.Xu@Sun.COM
339710680SMin.Xu@Sun.COM /*
339810680SMin.Xu@Sun.COM * e1000_cleanup_led_pchlan - Restore the default LED operation
339910680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
340010680SMin.Xu@Sun.COM *
340110680SMin.Xu@Sun.COM * Return the LED back to the default configuration.
340210680SMin.Xu@Sun.COM */
340310680SMin.Xu@Sun.COM static s32
e1000_cleanup_led_pchlan(struct e1000_hw * hw)340410680SMin.Xu@Sun.COM e1000_cleanup_led_pchlan(struct e1000_hw *hw)
340510680SMin.Xu@Sun.COM {
340610680SMin.Xu@Sun.COM DEBUGFUNC("e1000_cleanup_led_pchlan");
340710680SMin.Xu@Sun.COM
340810680SMin.Xu@Sun.COM return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG,
340910680SMin.Xu@Sun.COM (u16)hw->mac.ledctl_default));
341010680SMin.Xu@Sun.COM }
341110680SMin.Xu@Sun.COM
341210680SMin.Xu@Sun.COM /*
341310680SMin.Xu@Sun.COM * e1000_led_on_pchlan - Turn LEDs on
341410680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
341510680SMin.Xu@Sun.COM *
341610680SMin.Xu@Sun.COM * Turn on the LEDs.
341710680SMin.Xu@Sun.COM */
341810680SMin.Xu@Sun.COM static s32
e1000_led_on_pchlan(struct e1000_hw * hw)341910680SMin.Xu@Sun.COM e1000_led_on_pchlan(struct e1000_hw *hw)
342010680SMin.Xu@Sun.COM {
342110680SMin.Xu@Sun.COM u16 data = (u16)hw->mac.ledctl_mode2;
342210680SMin.Xu@Sun.COM u32 i, led;
342310680SMin.Xu@Sun.COM
342410680SMin.Xu@Sun.COM DEBUGFUNC("e1000_led_on_pchlan");
342510680SMin.Xu@Sun.COM
342610680SMin.Xu@Sun.COM /*
342710680SMin.Xu@Sun.COM * If no link, then turn LED on by setting the invert bit
342810680SMin.Xu@Sun.COM * for each LED that's mode is "link_up" in ledctl_mode2.
342910680SMin.Xu@Sun.COM */
343010680SMin.Xu@Sun.COM if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
343110680SMin.Xu@Sun.COM for (i = 0; i < 3; i++) {
343210680SMin.Xu@Sun.COM led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
343310680SMin.Xu@Sun.COM if ((led & E1000_PHY_LED0_MODE_MASK) !=
343410680SMin.Xu@Sun.COM E1000_LEDCTL_MODE_LINK_UP)
343510680SMin.Xu@Sun.COM continue;
343610680SMin.Xu@Sun.COM if (led & E1000_PHY_LED0_IVRT)
343710680SMin.Xu@Sun.COM data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
343810680SMin.Xu@Sun.COM else
343910680SMin.Xu@Sun.COM data |= (E1000_PHY_LED0_IVRT << (i * 5));
344010680SMin.Xu@Sun.COM }
344110680SMin.Xu@Sun.COM }
344210680SMin.Xu@Sun.COM
344310680SMin.Xu@Sun.COM return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data));
344410680SMin.Xu@Sun.COM }
344510680SMin.Xu@Sun.COM
344610680SMin.Xu@Sun.COM /*
344710680SMin.Xu@Sun.COM * e1000_led_off_pchlan - Turn LEDs off
344810680SMin.Xu@Sun.COM * @hw: pointer to the HW structure
344910680SMin.Xu@Sun.COM *
345010680SMin.Xu@Sun.COM * Turn off the LEDs.
345110680SMin.Xu@Sun.COM */
345210680SMin.Xu@Sun.COM static s32
e1000_led_off_pchlan(struct e1000_hw * hw)345310680SMin.Xu@Sun.COM e1000_led_off_pchlan(struct e1000_hw *hw)
345410680SMin.Xu@Sun.COM {
345510680SMin.Xu@Sun.COM u16 data = (u16)hw->mac.ledctl_mode1;
345610680SMin.Xu@Sun.COM u32 i, led;
345710680SMin.Xu@Sun.COM
345810680SMin.Xu@Sun.COM DEBUGFUNC("e1000_led_off_pchlan");
345910680SMin.Xu@Sun.COM
346010680SMin.Xu@Sun.COM /*
346110680SMin.Xu@Sun.COM * If no link, then turn LED off by clearing the invert bit
346210680SMin.Xu@Sun.COM * for each LED that's mode is "link_up" in ledctl_mode1.
346310680SMin.Xu@Sun.COM */
346410680SMin.Xu@Sun.COM if (!(E1000_READ_REG(hw, E1000_STATUS) & E1000_STATUS_LU)) {
346510680SMin.Xu@Sun.COM for (i = 0; i < 3; i++) {
346610680SMin.Xu@Sun.COM led = (data >> (i * 5)) & E1000_PHY_LED0_MASK;
346710680SMin.Xu@Sun.COM if ((led & E1000_PHY_LED0_MODE_MASK) !=
346810680SMin.Xu@Sun.COM E1000_LEDCTL_MODE_LINK_UP)
346910680SMin.Xu@Sun.COM continue;
347010680SMin.Xu@Sun.COM if (led & E1000_PHY_LED0_IVRT)
347110680SMin.Xu@Sun.COM data &= ~(E1000_PHY_LED0_IVRT << (i * 5));
347210680SMin.Xu@Sun.COM else
347310680SMin.Xu@Sun.COM data |= (E1000_PHY_LED0_IVRT << (i * 5));
347410680SMin.Xu@Sun.COM }
347510680SMin.Xu@Sun.COM }
347610680SMin.Xu@Sun.COM
347710680SMin.Xu@Sun.COM return (hw->phy.ops.write_reg(hw, HV_LED_CONFIG, data));
347810680SMin.Xu@Sun.COM }
347910680SMin.Xu@Sun.COM
348010680SMin.Xu@Sun.COM /*
34814919Sxy150489 * e1000_get_cfg_done_ich8lan - Read config done bit
34824919Sxy150489 * @hw: pointer to the HW structure
34834919Sxy150489 *
34844919Sxy150489 * Read the management control register for the config done bit for
34854919Sxy150489 * completion status. NOTE: silicon which is EEPROM-less will fail trying
34864919Sxy150489 * to read the config done bit, so an error is *ONLY* logged and returns
34874919Sxy150489 * E1000_SUCCESS. If we were to return with error, EEPROM-less silicon
34884919Sxy150489 * would not be able to be reset or change link.
34894919Sxy150489 */
34904919Sxy150489 static s32
e1000_get_cfg_done_ich8lan(struct e1000_hw * hw)34914919Sxy150489 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw)
34924919Sxy150489 {
34936735Scc210113 s32 ret_val = E1000_SUCCESS;
34947607STed.You@Sun.COM u32 bank = 0;
34956735Scc210113
349610680SMin.Xu@Sun.COM if (hw->mac.type >= e1000_pchlan) {
349710680SMin.Xu@Sun.COM u32 status = E1000_READ_REG(hw, E1000_STATUS);
349810680SMin.Xu@Sun.COM
349910680SMin.Xu@Sun.COM if (status & E1000_STATUS_PHYRA) {
350010680SMin.Xu@Sun.COM E1000_WRITE_REG(hw, E1000_STATUS, status &
350110680SMin.Xu@Sun.COM ~E1000_STATUS_PHYRA);
350210680SMin.Xu@Sun.COM } else
3503*11143SGuoqing.Zhu@Sun.COM /* EMPTY */
350410680SMin.Xu@Sun.COM DEBUGOUT("PHY Reset Asserted not set - needs delay\n");
350510680SMin.Xu@Sun.COM }
350610680SMin.Xu@Sun.COM
35077426SChenliang.Xu@Sun.COM (void) e1000_get_cfg_done_generic(hw);
35084919Sxy150489
35094919Sxy150489 /* If EEPROM is not marked present, init the IGP 3 PHY manually */
351010680SMin.Xu@Sun.COM if ((hw->mac.type != e1000_ich10lan) &&
351110680SMin.Xu@Sun.COM (hw->mac.type != e1000_pchlan)) {
35127607STed.You@Sun.COM if (((E1000_READ_REG(hw, E1000_EECD) & E1000_EECD_PRES) == 0) &&
35137607STed.You@Sun.COM (hw->phy.type == e1000_phy_igp_3)) {
35147607STed.You@Sun.COM (void) e1000_phy_init_script_igp3(hw);
35157607STed.You@Sun.COM }
35167607STed.You@Sun.COM } else {
35177607STed.You@Sun.COM if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) {
35188479SChenlu.Chen@Sun.COM /* Maybe we should do a basic PHY config */
35197607STed.You@Sun.COM DEBUGOUT("EEPROM not present\n");
35207607STed.You@Sun.COM ret_val = -E1000_ERR_CONFIG;
35217607STed.You@Sun.COM }
35224919Sxy150489 }
35237607STed.You@Sun.COM
35246735Scc210113 return (ret_val);
35256735Scc210113 }
35266735Scc210113
35276735Scc210113 /*
35286735Scc210113 * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down
35296735Scc210113 * @hw: pointer to the HW structure
35306735Scc210113 *
35316735Scc210113 * In the case of a PHY power down to save power, or to turn off link during a
35326735Scc210113 * driver unload, or wake on lan is not enabled, remove the link.
35336735Scc210113 */
35346735Scc210113 static void
e1000_power_down_phy_copper_ich8lan(struct e1000_hw * hw)35356735Scc210113 e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw)
35366735Scc210113 {
35376735Scc210113 /* If the management interface is not enabled, then power down */
35388479SChenlu.Chen@Sun.COM if (!(hw->mac.ops.check_mng_mode(hw) ||
35398479SChenlu.Chen@Sun.COM hw->phy.ops.check_reset_block(hw)))
35406735Scc210113 e1000_power_down_phy_copper(hw);
35414919Sxy150489 }
35424919Sxy150489
35434919Sxy150489 /*
35444919Sxy150489 * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters
35454919Sxy150489 * @hw: pointer to the HW structure
35464919Sxy150489 *
35474919Sxy150489 * Clears hardware counters specific to the silicon family and calls
35484919Sxy150489 * clear_hw_cntrs_generic to clear all general purpose counters.
35494919Sxy150489 */
35504919Sxy150489 static void
e1000_clear_hw_cntrs_ich8lan(struct e1000_hw * hw)35514919Sxy150489 e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw)
35524919Sxy150489 {
355310680SMin.Xu@Sun.COM u16 phy_data;
355410680SMin.Xu@Sun.COM
35554919Sxy150489 DEBUGFUNC("e1000_clear_hw_cntrs_ich8lan");
35564919Sxy150489
35574919Sxy150489 e1000_clear_hw_cntrs_base_generic(hw);
35584919Sxy150489
35597426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ALGNERRC);
35607426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_RXERRC);
35617426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TNCRS);
35627426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_CEXTERR);
35637426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTC);
35647426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_TSCTFC);
35654919Sxy150489
35667426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPRC);
35677426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPDC);
35687426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_MGTPTC);
35694919Sxy150489
35707426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_IAC);
35717426SChenliang.Xu@Sun.COM (void) E1000_READ_REG(hw, E1000_ICRXOC);
357210680SMin.Xu@Sun.COM
357310680SMin.Xu@Sun.COM /* Clear PHY statistics registers */
357410680SMin.Xu@Sun.COM if ((hw->phy.type == e1000_phy_82578) ||
357510680SMin.Xu@Sun.COM (hw->phy.type == e1000_phy_82577)) {
357610680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_SCC_UPPER, &phy_data);
357710680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_SCC_LOWER, &phy_data);
357810680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_ECOL_UPPER, &phy_data);
357910680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_ECOL_LOWER, &phy_data);
358010680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_MCC_UPPER, &phy_data);
358110680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_MCC_LOWER, &phy_data);
358210680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_LATECOL_UPPER, &phy_data);
358310680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_LATECOL_LOWER, &phy_data);
358410680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_COLC_UPPER, &phy_data);
358510680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_COLC_LOWER, &phy_data);
358610680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_DC_UPPER, &phy_data);
358710680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_DC_LOWER, &phy_data);
358810680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_TNCRS_UPPER, &phy_data);
358910680SMin.Xu@Sun.COM (void) hw->phy.ops.read_reg(hw, HV_TNCRS_LOWER, &phy_data);
359010680SMin.Xu@Sun.COM }
35914919Sxy150489 }
3592