18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci/* 82562G 10/100 Network Connection 58c2ecf20Sopenharmony_ci * 82562G-2 10/100 Network Connection 68c2ecf20Sopenharmony_ci * 82562GT 10/100 Network Connection 78c2ecf20Sopenharmony_ci * 82562GT-2 10/100 Network Connection 88c2ecf20Sopenharmony_ci * 82562V 10/100 Network Connection 98c2ecf20Sopenharmony_ci * 82562V-2 10/100 Network Connection 108c2ecf20Sopenharmony_ci * 82566DC-2 Gigabit Network Connection 118c2ecf20Sopenharmony_ci * 82566DC Gigabit Network Connection 128c2ecf20Sopenharmony_ci * 82566DM-2 Gigabit Network Connection 138c2ecf20Sopenharmony_ci * 82566DM Gigabit Network Connection 148c2ecf20Sopenharmony_ci * 82566MC Gigabit Network Connection 158c2ecf20Sopenharmony_ci * 82566MM Gigabit Network Connection 168c2ecf20Sopenharmony_ci * 82567LM Gigabit Network Connection 178c2ecf20Sopenharmony_ci * 82567LF Gigabit Network Connection 188c2ecf20Sopenharmony_ci * 82567V Gigabit Network Connection 198c2ecf20Sopenharmony_ci * 82567LM-2 Gigabit Network Connection 208c2ecf20Sopenharmony_ci * 82567LF-2 Gigabit Network Connection 218c2ecf20Sopenharmony_ci * 82567V-2 Gigabit Network Connection 228c2ecf20Sopenharmony_ci * 82567LF-3 Gigabit Network Connection 238c2ecf20Sopenharmony_ci * 82567LM-3 Gigabit Network Connection 248c2ecf20Sopenharmony_ci * 82567LM-4 Gigabit Network Connection 258c2ecf20Sopenharmony_ci * 82577LM Gigabit Network Connection 268c2ecf20Sopenharmony_ci * 82577LC Gigabit Network Connection 278c2ecf20Sopenharmony_ci * 82578DM Gigabit Network Connection 288c2ecf20Sopenharmony_ci * 82578DC Gigabit Network Connection 298c2ecf20Sopenharmony_ci * 82579LM Gigabit Network Connection 308c2ecf20Sopenharmony_ci * 82579V Gigabit Network Connection 318c2ecf20Sopenharmony_ci * Ethernet Connection I217-LM 328c2ecf20Sopenharmony_ci * Ethernet Connection I217-V 338c2ecf20Sopenharmony_ci * Ethernet Connection I218-V 348c2ecf20Sopenharmony_ci * Ethernet Connection I218-LM 358c2ecf20Sopenharmony_ci * Ethernet Connection (2) I218-LM 368c2ecf20Sopenharmony_ci * Ethernet Connection (2) I218-V 378c2ecf20Sopenharmony_ci * Ethernet Connection (3) I218-LM 388c2ecf20Sopenharmony_ci * Ethernet Connection (3) I218-V 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#include "e1000.h" 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/* ICH GbE Flash Hardware Sequencing Flash Status Register bit breakdown */ 448c2ecf20Sopenharmony_ci/* Offset 04h HSFSTS */ 458c2ecf20Sopenharmony_ciunion ich8_hws_flash_status { 468c2ecf20Sopenharmony_ci struct ich8_hsfsts { 478c2ecf20Sopenharmony_ci u16 flcdone:1; /* bit 0 Flash Cycle Done */ 488c2ecf20Sopenharmony_ci u16 flcerr:1; /* bit 1 Flash Cycle Error */ 498c2ecf20Sopenharmony_ci u16 dael:1; /* bit 2 Direct Access error Log */ 508c2ecf20Sopenharmony_ci u16 berasesz:2; /* bit 4:3 Sector Erase Size */ 518c2ecf20Sopenharmony_ci u16 flcinprog:1; /* bit 5 flash cycle in Progress */ 528c2ecf20Sopenharmony_ci u16 reserved1:2; /* bit 13:6 Reserved */ 538c2ecf20Sopenharmony_ci u16 reserved2:6; /* bit 13:6 Reserved */ 548c2ecf20Sopenharmony_ci u16 fldesvalid:1; /* bit 14 Flash Descriptor Valid */ 558c2ecf20Sopenharmony_ci u16 flockdn:1; /* bit 15 Flash Config Lock-Down */ 568c2ecf20Sopenharmony_ci } hsf_status; 578c2ecf20Sopenharmony_ci u16 regval; 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci/* ICH GbE Flash Hardware Sequencing Flash control Register bit breakdown */ 618c2ecf20Sopenharmony_ci/* Offset 06h FLCTL */ 628c2ecf20Sopenharmony_ciunion ich8_hws_flash_ctrl { 638c2ecf20Sopenharmony_ci struct ich8_hsflctl { 648c2ecf20Sopenharmony_ci u16 flcgo:1; /* 0 Flash Cycle Go */ 658c2ecf20Sopenharmony_ci u16 flcycle:2; /* 2:1 Flash Cycle */ 668c2ecf20Sopenharmony_ci u16 reserved:5; /* 7:3 Reserved */ 678c2ecf20Sopenharmony_ci u16 fldbcount:2; /* 9:8 Flash Data Byte Count */ 688c2ecf20Sopenharmony_ci u16 flockdn:6; /* 15:10 Reserved */ 698c2ecf20Sopenharmony_ci } hsf_ctrl; 708c2ecf20Sopenharmony_ci u16 regval; 718c2ecf20Sopenharmony_ci}; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci/* ICH Flash Region Access Permissions */ 748c2ecf20Sopenharmony_ciunion ich8_hws_flash_regacc { 758c2ecf20Sopenharmony_ci struct ich8_flracc { 768c2ecf20Sopenharmony_ci u32 grra:8; /* 0:7 GbE region Read Access */ 778c2ecf20Sopenharmony_ci u32 grwa:8; /* 8:15 GbE region Write Access */ 788c2ecf20Sopenharmony_ci u32 gmrag:8; /* 23:16 GbE Master Read Access Grant */ 798c2ecf20Sopenharmony_ci u32 gmwag:8; /* 31:24 GbE Master Write Access Grant */ 808c2ecf20Sopenharmony_ci } hsf_flregacc; 818c2ecf20Sopenharmony_ci u16 regval; 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* ICH Flash Protected Region */ 858c2ecf20Sopenharmony_ciunion ich8_flash_protected_range { 868c2ecf20Sopenharmony_ci struct ich8_pr { 878c2ecf20Sopenharmony_ci u32 base:13; /* 0:12 Protected Range Base */ 888c2ecf20Sopenharmony_ci u32 reserved1:2; /* 13:14 Reserved */ 898c2ecf20Sopenharmony_ci u32 rpe:1; /* 15 Read Protection Enable */ 908c2ecf20Sopenharmony_ci u32 limit:13; /* 16:28 Protected Range Limit */ 918c2ecf20Sopenharmony_ci u32 reserved2:2; /* 29:30 Reserved */ 928c2ecf20Sopenharmony_ci u32 wpe:1; /* 31 Write Protection Enable */ 938c2ecf20Sopenharmony_ci } range; 948c2ecf20Sopenharmony_ci u32 regval; 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw); 988c2ecf20Sopenharmony_cistatic void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw); 998c2ecf20Sopenharmony_cistatic s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank); 1008c2ecf20Sopenharmony_cistatic s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 1018c2ecf20Sopenharmony_ci u32 offset, u8 byte); 1028c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 1038c2ecf20Sopenharmony_ci u8 *data); 1048c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 1058c2ecf20Sopenharmony_ci u16 *data); 1068c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 1078c2ecf20Sopenharmony_ci u8 size, u16 *data); 1088c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 1098c2ecf20Sopenharmony_ci u32 *data); 1108c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, 1118c2ecf20Sopenharmony_ci u32 offset, u32 *data); 1128c2ecf20Sopenharmony_cistatic s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, 1138c2ecf20Sopenharmony_ci u32 offset, u32 data); 1148c2ecf20Sopenharmony_cistatic s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 1158c2ecf20Sopenharmony_ci u32 offset, u32 dword); 1168c2ecf20Sopenharmony_cistatic s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw); 1178c2ecf20Sopenharmony_cistatic s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw); 1188c2ecf20Sopenharmony_cistatic s32 e1000_led_on_ich8lan(struct e1000_hw *hw); 1198c2ecf20Sopenharmony_cistatic s32 e1000_led_off_ich8lan(struct e1000_hw *hw); 1208c2ecf20Sopenharmony_cistatic s32 e1000_id_led_init_pchlan(struct e1000_hw *hw); 1218c2ecf20Sopenharmony_cistatic s32 e1000_setup_led_pchlan(struct e1000_hw *hw); 1228c2ecf20Sopenharmony_cistatic s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw); 1238c2ecf20Sopenharmony_cistatic s32 e1000_led_on_pchlan(struct e1000_hw *hw); 1248c2ecf20Sopenharmony_cistatic s32 e1000_led_off_pchlan(struct e1000_hw *hw); 1258c2ecf20Sopenharmony_cistatic s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active); 1268c2ecf20Sopenharmony_cistatic void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw); 1278c2ecf20Sopenharmony_cistatic void e1000_lan_init_done_ich8lan(struct e1000_hw *hw); 1288c2ecf20Sopenharmony_cistatic s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link); 1298c2ecf20Sopenharmony_cistatic s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw); 1308c2ecf20Sopenharmony_cistatic bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw); 1318c2ecf20Sopenharmony_cistatic bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw); 1328c2ecf20Sopenharmony_cistatic int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index); 1338c2ecf20Sopenharmony_cistatic int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index); 1348c2ecf20Sopenharmony_cistatic u32 e1000_rar_get_count_pch_lpt(struct e1000_hw *hw); 1358c2ecf20Sopenharmony_cistatic s32 e1000_k1_workaround_lv(struct e1000_hw *hw); 1368c2ecf20Sopenharmony_cistatic void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate); 1378c2ecf20Sopenharmony_cistatic s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force); 1388c2ecf20Sopenharmony_cistatic s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw); 1398c2ecf20Sopenharmony_cistatic s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic inline u16 __er16flash(struct e1000_hw *hw, unsigned long reg) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci return readw(hw->flash_address + reg); 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_cistatic inline u32 __er32flash(struct e1000_hw *hw, unsigned long reg) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci return readl(hw->flash_address + reg); 1498c2ecf20Sopenharmony_ci} 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_cistatic inline void __ew16flash(struct e1000_hw *hw, unsigned long reg, u16 val) 1528c2ecf20Sopenharmony_ci{ 1538c2ecf20Sopenharmony_ci writew(val, hw->flash_address + reg); 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic inline void __ew32flash(struct e1000_hw *hw, unsigned long reg, u32 val) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci writel(val, hw->flash_address + reg); 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci#define er16flash(reg) __er16flash(hw, (reg)) 1628c2ecf20Sopenharmony_ci#define er32flash(reg) __er32flash(hw, (reg)) 1638c2ecf20Sopenharmony_ci#define ew16flash(reg, val) __ew16flash(hw, (reg), (val)) 1648c2ecf20Sopenharmony_ci#define ew32flash(reg, val) __ew32flash(hw, (reg), (val)) 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci/** 1678c2ecf20Sopenharmony_ci * e1000_phy_is_accessible_pchlan - Check if able to access PHY registers 1688c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 1698c2ecf20Sopenharmony_ci * 1708c2ecf20Sopenharmony_ci * Test access to the PHY registers by reading the PHY ID registers. If 1718c2ecf20Sopenharmony_ci * the PHY ID is already known (e.g. resume path) compare it with known ID, 1728c2ecf20Sopenharmony_ci * otherwise assume the read PHY ID is correct if it is valid. 1738c2ecf20Sopenharmony_ci * 1748c2ecf20Sopenharmony_ci * Assumes the sw/fw/hw semaphore is already acquired. 1758c2ecf20Sopenharmony_ci **/ 1768c2ecf20Sopenharmony_cistatic bool e1000_phy_is_accessible_pchlan(struct e1000_hw *hw) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u16 phy_reg = 0; 1798c2ecf20Sopenharmony_ci u32 phy_id = 0; 1808c2ecf20Sopenharmony_ci s32 ret_val = 0; 1818c2ecf20Sopenharmony_ci u16 retry_count; 1828c2ecf20Sopenharmony_ci u32 mac_reg = 0; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci for (retry_count = 0; retry_count < 2; retry_count++) { 1858c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, MII_PHYSID1, &phy_reg); 1868c2ecf20Sopenharmony_ci if (ret_val || (phy_reg == 0xFFFF)) 1878c2ecf20Sopenharmony_ci continue; 1888c2ecf20Sopenharmony_ci phy_id = (u32)(phy_reg << 16); 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, MII_PHYSID2, &phy_reg); 1918c2ecf20Sopenharmony_ci if (ret_val || (phy_reg == 0xFFFF)) { 1928c2ecf20Sopenharmony_ci phy_id = 0; 1938c2ecf20Sopenharmony_ci continue; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci phy_id |= (u32)(phy_reg & PHY_REVISION_MASK); 1968c2ecf20Sopenharmony_ci break; 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci if (hw->phy.id) { 2008c2ecf20Sopenharmony_ci if (hw->phy.id == phy_id) 2018c2ecf20Sopenharmony_ci goto out; 2028c2ecf20Sopenharmony_ci } else if (phy_id) { 2038c2ecf20Sopenharmony_ci hw->phy.id = phy_id; 2048c2ecf20Sopenharmony_ci hw->phy.revision = (u32)(phy_reg & ~PHY_REVISION_MASK); 2058c2ecf20Sopenharmony_ci goto out; 2068c2ecf20Sopenharmony_ci } 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci /* In case the PHY needs to be in mdio slow mode, 2098c2ecf20Sopenharmony_ci * set slow mode and try to get the PHY id again. 2108c2ecf20Sopenharmony_ci */ 2118c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch_lpt) { 2128c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 2138c2ecf20Sopenharmony_ci ret_val = e1000_set_mdio_slow_mode_hv(hw); 2148c2ecf20Sopenharmony_ci if (!ret_val) 2158c2ecf20Sopenharmony_ci ret_val = e1000e_get_phy_id(hw); 2168c2ecf20Sopenharmony_ci hw->phy.ops.acquire(hw); 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci if (ret_val) 2208c2ecf20Sopenharmony_ci return false; 2218c2ecf20Sopenharmony_ciout: 2228c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 2238c2ecf20Sopenharmony_ci /* Only unforce SMBus if ME is not active */ 2248c2ecf20Sopenharmony_ci if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { 2258c2ecf20Sopenharmony_ci /* Unforce SMBus mode in PHY */ 2268c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, CV_SMB_CTRL, &phy_reg); 2278c2ecf20Sopenharmony_ci phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 2288c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, CV_SMB_CTRL, phy_reg); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* Unforce SMBus mode in MAC */ 2318c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 2328c2ecf20Sopenharmony_ci mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 2338c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return true; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci/** 2418c2ecf20Sopenharmony_ci * e1000_toggle_lanphypc_pch_lpt - toggle the LANPHYPC pin value 2428c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2438c2ecf20Sopenharmony_ci * 2448c2ecf20Sopenharmony_ci * Toggling the LANPHYPC pin value fully power-cycles the PHY and is 2458c2ecf20Sopenharmony_ci * used to reset the PHY to a quiescent state when necessary. 2468c2ecf20Sopenharmony_ci **/ 2478c2ecf20Sopenharmony_cistatic void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci u32 mac_reg; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci /* Set Phy Config Counter to 50msec */ 2528c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM3); 2538c2ecf20Sopenharmony_ci mac_reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 2548c2ecf20Sopenharmony_ci mac_reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 2558c2ecf20Sopenharmony_ci ew32(FEXTNVM3, mac_reg); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci /* Toggle LANPHYPC Value bit */ 2588c2ecf20Sopenharmony_ci mac_reg = er32(CTRL); 2598c2ecf20Sopenharmony_ci mac_reg |= E1000_CTRL_LANPHYPC_OVERRIDE; 2608c2ecf20Sopenharmony_ci mac_reg &= ~E1000_CTRL_LANPHYPC_VALUE; 2618c2ecf20Sopenharmony_ci ew32(CTRL, mac_reg); 2628c2ecf20Sopenharmony_ci e1e_flush(); 2638c2ecf20Sopenharmony_ci usleep_range(10, 20); 2648c2ecf20Sopenharmony_ci mac_reg &= ~E1000_CTRL_LANPHYPC_OVERRIDE; 2658c2ecf20Sopenharmony_ci ew32(CTRL, mac_reg); 2668c2ecf20Sopenharmony_ci e1e_flush(); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch_lpt) { 2698c2ecf20Sopenharmony_ci msleep(50); 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci u16 count = 20; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci do { 2748c2ecf20Sopenharmony_ci usleep_range(5000, 6000); 2758c2ecf20Sopenharmony_ci } while (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LPCD) && count--); 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci msleep(30); 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci/** 2828c2ecf20Sopenharmony_ci * e1000_init_phy_workarounds_pchlan - PHY initialization workarounds 2838c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 2848c2ecf20Sopenharmony_ci * 2858c2ecf20Sopenharmony_ci * Workarounds/flow necessary for PHY initialization during driver load 2868c2ecf20Sopenharmony_ci * and resume paths. 2878c2ecf20Sopenharmony_ci **/ 2888c2ecf20Sopenharmony_cistatic s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci struct e1000_adapter *adapter = hw->adapter; 2918c2ecf20Sopenharmony_ci u32 mac_reg, fwsm = er32(FWSM); 2928c2ecf20Sopenharmony_ci s32 ret_val; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* Gate automatic PHY configuration by hardware on managed and 2958c2ecf20Sopenharmony_ci * non-managed 82579 and newer adapters. 2968c2ecf20Sopenharmony_ci */ 2978c2ecf20Sopenharmony_ci e1000_gate_hw_phy_config_ich8lan(hw, true); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci /* It is not possible to be certain of the current state of ULP 3008c2ecf20Sopenharmony_ci * so forcibly disable it. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_unknown; 3038c2ecf20Sopenharmony_ci ret_val = e1000_disable_ulp_lpt_lp(hw, true); 3048c2ecf20Sopenharmony_ci if (ret_val) 3058c2ecf20Sopenharmony_ci e_warn("Failed to disable ULP\n"); 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 3088c2ecf20Sopenharmony_ci if (ret_val) { 3098c2ecf20Sopenharmony_ci e_dbg("Failed to initialize PHY flow\n"); 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* The MAC-PHY interconnect may be in SMBus mode. If the PHY is 3148c2ecf20Sopenharmony_ci * inaccessible and resetting the PHY is not blocked, toggle the 3158c2ecf20Sopenharmony_ci * LANPHYPC Value bit to force the interconnect to PCIe mode. 3168c2ecf20Sopenharmony_ci */ 3178c2ecf20Sopenharmony_ci switch (hw->mac.type) { 3188c2ecf20Sopenharmony_ci case e1000_pch_lpt: 3198c2ecf20Sopenharmony_ci case e1000_pch_spt: 3208c2ecf20Sopenharmony_ci case e1000_pch_cnp: 3218c2ecf20Sopenharmony_ci case e1000_pch_tgp: 3228c2ecf20Sopenharmony_ci case e1000_pch_adp: 3238c2ecf20Sopenharmony_ci case e1000_pch_mtp: 3248c2ecf20Sopenharmony_ci if (e1000_phy_is_accessible_pchlan(hw)) 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci /* Before toggling LANPHYPC, see if PHY is accessible by 3288c2ecf20Sopenharmony_ci * forcing MAC to SMBus mode first. 3298c2ecf20Sopenharmony_ci */ 3308c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 3318c2ecf20Sopenharmony_ci mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 3328c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* Wait 50 milliseconds for MAC to finish any retries 3358c2ecf20Sopenharmony_ci * that it might be trying to perform from previous 3368c2ecf20Sopenharmony_ci * attempts to acknowledge any phy read requests. 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci msleep(50); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci fallthrough; 3418c2ecf20Sopenharmony_ci case e1000_pch2lan: 3428c2ecf20Sopenharmony_ci if (e1000_phy_is_accessible_pchlan(hw)) 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci fallthrough; 3468c2ecf20Sopenharmony_ci case e1000_pchlan: 3478c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_pchlan) && 3488c2ecf20Sopenharmony_ci (fwsm & E1000_ICH_FWSM_FW_VALID)) 3498c2ecf20Sopenharmony_ci break; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci if (hw->phy.ops.check_reset_block(hw)) { 3528c2ecf20Sopenharmony_ci e_dbg("Required LANPHYPC toggle blocked by ME\n"); 3538c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_PHY; 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci /* Toggle LANPHYPC Value bit */ 3588c2ecf20Sopenharmony_ci e1000_toggle_lanphypc_pch_lpt(hw); 3598c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 3608c2ecf20Sopenharmony_ci if (e1000_phy_is_accessible_pchlan(hw)) 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci /* Toggling LANPHYPC brings the PHY out of SMBus mode 3648c2ecf20Sopenharmony_ci * so ensure that the MAC is also out of SMBus mode 3658c2ecf20Sopenharmony_ci */ 3668c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 3678c2ecf20Sopenharmony_ci mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 3688c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci if (e1000_phy_is_accessible_pchlan(hw)) 3718c2ecf20Sopenharmony_ci break; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_PHY; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci break; 3768c2ecf20Sopenharmony_ci default: 3778c2ecf20Sopenharmony_ci break; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 3818c2ecf20Sopenharmony_ci if (!ret_val) { 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* Check to see if able to reset PHY. Print error if not */ 3848c2ecf20Sopenharmony_ci if (hw->phy.ops.check_reset_block(hw)) { 3858c2ecf20Sopenharmony_ci e_err("Reset blocked by ME\n"); 3868c2ecf20Sopenharmony_ci goto out; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* Reset the PHY before any access to it. Doing so, ensures 3908c2ecf20Sopenharmony_ci * that the PHY is in a known good state before we read/write 3918c2ecf20Sopenharmony_ci * PHY registers. The generic reset is sufficient here, 3928c2ecf20Sopenharmony_ci * because we haven't determined the PHY type yet. 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci ret_val = e1000e_phy_hw_reset_generic(hw); 3958c2ecf20Sopenharmony_ci if (ret_val) 3968c2ecf20Sopenharmony_ci goto out; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci /* On a successful reset, possibly need to wait for the PHY 3998c2ecf20Sopenharmony_ci * to quiesce to an accessible state before returning control 4008c2ecf20Sopenharmony_ci * to the calling function. If the PHY does not quiesce, then 4018c2ecf20Sopenharmony_ci * return E1000E_BLK_PHY_RESET, as this is the condition that 4028c2ecf20Sopenharmony_ci * the PHY is in. 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.check_reset_block(hw); 4058c2ecf20Sopenharmony_ci if (ret_val) 4068c2ecf20Sopenharmony_ci e_err("ME blocked access to PHY after reset\n"); 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ciout: 4108c2ecf20Sopenharmony_ci /* Ungate automatic PHY configuration on non-managed 82579 */ 4118c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_pch2lan) && 4128c2ecf20Sopenharmony_ci !(fwsm & E1000_ICH_FWSM_FW_VALID)) { 4138c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 4148c2ecf20Sopenharmony_ci e1000_gate_hw_phy_config_ich8lan(hw, false); 4158c2ecf20Sopenharmony_ci } 4168c2ecf20Sopenharmony_ci 4178c2ecf20Sopenharmony_ci return ret_val; 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci/** 4218c2ecf20Sopenharmony_ci * e1000_init_phy_params_pchlan - Initialize PHY function pointers 4228c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 4238c2ecf20Sopenharmony_ci * 4248c2ecf20Sopenharmony_ci * Initialize family-specific PHY parameters and function pointers. 4258c2ecf20Sopenharmony_ci **/ 4268c2ecf20Sopenharmony_cistatic s32 e1000_init_phy_params_pchlan(struct e1000_hw *hw) 4278c2ecf20Sopenharmony_ci{ 4288c2ecf20Sopenharmony_ci struct e1000_phy_info *phy = &hw->phy; 4298c2ecf20Sopenharmony_ci s32 ret_val; 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci phy->addr = 1; 4328c2ecf20Sopenharmony_ci phy->reset_delay_us = 100; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci phy->ops.set_page = e1000_set_page_igp; 4358c2ecf20Sopenharmony_ci phy->ops.read_reg = e1000_read_phy_reg_hv; 4368c2ecf20Sopenharmony_ci phy->ops.read_reg_locked = e1000_read_phy_reg_hv_locked; 4378c2ecf20Sopenharmony_ci phy->ops.read_reg_page = e1000_read_phy_reg_page_hv; 4388c2ecf20Sopenharmony_ci phy->ops.set_d0_lplu_state = e1000_set_lplu_state_pchlan; 4398c2ecf20Sopenharmony_ci phy->ops.set_d3_lplu_state = e1000_set_lplu_state_pchlan; 4408c2ecf20Sopenharmony_ci phy->ops.write_reg = e1000_write_phy_reg_hv; 4418c2ecf20Sopenharmony_ci phy->ops.write_reg_locked = e1000_write_phy_reg_hv_locked; 4428c2ecf20Sopenharmony_ci phy->ops.write_reg_page = e1000_write_phy_reg_page_hv; 4438c2ecf20Sopenharmony_ci phy->ops.power_up = e1000_power_up_phy_copper; 4448c2ecf20Sopenharmony_ci phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 4458c2ecf20Sopenharmony_ci phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci phy->id = e1000_phy_unknown; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret_val = e1000_init_phy_workarounds_pchlan(hw); 4508c2ecf20Sopenharmony_ci if (ret_val) 4518c2ecf20Sopenharmony_ci return ret_val; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci if (phy->id == e1000_phy_unknown) 4548c2ecf20Sopenharmony_ci switch (hw->mac.type) { 4558c2ecf20Sopenharmony_ci default: 4568c2ecf20Sopenharmony_ci ret_val = e1000e_get_phy_id(hw); 4578c2ecf20Sopenharmony_ci if (ret_val) 4588c2ecf20Sopenharmony_ci return ret_val; 4598c2ecf20Sopenharmony_ci if ((phy->id != 0) && (phy->id != PHY_REVISION_MASK)) 4608c2ecf20Sopenharmony_ci break; 4618c2ecf20Sopenharmony_ci fallthrough; 4628c2ecf20Sopenharmony_ci case e1000_pch2lan: 4638c2ecf20Sopenharmony_ci case e1000_pch_lpt: 4648c2ecf20Sopenharmony_ci case e1000_pch_spt: 4658c2ecf20Sopenharmony_ci case e1000_pch_cnp: 4668c2ecf20Sopenharmony_ci case e1000_pch_tgp: 4678c2ecf20Sopenharmony_ci case e1000_pch_adp: 4688c2ecf20Sopenharmony_ci case e1000_pch_mtp: 4698c2ecf20Sopenharmony_ci /* In case the PHY needs to be in mdio slow mode, 4708c2ecf20Sopenharmony_ci * set slow mode and try to get the PHY id again. 4718c2ecf20Sopenharmony_ci */ 4728c2ecf20Sopenharmony_ci ret_val = e1000_set_mdio_slow_mode_hv(hw); 4738c2ecf20Sopenharmony_ci if (ret_val) 4748c2ecf20Sopenharmony_ci return ret_val; 4758c2ecf20Sopenharmony_ci ret_val = e1000e_get_phy_id(hw); 4768c2ecf20Sopenharmony_ci if (ret_val) 4778c2ecf20Sopenharmony_ci return ret_val; 4788c2ecf20Sopenharmony_ci break; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci phy->type = e1000e_get_phy_type_from_id(phy->id); 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci switch (phy->type) { 4838c2ecf20Sopenharmony_ci case e1000_phy_82577: 4848c2ecf20Sopenharmony_ci case e1000_phy_82579: 4858c2ecf20Sopenharmony_ci case e1000_phy_i217: 4868c2ecf20Sopenharmony_ci phy->ops.check_polarity = e1000_check_polarity_82577; 4878c2ecf20Sopenharmony_ci phy->ops.force_speed_duplex = 4888c2ecf20Sopenharmony_ci e1000_phy_force_speed_duplex_82577; 4898c2ecf20Sopenharmony_ci phy->ops.get_cable_length = e1000_get_cable_length_82577; 4908c2ecf20Sopenharmony_ci phy->ops.get_info = e1000_get_phy_info_82577; 4918c2ecf20Sopenharmony_ci phy->ops.commit = e1000e_phy_sw_reset; 4928c2ecf20Sopenharmony_ci break; 4938c2ecf20Sopenharmony_ci case e1000_phy_82578: 4948c2ecf20Sopenharmony_ci phy->ops.check_polarity = e1000_check_polarity_m88; 4958c2ecf20Sopenharmony_ci phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; 4968c2ecf20Sopenharmony_ci phy->ops.get_cable_length = e1000e_get_cable_length_m88; 4978c2ecf20Sopenharmony_ci phy->ops.get_info = e1000e_get_phy_info_m88; 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci default: 5008c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_PHY; 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci return ret_val; 5058c2ecf20Sopenharmony_ci} 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci/** 5088c2ecf20Sopenharmony_ci * e1000_init_phy_params_ich8lan - Initialize PHY function pointers 5098c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 5108c2ecf20Sopenharmony_ci * 5118c2ecf20Sopenharmony_ci * Initialize family-specific PHY parameters and function pointers. 5128c2ecf20Sopenharmony_ci **/ 5138c2ecf20Sopenharmony_cistatic s32 e1000_init_phy_params_ich8lan(struct e1000_hw *hw) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci struct e1000_phy_info *phy = &hw->phy; 5168c2ecf20Sopenharmony_ci s32 ret_val; 5178c2ecf20Sopenharmony_ci u16 i = 0; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci phy->addr = 1; 5208c2ecf20Sopenharmony_ci phy->reset_delay_us = 100; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci phy->ops.power_up = e1000_power_up_phy_copper; 5238c2ecf20Sopenharmony_ci phy->ops.power_down = e1000_power_down_phy_copper_ich8lan; 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci /* We may need to do this twice - once for IGP and if that fails, 5268c2ecf20Sopenharmony_ci * we'll set BM func pointers and try again 5278c2ecf20Sopenharmony_ci */ 5288c2ecf20Sopenharmony_ci ret_val = e1000e_determine_phy_address(hw); 5298c2ecf20Sopenharmony_ci if (ret_val) { 5308c2ecf20Sopenharmony_ci phy->ops.write_reg = e1000e_write_phy_reg_bm; 5318c2ecf20Sopenharmony_ci phy->ops.read_reg = e1000e_read_phy_reg_bm; 5328c2ecf20Sopenharmony_ci ret_val = e1000e_determine_phy_address(hw); 5338c2ecf20Sopenharmony_ci if (ret_val) { 5348c2ecf20Sopenharmony_ci e_dbg("Cannot determine PHY addr. Erroring out\n"); 5358c2ecf20Sopenharmony_ci return ret_val; 5368c2ecf20Sopenharmony_ci } 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci phy->id = 0; 5408c2ecf20Sopenharmony_ci while ((e1000_phy_unknown == e1000e_get_phy_type_from_id(phy->id)) && 5418c2ecf20Sopenharmony_ci (i++ < 100)) { 5428c2ecf20Sopenharmony_ci usleep_range(1000, 1100); 5438c2ecf20Sopenharmony_ci ret_val = e1000e_get_phy_id(hw); 5448c2ecf20Sopenharmony_ci if (ret_val) 5458c2ecf20Sopenharmony_ci return ret_val; 5468c2ecf20Sopenharmony_ci } 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* Verify phy id */ 5498c2ecf20Sopenharmony_ci switch (phy->id) { 5508c2ecf20Sopenharmony_ci case IGP03E1000_E_PHY_ID: 5518c2ecf20Sopenharmony_ci phy->type = e1000_phy_igp_3; 5528c2ecf20Sopenharmony_ci phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 5538c2ecf20Sopenharmony_ci phy->ops.read_reg_locked = e1000e_read_phy_reg_igp_locked; 5548c2ecf20Sopenharmony_ci phy->ops.write_reg_locked = e1000e_write_phy_reg_igp_locked; 5558c2ecf20Sopenharmony_ci phy->ops.get_info = e1000e_get_phy_info_igp; 5568c2ecf20Sopenharmony_ci phy->ops.check_polarity = e1000_check_polarity_igp; 5578c2ecf20Sopenharmony_ci phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_igp; 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci case IFE_E_PHY_ID: 5608c2ecf20Sopenharmony_ci case IFE_PLUS_E_PHY_ID: 5618c2ecf20Sopenharmony_ci case IFE_C_E_PHY_ID: 5628c2ecf20Sopenharmony_ci phy->type = e1000_phy_ife; 5638c2ecf20Sopenharmony_ci phy->autoneg_mask = E1000_ALL_NOT_GIG; 5648c2ecf20Sopenharmony_ci phy->ops.get_info = e1000_get_phy_info_ife; 5658c2ecf20Sopenharmony_ci phy->ops.check_polarity = e1000_check_polarity_ife; 5668c2ecf20Sopenharmony_ci phy->ops.force_speed_duplex = e1000_phy_force_speed_duplex_ife; 5678c2ecf20Sopenharmony_ci break; 5688c2ecf20Sopenharmony_ci case BME1000_E_PHY_ID: 5698c2ecf20Sopenharmony_ci phy->type = e1000_phy_bm; 5708c2ecf20Sopenharmony_ci phy->autoneg_mask = AUTONEG_ADVERTISE_SPEED_DEFAULT; 5718c2ecf20Sopenharmony_ci phy->ops.read_reg = e1000e_read_phy_reg_bm; 5728c2ecf20Sopenharmony_ci phy->ops.write_reg = e1000e_write_phy_reg_bm; 5738c2ecf20Sopenharmony_ci phy->ops.commit = e1000e_phy_sw_reset; 5748c2ecf20Sopenharmony_ci phy->ops.get_info = e1000e_get_phy_info_m88; 5758c2ecf20Sopenharmony_ci phy->ops.check_polarity = e1000_check_polarity_m88; 5768c2ecf20Sopenharmony_ci phy->ops.force_speed_duplex = e1000e_phy_force_speed_duplex_m88; 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci default: 5798c2ecf20Sopenharmony_ci return -E1000_ERR_PHY; 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return 0; 5838c2ecf20Sopenharmony_ci} 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci/** 5868c2ecf20Sopenharmony_ci * e1000_init_nvm_params_ich8lan - Initialize NVM function pointers 5878c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 5888c2ecf20Sopenharmony_ci * 5898c2ecf20Sopenharmony_ci * Initialize family-specific NVM parameters and function 5908c2ecf20Sopenharmony_ci * pointers. 5918c2ecf20Sopenharmony_ci **/ 5928c2ecf20Sopenharmony_cistatic s32 e1000_init_nvm_params_ich8lan(struct e1000_hw *hw) 5938c2ecf20Sopenharmony_ci{ 5948c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 5958c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 5968c2ecf20Sopenharmony_ci u32 gfpreg, sector_base_addr, sector_end_addr; 5978c2ecf20Sopenharmony_ci u16 i; 5988c2ecf20Sopenharmony_ci u32 nvm_size; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci nvm->type = e1000_nvm_flash_sw; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) { 6038c2ecf20Sopenharmony_ci /* in SPT, gfpreg doesn't exist. NVM size is taken from the 6048c2ecf20Sopenharmony_ci * STRAP register. This is because in SPT the GbE Flash region 6058c2ecf20Sopenharmony_ci * is no longer accessed through the flash registers. Instead, 6068c2ecf20Sopenharmony_ci * the mechanism has changed, and the Flash region access 6078c2ecf20Sopenharmony_ci * registers are now implemented in GbE memory space. 6088c2ecf20Sopenharmony_ci */ 6098c2ecf20Sopenharmony_ci nvm->flash_base_addr = 0; 6108c2ecf20Sopenharmony_ci nvm_size = (((er32(STRAP) >> 1) & 0x1F) + 1) 6118c2ecf20Sopenharmony_ci * NVM_SIZE_MULTIPLIER; 6128c2ecf20Sopenharmony_ci nvm->flash_bank_size = nvm_size / 2; 6138c2ecf20Sopenharmony_ci /* Adjust to word count */ 6148c2ecf20Sopenharmony_ci nvm->flash_bank_size /= sizeof(u16); 6158c2ecf20Sopenharmony_ci /* Set the base address for flash register access */ 6168c2ecf20Sopenharmony_ci hw->flash_address = hw->hw_addr + E1000_FLASH_BASE_ADDR; 6178c2ecf20Sopenharmony_ci } else { 6188c2ecf20Sopenharmony_ci /* Can't read flash registers if register set isn't mapped. */ 6198c2ecf20Sopenharmony_ci if (!hw->flash_address) { 6208c2ecf20Sopenharmony_ci e_dbg("ERROR: Flash registers not mapped\n"); 6218c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 6228c2ecf20Sopenharmony_ci } 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci gfpreg = er32flash(ICH_FLASH_GFPREG); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* sector_X_addr is a "sector"-aligned address (4096 bytes) 6278c2ecf20Sopenharmony_ci * Add 1 to sector_end_addr since this sector is included in 6288c2ecf20Sopenharmony_ci * the overall size. 6298c2ecf20Sopenharmony_ci */ 6308c2ecf20Sopenharmony_ci sector_base_addr = gfpreg & FLASH_GFPREG_BASE_MASK; 6318c2ecf20Sopenharmony_ci sector_end_addr = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK) + 1; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci /* flash_base_addr is byte-aligned */ 6348c2ecf20Sopenharmony_ci nvm->flash_base_addr = sector_base_addr 6358c2ecf20Sopenharmony_ci << FLASH_SECTOR_ADDR_SHIFT; 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_ci /* find total size of the NVM, then cut in half since the total 6388c2ecf20Sopenharmony_ci * size represents two separate NVM banks. 6398c2ecf20Sopenharmony_ci */ 6408c2ecf20Sopenharmony_ci nvm->flash_bank_size = ((sector_end_addr - sector_base_addr) 6418c2ecf20Sopenharmony_ci << FLASH_SECTOR_ADDR_SHIFT); 6428c2ecf20Sopenharmony_ci nvm->flash_bank_size /= 2; 6438c2ecf20Sopenharmony_ci /* Adjust to word count */ 6448c2ecf20Sopenharmony_ci nvm->flash_bank_size /= sizeof(u16); 6458c2ecf20Sopenharmony_ci } 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_ci nvm->word_size = E1000_ICH8_SHADOW_RAM_WORDS; 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci /* Clear shadow ram */ 6508c2ecf20Sopenharmony_ci for (i = 0; i < nvm->word_size; i++) { 6518c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].modified = false; 6528c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].value = 0xFFFF; 6538c2ecf20Sopenharmony_ci } 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci return 0; 6568c2ecf20Sopenharmony_ci} 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci/** 6598c2ecf20Sopenharmony_ci * e1000_init_mac_params_ich8lan - Initialize MAC function pointers 6608c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 6618c2ecf20Sopenharmony_ci * 6628c2ecf20Sopenharmony_ci * Initialize family-specific MAC parameters and function 6638c2ecf20Sopenharmony_ci * pointers. 6648c2ecf20Sopenharmony_ci **/ 6658c2ecf20Sopenharmony_cistatic s32 e1000_init_mac_params_ich8lan(struct e1000_hw *hw) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 6688c2ecf20Sopenharmony_ci 6698c2ecf20Sopenharmony_ci /* Set media type function pointer */ 6708c2ecf20Sopenharmony_ci hw->phy.media_type = e1000_media_type_copper; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci /* Set mta register count */ 6738c2ecf20Sopenharmony_ci mac->mta_reg_count = 32; 6748c2ecf20Sopenharmony_ci /* Set rar entry count */ 6758c2ecf20Sopenharmony_ci mac->rar_entry_count = E1000_ICH_RAR_ENTRIES; 6768c2ecf20Sopenharmony_ci if (mac->type == e1000_ich8lan) 6778c2ecf20Sopenharmony_ci mac->rar_entry_count--; 6788c2ecf20Sopenharmony_ci /* FWSM register */ 6798c2ecf20Sopenharmony_ci mac->has_fwsm = true; 6808c2ecf20Sopenharmony_ci /* ARC subsystem not supported */ 6818c2ecf20Sopenharmony_ci mac->arc_subsystem_valid = false; 6828c2ecf20Sopenharmony_ci /* Adaptive IFS supported */ 6838c2ecf20Sopenharmony_ci mac->adaptive_ifs = true; 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* LED and other operations */ 6868c2ecf20Sopenharmony_ci switch (mac->type) { 6878c2ecf20Sopenharmony_ci case e1000_ich8lan: 6888c2ecf20Sopenharmony_ci case e1000_ich9lan: 6898c2ecf20Sopenharmony_ci case e1000_ich10lan: 6908c2ecf20Sopenharmony_ci /* check management mode */ 6918c2ecf20Sopenharmony_ci mac->ops.check_mng_mode = e1000_check_mng_mode_ich8lan; 6928c2ecf20Sopenharmony_ci /* ID LED init */ 6938c2ecf20Sopenharmony_ci mac->ops.id_led_init = e1000e_id_led_init_generic; 6948c2ecf20Sopenharmony_ci /* blink LED */ 6958c2ecf20Sopenharmony_ci mac->ops.blink_led = e1000e_blink_led_generic; 6968c2ecf20Sopenharmony_ci /* setup LED */ 6978c2ecf20Sopenharmony_ci mac->ops.setup_led = e1000e_setup_led_generic; 6988c2ecf20Sopenharmony_ci /* cleanup LED */ 6998c2ecf20Sopenharmony_ci mac->ops.cleanup_led = e1000_cleanup_led_ich8lan; 7008c2ecf20Sopenharmony_ci /* turn on/off LED */ 7018c2ecf20Sopenharmony_ci mac->ops.led_on = e1000_led_on_ich8lan; 7028c2ecf20Sopenharmony_ci mac->ops.led_off = e1000_led_off_ich8lan; 7038c2ecf20Sopenharmony_ci break; 7048c2ecf20Sopenharmony_ci case e1000_pch2lan: 7058c2ecf20Sopenharmony_ci mac->rar_entry_count = E1000_PCH2_RAR_ENTRIES; 7068c2ecf20Sopenharmony_ci mac->ops.rar_set = e1000_rar_set_pch2lan; 7078c2ecf20Sopenharmony_ci fallthrough; 7088c2ecf20Sopenharmony_ci case e1000_pch_lpt: 7098c2ecf20Sopenharmony_ci case e1000_pch_spt: 7108c2ecf20Sopenharmony_ci case e1000_pch_cnp: 7118c2ecf20Sopenharmony_ci case e1000_pch_tgp: 7128c2ecf20Sopenharmony_ci case e1000_pch_adp: 7138c2ecf20Sopenharmony_ci case e1000_pch_mtp: 7148c2ecf20Sopenharmony_ci case e1000_pchlan: 7158c2ecf20Sopenharmony_ci /* check management mode */ 7168c2ecf20Sopenharmony_ci mac->ops.check_mng_mode = e1000_check_mng_mode_pchlan; 7178c2ecf20Sopenharmony_ci /* ID LED init */ 7188c2ecf20Sopenharmony_ci mac->ops.id_led_init = e1000_id_led_init_pchlan; 7198c2ecf20Sopenharmony_ci /* setup LED */ 7208c2ecf20Sopenharmony_ci mac->ops.setup_led = e1000_setup_led_pchlan; 7218c2ecf20Sopenharmony_ci /* cleanup LED */ 7228c2ecf20Sopenharmony_ci mac->ops.cleanup_led = e1000_cleanup_led_pchlan; 7238c2ecf20Sopenharmony_ci /* turn on/off LED */ 7248c2ecf20Sopenharmony_ci mac->ops.led_on = e1000_led_on_pchlan; 7258c2ecf20Sopenharmony_ci mac->ops.led_off = e1000_led_off_pchlan; 7268c2ecf20Sopenharmony_ci break; 7278c2ecf20Sopenharmony_ci default: 7288c2ecf20Sopenharmony_ci break; 7298c2ecf20Sopenharmony_ci } 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (mac->type >= e1000_pch_lpt) { 7328c2ecf20Sopenharmony_ci mac->rar_entry_count = E1000_PCH_LPT_RAR_ENTRIES; 7338c2ecf20Sopenharmony_ci mac->ops.rar_set = e1000_rar_set_pch_lpt; 7348c2ecf20Sopenharmony_ci mac->ops.setup_physical_interface = 7358c2ecf20Sopenharmony_ci e1000_setup_copper_link_pch_lpt; 7368c2ecf20Sopenharmony_ci mac->ops.rar_get_count = e1000_rar_get_count_pch_lpt; 7378c2ecf20Sopenharmony_ci } 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* Enable PCS Lock-loss workaround for ICH8 */ 7408c2ecf20Sopenharmony_ci if (mac->type == e1000_ich8lan) 7418c2ecf20Sopenharmony_ci e1000e_set_kmrn_lock_loss_workaround_ich8lan(hw, true); 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci return 0; 7448c2ecf20Sopenharmony_ci} 7458c2ecf20Sopenharmony_ci 7468c2ecf20Sopenharmony_ci/** 7478c2ecf20Sopenharmony_ci * __e1000_access_emi_reg_locked - Read/write EMI register 7488c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7498c2ecf20Sopenharmony_ci * @address: EMI address to program 7508c2ecf20Sopenharmony_ci * @data: pointer to value to read/write from/to the EMI address 7518c2ecf20Sopenharmony_ci * @read: boolean flag to indicate read or write 7528c2ecf20Sopenharmony_ci * 7538c2ecf20Sopenharmony_ci * This helper function assumes the SW/FW/HW Semaphore is already acquired. 7548c2ecf20Sopenharmony_ci **/ 7558c2ecf20Sopenharmony_cistatic s32 __e1000_access_emi_reg_locked(struct e1000_hw *hw, u16 address, 7568c2ecf20Sopenharmony_ci u16 *data, bool read) 7578c2ecf20Sopenharmony_ci{ 7588c2ecf20Sopenharmony_ci s32 ret_val; 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, I82579_EMI_ADDR, address); 7618c2ecf20Sopenharmony_ci if (ret_val) 7628c2ecf20Sopenharmony_ci return ret_val; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci if (read) 7658c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, I82579_EMI_DATA, data); 7668c2ecf20Sopenharmony_ci else 7678c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, I82579_EMI_DATA, *data); 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci return ret_val; 7708c2ecf20Sopenharmony_ci} 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci/** 7738c2ecf20Sopenharmony_ci * e1000_read_emi_reg_locked - Read Extended Management Interface register 7748c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7758c2ecf20Sopenharmony_ci * @addr: EMI address to program 7768c2ecf20Sopenharmony_ci * @data: value to be read from the EMI address 7778c2ecf20Sopenharmony_ci * 7788c2ecf20Sopenharmony_ci * Assumes the SW/FW/HW Semaphore is already acquired. 7798c2ecf20Sopenharmony_ci **/ 7808c2ecf20Sopenharmony_cis32 e1000_read_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 *data) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci return __e1000_access_emi_reg_locked(hw, addr, data, true); 7838c2ecf20Sopenharmony_ci} 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci/** 7868c2ecf20Sopenharmony_ci * e1000_write_emi_reg_locked - Write Extended Management Interface register 7878c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 7888c2ecf20Sopenharmony_ci * @addr: EMI address to program 7898c2ecf20Sopenharmony_ci * @data: value to be written to the EMI address 7908c2ecf20Sopenharmony_ci * 7918c2ecf20Sopenharmony_ci * Assumes the SW/FW/HW Semaphore is already acquired. 7928c2ecf20Sopenharmony_ci **/ 7938c2ecf20Sopenharmony_cis32 e1000_write_emi_reg_locked(struct e1000_hw *hw, u16 addr, u16 data) 7948c2ecf20Sopenharmony_ci{ 7958c2ecf20Sopenharmony_ci return __e1000_access_emi_reg_locked(hw, addr, &data, false); 7968c2ecf20Sopenharmony_ci} 7978c2ecf20Sopenharmony_ci 7988c2ecf20Sopenharmony_ci/** 7998c2ecf20Sopenharmony_ci * e1000_set_eee_pchlan - Enable/disable EEE support 8008c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 8018c2ecf20Sopenharmony_ci * 8028c2ecf20Sopenharmony_ci * Enable/disable EEE based on setting in dev_spec structure, the duplex of 8038c2ecf20Sopenharmony_ci * the link and the EEE capabilities of the link partner. The LPI Control 8048c2ecf20Sopenharmony_ci * register bits will remain set only if/when link is up. 8058c2ecf20Sopenharmony_ci * 8068c2ecf20Sopenharmony_ci * EEE LPI must not be asserted earlier than one second after link is up. 8078c2ecf20Sopenharmony_ci * On 82579, EEE LPI should not be enabled until such time otherwise there 8088c2ecf20Sopenharmony_ci * can be link issues with some switches. Other devices can have EEE LPI 8098c2ecf20Sopenharmony_ci * enabled immediately upon link up since they have a timer in hardware which 8108c2ecf20Sopenharmony_ci * prevents LPI from being asserted too early. 8118c2ecf20Sopenharmony_ci **/ 8128c2ecf20Sopenharmony_cis32 e1000_set_eee_pchlan(struct e1000_hw *hw) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 8158c2ecf20Sopenharmony_ci s32 ret_val; 8168c2ecf20Sopenharmony_ci u16 lpa, pcs_status, adv, adv_addr, lpi_ctrl, data; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci switch (hw->phy.type) { 8198c2ecf20Sopenharmony_ci case e1000_phy_82579: 8208c2ecf20Sopenharmony_ci lpa = I82579_EEE_LP_ABILITY; 8218c2ecf20Sopenharmony_ci pcs_status = I82579_EEE_PCS_STATUS; 8228c2ecf20Sopenharmony_ci adv_addr = I82579_EEE_ADVERTISEMENT; 8238c2ecf20Sopenharmony_ci break; 8248c2ecf20Sopenharmony_ci case e1000_phy_i217: 8258c2ecf20Sopenharmony_ci lpa = I217_EEE_LP_ABILITY; 8268c2ecf20Sopenharmony_ci pcs_status = I217_EEE_PCS_STATUS; 8278c2ecf20Sopenharmony_ci adv_addr = I217_EEE_ADVERTISEMENT; 8288c2ecf20Sopenharmony_ci break; 8298c2ecf20Sopenharmony_ci default: 8308c2ecf20Sopenharmony_ci return 0; 8318c2ecf20Sopenharmony_ci } 8328c2ecf20Sopenharmony_ci 8338c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 8348c2ecf20Sopenharmony_ci if (ret_val) 8358c2ecf20Sopenharmony_ci return ret_val; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, I82579_LPI_CTRL, &lpi_ctrl); 8388c2ecf20Sopenharmony_ci if (ret_val) 8398c2ecf20Sopenharmony_ci goto release; 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci /* Clear bits that enable EEE in various speeds */ 8428c2ecf20Sopenharmony_ci lpi_ctrl &= ~I82579_LPI_CTRL_ENABLE_MASK; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci /* Enable EEE if not disabled by user */ 8458c2ecf20Sopenharmony_ci if (!dev_spec->eee_disable) { 8468c2ecf20Sopenharmony_ci /* Save off link partner's EEE ability */ 8478c2ecf20Sopenharmony_ci ret_val = e1000_read_emi_reg_locked(hw, lpa, 8488c2ecf20Sopenharmony_ci &dev_spec->eee_lp_ability); 8498c2ecf20Sopenharmony_ci if (ret_val) 8508c2ecf20Sopenharmony_ci goto release; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci /* Read EEE advertisement */ 8538c2ecf20Sopenharmony_ci ret_val = e1000_read_emi_reg_locked(hw, adv_addr, &adv); 8548c2ecf20Sopenharmony_ci if (ret_val) 8558c2ecf20Sopenharmony_ci goto release; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* Enable EEE only for speeds in which the link partner is 8588c2ecf20Sopenharmony_ci * EEE capable and for which we advertise EEE. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci if (adv & dev_spec->eee_lp_ability & I82579_EEE_1000_SUPPORTED) 8618c2ecf20Sopenharmony_ci lpi_ctrl |= I82579_LPI_CTRL_1000_ENABLE; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci if (adv & dev_spec->eee_lp_ability & I82579_EEE_100_SUPPORTED) { 8648c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, MII_LPA, &data); 8658c2ecf20Sopenharmony_ci if (data & LPA_100FULL) 8668c2ecf20Sopenharmony_ci lpi_ctrl |= I82579_LPI_CTRL_100_ENABLE; 8678c2ecf20Sopenharmony_ci else 8688c2ecf20Sopenharmony_ci /* EEE is not supported in 100Half, so ignore 8698c2ecf20Sopenharmony_ci * partner's EEE in 100 ability if full-duplex 8708c2ecf20Sopenharmony_ci * is not advertised. 8718c2ecf20Sopenharmony_ci */ 8728c2ecf20Sopenharmony_ci dev_spec->eee_lp_ability &= 8738c2ecf20Sopenharmony_ci ~I82579_EEE_100_SUPPORTED; 8748c2ecf20Sopenharmony_ci } 8758c2ecf20Sopenharmony_ci } 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82579) { 8788c2ecf20Sopenharmony_ci ret_val = e1000_read_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 8798c2ecf20Sopenharmony_ci &data); 8808c2ecf20Sopenharmony_ci if (ret_val) 8818c2ecf20Sopenharmony_ci goto release; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci data &= ~I82579_LPI_100_PLL_SHUT; 8848c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, I82579_LPI_PLL_SHUT, 8858c2ecf20Sopenharmony_ci data); 8868c2ecf20Sopenharmony_ci } 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* R/Clr IEEE MMD 3.1 bits 11:10 - Tx/Rx LPI Received */ 8898c2ecf20Sopenharmony_ci ret_val = e1000_read_emi_reg_locked(hw, pcs_status, &data); 8908c2ecf20Sopenharmony_ci if (ret_val) 8918c2ecf20Sopenharmony_ci goto release; 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, I82579_LPI_CTRL, lpi_ctrl); 8948c2ecf20Sopenharmony_cirelease: 8958c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 8968c2ecf20Sopenharmony_ci 8978c2ecf20Sopenharmony_ci return ret_val; 8988c2ecf20Sopenharmony_ci} 8998c2ecf20Sopenharmony_ci 9008c2ecf20Sopenharmony_ci/** 9018c2ecf20Sopenharmony_ci * e1000_k1_workaround_lpt_lp - K1 workaround on Lynxpoint-LP 9028c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 9038c2ecf20Sopenharmony_ci * @link: link up bool flag 9048c2ecf20Sopenharmony_ci * 9058c2ecf20Sopenharmony_ci * When K1 is enabled for 1Gbps, the MAC can miss 2 DMA completion indications 9068c2ecf20Sopenharmony_ci * preventing further DMA write requests. Workaround the issue by disabling 9078c2ecf20Sopenharmony_ci * the de-assertion of the clock request when in 1Gpbs mode. 9088c2ecf20Sopenharmony_ci * Also, set appropriate Tx re-transmission timeouts for 10 and 100Half link 9098c2ecf20Sopenharmony_ci * speeds in order to avoid Tx hangs. 9108c2ecf20Sopenharmony_ci **/ 9118c2ecf20Sopenharmony_cistatic s32 e1000_k1_workaround_lpt_lp(struct e1000_hw *hw, bool link) 9128c2ecf20Sopenharmony_ci{ 9138c2ecf20Sopenharmony_ci u32 fextnvm6 = er32(FEXTNVM6); 9148c2ecf20Sopenharmony_ci u32 status = er32(STATUS); 9158c2ecf20Sopenharmony_ci s32 ret_val = 0; 9168c2ecf20Sopenharmony_ci u16 reg; 9178c2ecf20Sopenharmony_ci 9188c2ecf20Sopenharmony_ci if (link && (status & E1000_STATUS_SPEED_1000)) { 9198c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 9208c2ecf20Sopenharmony_ci if (ret_val) 9218c2ecf20Sopenharmony_ci return ret_val; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ret_val = 9248c2ecf20Sopenharmony_ci e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 9258c2ecf20Sopenharmony_ci ®); 9268c2ecf20Sopenharmony_ci if (ret_val) 9278c2ecf20Sopenharmony_ci goto release; 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci ret_val = 9308c2ecf20Sopenharmony_ci e1000e_write_kmrn_reg_locked(hw, 9318c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_K1_CONFIG, 9328c2ecf20Sopenharmony_ci reg & 9338c2ecf20Sopenharmony_ci ~E1000_KMRNCTRLSTA_K1_ENABLE); 9348c2ecf20Sopenharmony_ci if (ret_val) 9358c2ecf20Sopenharmony_ci goto release; 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci usleep_range(10, 20); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci ew32(FEXTNVM6, fextnvm6 | E1000_FEXTNVM6_REQ_PLL_CLK); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci ret_val = 9428c2ecf20Sopenharmony_ci e1000e_write_kmrn_reg_locked(hw, 9438c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_K1_CONFIG, 9448c2ecf20Sopenharmony_ci reg); 9458c2ecf20Sopenharmony_cirelease: 9468c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 9478c2ecf20Sopenharmony_ci } else { 9488c2ecf20Sopenharmony_ci /* clear FEXTNVM6 bit 8 on link down or 10/100 */ 9498c2ecf20Sopenharmony_ci fextnvm6 &= ~E1000_FEXTNVM6_REQ_PLL_CLK; 9508c2ecf20Sopenharmony_ci 9518c2ecf20Sopenharmony_ci if ((hw->phy.revision > 5) || !link || 9528c2ecf20Sopenharmony_ci ((status & E1000_STATUS_SPEED_100) && 9538c2ecf20Sopenharmony_ci (status & E1000_STATUS_FD))) 9548c2ecf20Sopenharmony_ci goto update_fextnvm6; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, I217_INBAND_CTRL, ®); 9578c2ecf20Sopenharmony_ci if (ret_val) 9588c2ecf20Sopenharmony_ci return ret_val; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci /* Clear link status transmit timeout */ 9618c2ecf20Sopenharmony_ci reg &= ~I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_MASK; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci if (status & E1000_STATUS_SPEED_100) { 9648c2ecf20Sopenharmony_ci /* Set inband Tx timeout to 5x10us for 100Half */ 9658c2ecf20Sopenharmony_ci reg |= 5 << I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci /* Do not extend the K1 entry latency for 100Half */ 9688c2ecf20Sopenharmony_ci fextnvm6 &= ~E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 9698c2ecf20Sopenharmony_ci } else { 9708c2ecf20Sopenharmony_ci /* Set inband Tx timeout to 50x10us for 10Full/Half */ 9718c2ecf20Sopenharmony_ci reg |= 50 << 9728c2ecf20Sopenharmony_ci I217_INBAND_CTRL_LINK_STAT_TX_TIMEOUT_SHIFT; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci /* Extend the K1 entry latency for 10 Mbps */ 9758c2ecf20Sopenharmony_ci fextnvm6 |= E1000_FEXTNVM6_ENABLE_K1_ENTRY_CONDITION; 9768c2ecf20Sopenharmony_ci } 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, I217_INBAND_CTRL, reg); 9798c2ecf20Sopenharmony_ci if (ret_val) 9808c2ecf20Sopenharmony_ci return ret_val; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ciupdate_fextnvm6: 9838c2ecf20Sopenharmony_ci ew32(FEXTNVM6, fextnvm6); 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci return ret_val; 9878c2ecf20Sopenharmony_ci} 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci/** 9908c2ecf20Sopenharmony_ci * e1000_platform_pm_pch_lpt - Set platform power management values 9918c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 9928c2ecf20Sopenharmony_ci * @link: bool indicating link status 9938c2ecf20Sopenharmony_ci * 9948c2ecf20Sopenharmony_ci * Set the Latency Tolerance Reporting (LTR) values for the "PCIe-like" 9958c2ecf20Sopenharmony_ci * GbE MAC in the Lynx Point PCH based on Rx buffer size and link speed 9968c2ecf20Sopenharmony_ci * when link is up (which must not exceed the maximum latency supported 9978c2ecf20Sopenharmony_ci * by the platform), otherwise specify there is no LTR requirement. 9988c2ecf20Sopenharmony_ci * Unlike true-PCIe devices which set the LTR maximum snoop/no-snoop 9998c2ecf20Sopenharmony_ci * latencies in the LTR Extended Capability Structure in the PCIe Extended 10008c2ecf20Sopenharmony_ci * Capability register set, on this device LTR is set by writing the 10018c2ecf20Sopenharmony_ci * equivalent snoop/no-snoop latencies in the LTRV register in the MAC and 10028c2ecf20Sopenharmony_ci * set the SEND bit to send an Intel On-chip System Fabric sideband (IOSF-SB) 10038c2ecf20Sopenharmony_ci * message to the PMC. 10048c2ecf20Sopenharmony_ci **/ 10058c2ecf20Sopenharmony_cistatic s32 e1000_platform_pm_pch_lpt(struct e1000_hw *hw, bool link) 10068c2ecf20Sopenharmony_ci{ 10078c2ecf20Sopenharmony_ci u32 reg = link << (E1000_LTRV_REQ_SHIFT + E1000_LTRV_NOSNOOP_SHIFT) | 10088c2ecf20Sopenharmony_ci link << E1000_LTRV_REQ_SHIFT | E1000_LTRV_SEND; 10098c2ecf20Sopenharmony_ci u32 max_ltr_enc_d = 0; /* maximum LTR decoded by platform */ 10108c2ecf20Sopenharmony_ci u32 lat_enc_d = 0; /* latency decoded */ 10118c2ecf20Sopenharmony_ci u16 lat_enc = 0; /* latency encoded */ 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (link) { 10148c2ecf20Sopenharmony_ci u16 speed, duplex, scale = 0; 10158c2ecf20Sopenharmony_ci u16 max_snoop, max_nosnoop; 10168c2ecf20Sopenharmony_ci u16 max_ltr_enc; /* max LTR latency encoded */ 10178c2ecf20Sopenharmony_ci u64 value; 10188c2ecf20Sopenharmony_ci u32 rxa; 10198c2ecf20Sopenharmony_ci 10208c2ecf20Sopenharmony_ci if (!hw->adapter->max_frame_size) { 10218c2ecf20Sopenharmony_ci e_dbg("max_frame_size not set.\n"); 10228c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci hw->mac.ops.get_link_up_info(hw, &speed, &duplex); 10268c2ecf20Sopenharmony_ci if (!speed) { 10278c2ecf20Sopenharmony_ci e_dbg("Speed not set.\n"); 10288c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci /* Rx Packet Buffer Allocation size (KB) */ 10328c2ecf20Sopenharmony_ci rxa = er32(PBA) & E1000_PBA_RXA_MASK; 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci /* Determine the maximum latency tolerated by the device. 10358c2ecf20Sopenharmony_ci * 10368c2ecf20Sopenharmony_ci * Per the PCIe spec, the tolerated latencies are encoded as 10378c2ecf20Sopenharmony_ci * a 3-bit encoded scale (only 0-5 are valid) multiplied by 10388c2ecf20Sopenharmony_ci * a 10-bit value (0-1023) to provide a range from 1 ns to 10398c2ecf20Sopenharmony_ci * 2^25*(2^10-1) ns. The scale is encoded as 0=2^0ns, 10408c2ecf20Sopenharmony_ci * 1=2^5ns, 2=2^10ns,...5=2^25ns. 10418c2ecf20Sopenharmony_ci */ 10428c2ecf20Sopenharmony_ci rxa *= 512; 10438c2ecf20Sopenharmony_ci value = (rxa > hw->adapter->max_frame_size) ? 10448c2ecf20Sopenharmony_ci (rxa - hw->adapter->max_frame_size) * (16000 / speed) : 10458c2ecf20Sopenharmony_ci 0; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci while (value > PCI_LTR_VALUE_MASK) { 10488c2ecf20Sopenharmony_ci scale++; 10498c2ecf20Sopenharmony_ci value = DIV_ROUND_UP(value, BIT(5)); 10508c2ecf20Sopenharmony_ci } 10518c2ecf20Sopenharmony_ci if (scale > E1000_LTRV_SCALE_MAX) { 10528c2ecf20Sopenharmony_ci e_dbg("Invalid LTR latency scale %d\n", scale); 10538c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 10548c2ecf20Sopenharmony_ci } 10558c2ecf20Sopenharmony_ci lat_enc = (u16)((scale << PCI_LTR_SCALE_SHIFT) | value); 10568c2ecf20Sopenharmony_ci 10578c2ecf20Sopenharmony_ci /* Determine the maximum latency tolerated by the platform */ 10588c2ecf20Sopenharmony_ci pci_read_config_word(hw->adapter->pdev, E1000_PCI_LTR_CAP_LPT, 10598c2ecf20Sopenharmony_ci &max_snoop); 10608c2ecf20Sopenharmony_ci pci_read_config_word(hw->adapter->pdev, 10618c2ecf20Sopenharmony_ci E1000_PCI_LTR_CAP_LPT + 2, &max_nosnoop); 10628c2ecf20Sopenharmony_ci max_ltr_enc = max_t(u16, max_snoop, max_nosnoop); 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci lat_enc_d = (lat_enc & E1000_LTRV_VALUE_MASK) * 10658c2ecf20Sopenharmony_ci (1U << (E1000_LTRV_SCALE_FACTOR * 10668c2ecf20Sopenharmony_ci ((lat_enc & E1000_LTRV_SCALE_MASK) 10678c2ecf20Sopenharmony_ci >> E1000_LTRV_SCALE_SHIFT))); 10688c2ecf20Sopenharmony_ci 10698c2ecf20Sopenharmony_ci max_ltr_enc_d = (max_ltr_enc & E1000_LTRV_VALUE_MASK) * 10708c2ecf20Sopenharmony_ci (1U << (E1000_LTRV_SCALE_FACTOR * 10718c2ecf20Sopenharmony_ci ((max_ltr_enc & E1000_LTRV_SCALE_MASK) 10728c2ecf20Sopenharmony_ci >> E1000_LTRV_SCALE_SHIFT))); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (lat_enc_d > max_ltr_enc_d) 10758c2ecf20Sopenharmony_ci lat_enc = max_ltr_enc; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci 10788c2ecf20Sopenharmony_ci /* Set Snoop and No-Snoop latencies the same */ 10798c2ecf20Sopenharmony_ci reg |= lat_enc | (lat_enc << E1000_LTRV_NOSNOOP_SHIFT); 10808c2ecf20Sopenharmony_ci ew32(LTRV, reg); 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci return 0; 10838c2ecf20Sopenharmony_ci} 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci/** 10868c2ecf20Sopenharmony_ci * e1000_enable_ulp_lpt_lp - configure Ultra Low Power mode for LynxPoint-LP 10878c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 10888c2ecf20Sopenharmony_ci * @to_sx: boolean indicating a system power state transition to Sx 10898c2ecf20Sopenharmony_ci * 10908c2ecf20Sopenharmony_ci * When link is down, configure ULP mode to significantly reduce the power 10918c2ecf20Sopenharmony_ci * to the PHY. If on a Manageability Engine (ME) enabled system, tell the 10928c2ecf20Sopenharmony_ci * ME firmware to start the ULP configuration. If not on an ME enabled 10938c2ecf20Sopenharmony_ci * system, configure the ULP mode by software. 10948c2ecf20Sopenharmony_ci */ 10958c2ecf20Sopenharmony_cis32 e1000_enable_ulp_lpt_lp(struct e1000_hw *hw, bool to_sx) 10968c2ecf20Sopenharmony_ci{ 10978c2ecf20Sopenharmony_ci u32 mac_reg; 10988c2ecf20Sopenharmony_ci s32 ret_val = 0; 10998c2ecf20Sopenharmony_ci u16 phy_reg; 11008c2ecf20Sopenharmony_ci u16 oem_reg = 0; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci if ((hw->mac.type < e1000_pch_lpt) || 11038c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || 11048c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || 11058c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || 11068c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || 11078c2ecf20Sopenharmony_ci (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_on)) 11088c2ecf20Sopenharmony_ci return 0; 11098c2ecf20Sopenharmony_ci 11108c2ecf20Sopenharmony_ci if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { 11118c2ecf20Sopenharmony_ci /* Request ME configure ULP mode in the PHY */ 11128c2ecf20Sopenharmony_ci mac_reg = er32(H2ME); 11138c2ecf20Sopenharmony_ci mac_reg |= E1000_H2ME_ULP | E1000_H2ME_ENFORCE_SETTINGS; 11148c2ecf20Sopenharmony_ci ew32(H2ME, mac_reg); 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci goto out; 11178c2ecf20Sopenharmony_ci } 11188c2ecf20Sopenharmony_ci 11198c2ecf20Sopenharmony_ci if (!to_sx) { 11208c2ecf20Sopenharmony_ci int i = 0; 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci /* Poll up to 5 seconds for Cable Disconnected indication */ 11238c2ecf20Sopenharmony_ci while (!(er32(FEXT) & E1000_FEXT_PHY_CABLE_DISCONNECTED)) { 11248c2ecf20Sopenharmony_ci /* Bail if link is re-acquired */ 11258c2ecf20Sopenharmony_ci if (er32(STATUS) & E1000_STATUS_LU) 11268c2ecf20Sopenharmony_ci return -E1000_ERR_PHY; 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci if (i++ == 100) 11298c2ecf20Sopenharmony_ci break; 11308c2ecf20Sopenharmony_ci 11318c2ecf20Sopenharmony_ci msleep(50); 11328c2ecf20Sopenharmony_ci } 11338c2ecf20Sopenharmony_ci e_dbg("CABLE_DISCONNECTED %s set after %dmsec\n", 11348c2ecf20Sopenharmony_ci (er32(FEXT) & 11358c2ecf20Sopenharmony_ci E1000_FEXT_PHY_CABLE_DISCONNECTED) ? "" : "not", i * 50); 11368c2ecf20Sopenharmony_ci } 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 11398c2ecf20Sopenharmony_ci if (ret_val) 11408c2ecf20Sopenharmony_ci goto out; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci /* Force SMBus mode in PHY */ 11438c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 11448c2ecf20Sopenharmony_ci if (ret_val) 11458c2ecf20Sopenharmony_ci goto release; 11468c2ecf20Sopenharmony_ci phy_reg |= CV_SMB_CTRL_FORCE_SMBUS; 11478c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci /* Force SMBus mode in MAC */ 11508c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 11518c2ecf20Sopenharmony_ci mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 11528c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci /* Si workaround for ULP entry flow on i127/rev6 h/w. Enable 11558c2ecf20Sopenharmony_ci * LPLU and disable Gig speed when entering ULP 11568c2ecf20Sopenharmony_ci */ 11578c2ecf20Sopenharmony_ci if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6)) { 11588c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, HV_OEM_BITS, 11598c2ecf20Sopenharmony_ci &oem_reg); 11608c2ecf20Sopenharmony_ci if (ret_val) 11618c2ecf20Sopenharmony_ci goto release; 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_ci phy_reg = oem_reg; 11648c2ecf20Sopenharmony_ci phy_reg |= HV_OEM_BITS_LPLU | HV_OEM_BITS_GBE_DIS; 11658c2ecf20Sopenharmony_ci 11668c2ecf20Sopenharmony_ci ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 11678c2ecf20Sopenharmony_ci phy_reg); 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (ret_val) 11708c2ecf20Sopenharmony_ci goto release; 11718c2ecf20Sopenharmony_ci } 11728c2ecf20Sopenharmony_ci 11738c2ecf20Sopenharmony_ci /* Set Inband ULP Exit, Reset to SMBus mode and 11748c2ecf20Sopenharmony_ci * Disable SMBus Release on PERST# in PHY 11758c2ecf20Sopenharmony_ci */ 11768c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 11778c2ecf20Sopenharmony_ci if (ret_val) 11788c2ecf20Sopenharmony_ci goto release; 11798c2ecf20Sopenharmony_ci phy_reg |= (I218_ULP_CONFIG1_RESET_TO_SMBUS | 11808c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_DISABLE_SMB_PERST); 11818c2ecf20Sopenharmony_ci if (to_sx) { 11828c2ecf20Sopenharmony_ci if (er32(WUFC) & E1000_WUFC_LNKC) 11838c2ecf20Sopenharmony_ci phy_reg |= I218_ULP_CONFIG1_WOL_HOST; 11848c2ecf20Sopenharmony_ci else 11858c2ecf20Sopenharmony_ci phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 11868c2ecf20Sopenharmony_ci 11878c2ecf20Sopenharmony_ci phy_reg |= I218_ULP_CONFIG1_STICKY_ULP; 11888c2ecf20Sopenharmony_ci phy_reg &= ~I218_ULP_CONFIG1_INBAND_EXIT; 11898c2ecf20Sopenharmony_ci } else { 11908c2ecf20Sopenharmony_ci phy_reg |= I218_ULP_CONFIG1_INBAND_EXIT; 11918c2ecf20Sopenharmony_ci phy_reg &= ~I218_ULP_CONFIG1_STICKY_ULP; 11928c2ecf20Sopenharmony_ci phy_reg &= ~I218_ULP_CONFIG1_WOL_HOST; 11938c2ecf20Sopenharmony_ci } 11948c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_ci /* Set Disable SMBus Release on PERST# in MAC */ 11978c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM7); 11988c2ecf20Sopenharmony_ci mac_reg |= E1000_FEXTNVM7_DISABLE_SMB_PERST; 11998c2ecf20Sopenharmony_ci ew32(FEXTNVM7, mac_reg); 12008c2ecf20Sopenharmony_ci 12018c2ecf20Sopenharmony_ci /* Commit ULP changes in PHY by starting auto ULP configuration */ 12028c2ecf20Sopenharmony_ci phy_reg |= I218_ULP_CONFIG1_START; 12038c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if ((hw->phy.type == e1000_phy_i217) && (hw->phy.revision == 6) && 12068c2ecf20Sopenharmony_ci to_sx && (er32(STATUS) & E1000_STATUS_LU)) { 12078c2ecf20Sopenharmony_ci ret_val = e1000_write_phy_reg_hv_locked(hw, HV_OEM_BITS, 12088c2ecf20Sopenharmony_ci oem_reg); 12098c2ecf20Sopenharmony_ci if (ret_val) 12108c2ecf20Sopenharmony_ci goto release; 12118c2ecf20Sopenharmony_ci } 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_cirelease: 12148c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 12158c2ecf20Sopenharmony_ciout: 12168c2ecf20Sopenharmony_ci if (ret_val) 12178c2ecf20Sopenharmony_ci e_dbg("Error in ULP enable flow: %d\n", ret_val); 12188c2ecf20Sopenharmony_ci else 12198c2ecf20Sopenharmony_ci hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_on; 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return ret_val; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci/** 12258c2ecf20Sopenharmony_ci * e1000_disable_ulp_lpt_lp - unconfigure Ultra Low Power mode for LynxPoint-LP 12268c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 12278c2ecf20Sopenharmony_ci * @force: boolean indicating whether or not to force disabling ULP 12288c2ecf20Sopenharmony_ci * 12298c2ecf20Sopenharmony_ci * Un-configure ULP mode when link is up, the system is transitioned from 12308c2ecf20Sopenharmony_ci * Sx or the driver is unloaded. If on a Manageability Engine (ME) enabled 12318c2ecf20Sopenharmony_ci * system, poll for an indication from ME that ULP has been un-configured. 12328c2ecf20Sopenharmony_ci * If not on an ME enabled system, un-configure the ULP mode by software. 12338c2ecf20Sopenharmony_ci * 12348c2ecf20Sopenharmony_ci * During nominal operation, this function is called when link is acquired 12358c2ecf20Sopenharmony_ci * to disable ULP mode (force=false); otherwise, for example when unloading 12368c2ecf20Sopenharmony_ci * the driver or during Sx->S0 transitions, this is called with force=true 12378c2ecf20Sopenharmony_ci * to forcibly disable ULP. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_cistatic s32 e1000_disable_ulp_lpt_lp(struct e1000_hw *hw, bool force) 12408c2ecf20Sopenharmony_ci{ 12418c2ecf20Sopenharmony_ci s32 ret_val = 0; 12428c2ecf20Sopenharmony_ci u32 mac_reg; 12438c2ecf20Sopenharmony_ci u16 phy_reg; 12448c2ecf20Sopenharmony_ci int i = 0; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci if ((hw->mac.type < e1000_pch_lpt) || 12478c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_LM) || 12488c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPT_I217_V) || 12498c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM2) || 12508c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V2) || 12518c2ecf20Sopenharmony_ci (hw->dev_spec.ich8lan.ulp_state == e1000_ulp_state_off)) 12528c2ecf20Sopenharmony_ci return 0; 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci if (er32(FWSM) & E1000_ICH_FWSM_FW_VALID) { 12558c2ecf20Sopenharmony_ci struct e1000_adapter *adapter = hw->adapter; 12568c2ecf20Sopenharmony_ci bool firmware_bug = false; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci if (force) { 12598c2ecf20Sopenharmony_ci /* Request ME un-configure ULP mode in the PHY */ 12608c2ecf20Sopenharmony_ci mac_reg = er32(H2ME); 12618c2ecf20Sopenharmony_ci mac_reg &= ~E1000_H2ME_ULP; 12628c2ecf20Sopenharmony_ci mac_reg |= E1000_H2ME_ENFORCE_SETTINGS; 12638c2ecf20Sopenharmony_ci ew32(H2ME, mac_reg); 12648c2ecf20Sopenharmony_ci } 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci /* Poll up to 2.5 seconds for ME to clear ULP_CFG_DONE. 12678c2ecf20Sopenharmony_ci * If this takes more than 1 second, show a warning indicating a 12688c2ecf20Sopenharmony_ci * firmware bug 12698c2ecf20Sopenharmony_ci */ 12708c2ecf20Sopenharmony_ci while (er32(FWSM) & E1000_FWSM_ULP_CFG_DONE) { 12718c2ecf20Sopenharmony_ci if (i++ == 250) { 12728c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_PHY; 12738c2ecf20Sopenharmony_ci goto out; 12748c2ecf20Sopenharmony_ci } 12758c2ecf20Sopenharmony_ci if (i > 100 && !firmware_bug) 12768c2ecf20Sopenharmony_ci firmware_bug = true; 12778c2ecf20Sopenharmony_ci 12788c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci if (firmware_bug) 12818c2ecf20Sopenharmony_ci e_warn("ULP_CONFIG_DONE took %dmsec. This is a firmware bug\n", i * 10); 12828c2ecf20Sopenharmony_ci else 12838c2ecf20Sopenharmony_ci e_dbg("ULP_CONFIG_DONE cleared after %dmsec\n", i * 10); 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_ci if (force) { 12868c2ecf20Sopenharmony_ci mac_reg = er32(H2ME); 12878c2ecf20Sopenharmony_ci mac_reg &= ~E1000_H2ME_ENFORCE_SETTINGS; 12888c2ecf20Sopenharmony_ci ew32(H2ME, mac_reg); 12898c2ecf20Sopenharmony_ci } else { 12908c2ecf20Sopenharmony_ci /* Clear H2ME.ULP after ME ULP configuration */ 12918c2ecf20Sopenharmony_ci mac_reg = er32(H2ME); 12928c2ecf20Sopenharmony_ci mac_reg &= ~E1000_H2ME_ULP; 12938c2ecf20Sopenharmony_ci ew32(H2ME, mac_reg); 12948c2ecf20Sopenharmony_ci } 12958c2ecf20Sopenharmony_ci 12968c2ecf20Sopenharmony_ci goto out; 12978c2ecf20Sopenharmony_ci } 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 13008c2ecf20Sopenharmony_ci if (ret_val) 13018c2ecf20Sopenharmony_ci goto out; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci if (force) 13048c2ecf20Sopenharmony_ci /* Toggle LANPHYPC Value bit */ 13058c2ecf20Sopenharmony_ci e1000_toggle_lanphypc_pch_lpt(hw); 13068c2ecf20Sopenharmony_ci 13078c2ecf20Sopenharmony_ci /* Unforce SMBus mode in PHY */ 13088c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, &phy_reg); 13098c2ecf20Sopenharmony_ci if (ret_val) { 13108c2ecf20Sopenharmony_ci /* The MAC might be in PCIe mode, so temporarily force to 13118c2ecf20Sopenharmony_ci * SMBus mode in order to access the PHY. 13128c2ecf20Sopenharmony_ci */ 13138c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 13148c2ecf20Sopenharmony_ci mac_reg |= E1000_CTRL_EXT_FORCE_SMBUS; 13158c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ci msleep(50); 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, CV_SMB_CTRL, 13208c2ecf20Sopenharmony_ci &phy_reg); 13218c2ecf20Sopenharmony_ci if (ret_val) 13228c2ecf20Sopenharmony_ci goto release; 13238c2ecf20Sopenharmony_ci } 13248c2ecf20Sopenharmony_ci phy_reg &= ~CV_SMB_CTRL_FORCE_SMBUS; 13258c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, CV_SMB_CTRL, phy_reg); 13268c2ecf20Sopenharmony_ci 13278c2ecf20Sopenharmony_ci /* Unforce SMBus mode in MAC */ 13288c2ecf20Sopenharmony_ci mac_reg = er32(CTRL_EXT); 13298c2ecf20Sopenharmony_ci mac_reg &= ~E1000_CTRL_EXT_FORCE_SMBUS; 13308c2ecf20Sopenharmony_ci ew32(CTRL_EXT, mac_reg); 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci /* When ULP mode was previously entered, K1 was disabled by the 13338c2ecf20Sopenharmony_ci * hardware. Re-Enable K1 in the PHY when exiting ULP. 13348c2ecf20Sopenharmony_ci */ 13358c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, HV_PM_CTRL, &phy_reg); 13368c2ecf20Sopenharmony_ci if (ret_val) 13378c2ecf20Sopenharmony_ci goto release; 13388c2ecf20Sopenharmony_ci phy_reg |= HV_PM_CTRL_K1_ENABLE; 13398c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, HV_PM_CTRL, phy_reg); 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci /* Clear ULP enabled configuration */ 13428c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, &phy_reg); 13438c2ecf20Sopenharmony_ci if (ret_val) 13448c2ecf20Sopenharmony_ci goto release; 13458c2ecf20Sopenharmony_ci phy_reg &= ~(I218_ULP_CONFIG1_IND | 13468c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_STICKY_ULP | 13478c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_RESET_TO_SMBUS | 13488c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_WOL_HOST | 13498c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_INBAND_EXIT | 13508c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_EN_ULP_LANPHYPC | 13518c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_DIS_CLR_STICKY_ON_PERST | 13528c2ecf20Sopenharmony_ci I218_ULP_CONFIG1_DISABLE_SMB_PERST); 13538c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 13548c2ecf20Sopenharmony_ci 13558c2ecf20Sopenharmony_ci /* Commit ULP changes by starting auto ULP configuration */ 13568c2ecf20Sopenharmony_ci phy_reg |= I218_ULP_CONFIG1_START; 13578c2ecf20Sopenharmony_ci e1000_write_phy_reg_hv_locked(hw, I218_ULP_CONFIG1, phy_reg); 13588c2ecf20Sopenharmony_ci 13598c2ecf20Sopenharmony_ci /* Clear Disable SMBus Release on PERST# in MAC */ 13608c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM7); 13618c2ecf20Sopenharmony_ci mac_reg &= ~E1000_FEXTNVM7_DISABLE_SMB_PERST; 13628c2ecf20Sopenharmony_ci ew32(FEXTNVM7, mac_reg); 13638c2ecf20Sopenharmony_ci 13648c2ecf20Sopenharmony_cirelease: 13658c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 13668c2ecf20Sopenharmony_ci if (force) { 13678c2ecf20Sopenharmony_ci e1000_phy_hw_reset(hw); 13688c2ecf20Sopenharmony_ci msleep(50); 13698c2ecf20Sopenharmony_ci } 13708c2ecf20Sopenharmony_ciout: 13718c2ecf20Sopenharmony_ci if (ret_val) 13728c2ecf20Sopenharmony_ci e_dbg("Error in ULP disable flow: %d\n", ret_val); 13738c2ecf20Sopenharmony_ci else 13748c2ecf20Sopenharmony_ci hw->dev_spec.ich8lan.ulp_state = e1000_ulp_state_off; 13758c2ecf20Sopenharmony_ci 13768c2ecf20Sopenharmony_ci return ret_val; 13778c2ecf20Sopenharmony_ci} 13788c2ecf20Sopenharmony_ci 13798c2ecf20Sopenharmony_ci/** 13808c2ecf20Sopenharmony_ci * e1000_check_for_copper_link_ich8lan - Check for link (Copper) 13818c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 13828c2ecf20Sopenharmony_ci * 13838c2ecf20Sopenharmony_ci * Checks to see of the link status of the hardware has changed. If a 13848c2ecf20Sopenharmony_ci * change in link status has been detected, then we read the PHY registers 13858c2ecf20Sopenharmony_ci * to get the current speed/duplex if link exists. 13868c2ecf20Sopenharmony_ci **/ 13878c2ecf20Sopenharmony_cistatic s32 e1000_check_for_copper_link_ich8lan(struct e1000_hw *hw) 13888c2ecf20Sopenharmony_ci{ 13898c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 13908c2ecf20Sopenharmony_ci s32 ret_val, tipg_reg = 0; 13918c2ecf20Sopenharmony_ci u16 emi_addr, emi_val = 0; 13928c2ecf20Sopenharmony_ci bool link; 13938c2ecf20Sopenharmony_ci u16 phy_reg; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci /* We only want to go out to the PHY registers to see if Auto-Neg 13968c2ecf20Sopenharmony_ci * has completed and/or if our link status has changed. The 13978c2ecf20Sopenharmony_ci * get_link_status flag is set upon receiving a Link Status 13988c2ecf20Sopenharmony_ci * Change or Rx Sequence Error interrupt. 13998c2ecf20Sopenharmony_ci */ 14008c2ecf20Sopenharmony_ci if (!mac->get_link_status) 14018c2ecf20Sopenharmony_ci return 0; 14028c2ecf20Sopenharmony_ci mac->get_link_status = false; 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ci /* First we want to see if the MII Status Register reports 14058c2ecf20Sopenharmony_ci * link. If so, then we want to get the current speed/duplex 14068c2ecf20Sopenharmony_ci * of the PHY. 14078c2ecf20Sopenharmony_ci */ 14088c2ecf20Sopenharmony_ci ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); 14098c2ecf20Sopenharmony_ci if (ret_val) 14108c2ecf20Sopenharmony_ci goto out; 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) { 14138c2ecf20Sopenharmony_ci ret_val = e1000_k1_gig_workaround_hv(hw, link); 14148c2ecf20Sopenharmony_ci if (ret_val) 14158c2ecf20Sopenharmony_ci goto out; 14168c2ecf20Sopenharmony_ci } 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci /* When connected at 10Mbps half-duplex, some parts are excessively 14198c2ecf20Sopenharmony_ci * aggressive resulting in many collisions. To avoid this, increase 14208c2ecf20Sopenharmony_ci * the IPG and reduce Rx latency in the PHY. 14218c2ecf20Sopenharmony_ci */ 14228c2ecf20Sopenharmony_ci if ((hw->mac.type >= e1000_pch2lan) && link) { 14238c2ecf20Sopenharmony_ci u16 speed, duplex; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci e1000e_get_speed_and_duplex_copper(hw, &speed, &duplex); 14268c2ecf20Sopenharmony_ci tipg_reg = er32(TIPG); 14278c2ecf20Sopenharmony_ci tipg_reg &= ~E1000_TIPG_IPGT_MASK; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci if (duplex == HALF_DUPLEX && speed == SPEED_10) { 14308c2ecf20Sopenharmony_ci tipg_reg |= 0xFF; 14318c2ecf20Sopenharmony_ci /* Reduce Rx latency in analog PHY */ 14328c2ecf20Sopenharmony_ci emi_val = 0; 14338c2ecf20Sopenharmony_ci } else if (hw->mac.type >= e1000_pch_spt && 14348c2ecf20Sopenharmony_ci duplex == FULL_DUPLEX && speed != SPEED_1000) { 14358c2ecf20Sopenharmony_ci tipg_reg |= 0xC; 14368c2ecf20Sopenharmony_ci emi_val = 1; 14378c2ecf20Sopenharmony_ci } else { 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Roll back the default values */ 14408c2ecf20Sopenharmony_ci tipg_reg |= 0x08; 14418c2ecf20Sopenharmony_ci emi_val = 1; 14428c2ecf20Sopenharmony_ci } 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci ew32(TIPG, tipg_reg); 14458c2ecf20Sopenharmony_ci 14468c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 14478c2ecf20Sopenharmony_ci if (ret_val) 14488c2ecf20Sopenharmony_ci goto out; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pch2lan) 14518c2ecf20Sopenharmony_ci emi_addr = I82579_RX_CONFIG; 14528c2ecf20Sopenharmony_ci else 14538c2ecf20Sopenharmony_ci emi_addr = I217_RX_CONFIG; 14548c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, emi_addr, emi_val); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 14578c2ecf20Sopenharmony_ci u16 phy_reg; 14588c2ecf20Sopenharmony_ci 14598c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_PLL_CLOCK_GATE_REG, &phy_reg); 14608c2ecf20Sopenharmony_ci phy_reg &= ~I217_PLL_CLOCK_GATE_MASK; 14618c2ecf20Sopenharmony_ci if (speed == SPEED_100 || speed == SPEED_10) 14628c2ecf20Sopenharmony_ci phy_reg |= 0x3E8; 14638c2ecf20Sopenharmony_ci else 14648c2ecf20Sopenharmony_ci phy_reg |= 0xFA; 14658c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_PLL_CLOCK_GATE_REG, phy_reg); 14668c2ecf20Sopenharmony_ci 14678c2ecf20Sopenharmony_ci if (speed == SPEED_1000) { 14688c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_locked(hw, HV_PM_CTRL, 14698c2ecf20Sopenharmony_ci &phy_reg); 14708c2ecf20Sopenharmony_ci 14718c2ecf20Sopenharmony_ci phy_reg |= HV_PM_CTRL_K1_CLK_REQ; 14728c2ecf20Sopenharmony_ci 14738c2ecf20Sopenharmony_ci hw->phy.ops.write_reg_locked(hw, HV_PM_CTRL, 14748c2ecf20Sopenharmony_ci phy_reg); 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci } 14778c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci if (ret_val) 14808c2ecf20Sopenharmony_ci goto out; 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) { 14838c2ecf20Sopenharmony_ci u16 data; 14848c2ecf20Sopenharmony_ci u16 ptr_gap; 14858c2ecf20Sopenharmony_ci 14868c2ecf20Sopenharmony_ci if (speed == SPEED_1000) { 14878c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 14888c2ecf20Sopenharmony_ci if (ret_val) 14898c2ecf20Sopenharmony_ci goto out; 14908c2ecf20Sopenharmony_ci 14918c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, 14928c2ecf20Sopenharmony_ci PHY_REG(776, 20), 14938c2ecf20Sopenharmony_ci &data); 14948c2ecf20Sopenharmony_ci if (ret_val) { 14958c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 14968c2ecf20Sopenharmony_ci goto out; 14978c2ecf20Sopenharmony_ci } 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci ptr_gap = (data & (0x3FF << 2)) >> 2; 15008c2ecf20Sopenharmony_ci if (ptr_gap < 0x18) { 15018c2ecf20Sopenharmony_ci data &= ~(0x3FF << 2); 15028c2ecf20Sopenharmony_ci data |= (0x18 << 2); 15038c2ecf20Sopenharmony_ci ret_val = 15048c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, 15058c2ecf20Sopenharmony_ci PHY_REG(776, 20), 15068c2ecf20Sopenharmony_ci data); 15078c2ecf20Sopenharmony_ci } 15088c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 15098c2ecf20Sopenharmony_ci if (ret_val) 15108c2ecf20Sopenharmony_ci goto out; 15118c2ecf20Sopenharmony_ci } else { 15128c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 15138c2ecf20Sopenharmony_ci if (ret_val) 15148c2ecf20Sopenharmony_ci goto out; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, 15178c2ecf20Sopenharmony_ci PHY_REG(776, 20), 15188c2ecf20Sopenharmony_ci 0xC023); 15198c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 15208c2ecf20Sopenharmony_ci if (ret_val) 15218c2ecf20Sopenharmony_ci goto out; 15228c2ecf20Sopenharmony_ci 15238c2ecf20Sopenharmony_ci } 15248c2ecf20Sopenharmony_ci } 15258c2ecf20Sopenharmony_ci } 15268c2ecf20Sopenharmony_ci 15278c2ecf20Sopenharmony_ci /* I217 Packet Loss issue: 15288c2ecf20Sopenharmony_ci * ensure that FEXTNVM4 Beacon Duration is set correctly 15298c2ecf20Sopenharmony_ci * on power up. 15308c2ecf20Sopenharmony_ci * Set the Beacon Duration for I217 to 8 usec 15318c2ecf20Sopenharmony_ci */ 15328c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 15338c2ecf20Sopenharmony_ci u32 mac_reg; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM4); 15368c2ecf20Sopenharmony_ci mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 15378c2ecf20Sopenharmony_ci mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_8USEC; 15388c2ecf20Sopenharmony_ci ew32(FEXTNVM4, mac_reg); 15398c2ecf20Sopenharmony_ci } 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci /* Work-around I218 hang issue */ 15428c2ecf20Sopenharmony_ci if ((hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 15438c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_LPTLP_I218_V) || 15448c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_LM3) || 15458c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_PCH_I218_V3)) { 15468c2ecf20Sopenharmony_ci ret_val = e1000_k1_workaround_lpt_lp(hw, link); 15478c2ecf20Sopenharmony_ci if (ret_val) 15488c2ecf20Sopenharmony_ci goto out; 15498c2ecf20Sopenharmony_ci } 15508c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 15518c2ecf20Sopenharmony_ci /* Set platform power management values for 15528c2ecf20Sopenharmony_ci * Latency Tolerance Reporting (LTR) 15538c2ecf20Sopenharmony_ci */ 15548c2ecf20Sopenharmony_ci ret_val = e1000_platform_pm_pch_lpt(hw, link); 15558c2ecf20Sopenharmony_ci if (ret_val) 15568c2ecf20Sopenharmony_ci goto out; 15578c2ecf20Sopenharmony_ci } 15588c2ecf20Sopenharmony_ci 15598c2ecf20Sopenharmony_ci /* Clear link partner's EEE ability */ 15608c2ecf20Sopenharmony_ci hw->dev_spec.ich8lan.eee_lp_ability = 0; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 15638c2ecf20Sopenharmony_ci u32 fextnvm6 = er32(FEXTNVM6); 15648c2ecf20Sopenharmony_ci 15658c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pch_spt) { 15668c2ecf20Sopenharmony_ci /* FEXTNVM6 K1-off workaround - for SPT only */ 15678c2ecf20Sopenharmony_ci u32 pcieanacfg = er32(PCIEANACFG); 15688c2ecf20Sopenharmony_ci 15698c2ecf20Sopenharmony_ci if (pcieanacfg & E1000_FEXTNVM6_K1_OFF_ENABLE) 15708c2ecf20Sopenharmony_ci fextnvm6 |= E1000_FEXTNVM6_K1_OFF_ENABLE; 15718c2ecf20Sopenharmony_ci else 15728c2ecf20Sopenharmony_ci fextnvm6 &= ~E1000_FEXTNVM6_K1_OFF_ENABLE; 15738c2ecf20Sopenharmony_ci } 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci ew32(FEXTNVM6, fextnvm6); 15768c2ecf20Sopenharmony_ci } 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci if (!link) 15798c2ecf20Sopenharmony_ci goto out; 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_ci switch (hw->mac.type) { 15828c2ecf20Sopenharmony_ci case e1000_pch2lan: 15838c2ecf20Sopenharmony_ci ret_val = e1000_k1_workaround_lv(hw); 15848c2ecf20Sopenharmony_ci if (ret_val) 15858c2ecf20Sopenharmony_ci return ret_val; 15868c2ecf20Sopenharmony_ci fallthrough; 15878c2ecf20Sopenharmony_ci case e1000_pchlan: 15888c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82578) { 15898c2ecf20Sopenharmony_ci ret_val = e1000_link_stall_workaround_hv(hw); 15908c2ecf20Sopenharmony_ci if (ret_val) 15918c2ecf20Sopenharmony_ci return ret_val; 15928c2ecf20Sopenharmony_ci } 15938c2ecf20Sopenharmony_ci 15948c2ecf20Sopenharmony_ci /* Workaround for PCHx parts in half-duplex: 15958c2ecf20Sopenharmony_ci * Set the number of preambles removed from the packet 15968c2ecf20Sopenharmony_ci * when it is passed from the PHY to the MAC to prevent 15978c2ecf20Sopenharmony_ci * the MAC from misinterpreting the packet type. 15988c2ecf20Sopenharmony_ci */ 15998c2ecf20Sopenharmony_ci e1e_rphy(hw, HV_KMRN_FIFO_CTRLSTA, &phy_reg); 16008c2ecf20Sopenharmony_ci phy_reg &= ~HV_KMRN_FIFO_CTRLSTA_PREAMBLE_MASK; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci if ((er32(STATUS) & E1000_STATUS_FD) != E1000_STATUS_FD) 16038c2ecf20Sopenharmony_ci phy_reg |= BIT(HV_KMRN_FIFO_CTRLSTA_PREAMBLE_SHIFT); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, phy_reg); 16068c2ecf20Sopenharmony_ci break; 16078c2ecf20Sopenharmony_ci default: 16088c2ecf20Sopenharmony_ci break; 16098c2ecf20Sopenharmony_ci } 16108c2ecf20Sopenharmony_ci 16118c2ecf20Sopenharmony_ci /* Check if there was DownShift, must be checked 16128c2ecf20Sopenharmony_ci * immediately after link-up 16138c2ecf20Sopenharmony_ci */ 16148c2ecf20Sopenharmony_ci e1000e_check_downshift(hw); 16158c2ecf20Sopenharmony_ci 16168c2ecf20Sopenharmony_ci /* Enable/Disable EEE after link up */ 16178c2ecf20Sopenharmony_ci if (hw->phy.type > e1000_phy_82579) { 16188c2ecf20Sopenharmony_ci ret_val = e1000_set_eee_pchlan(hw); 16198c2ecf20Sopenharmony_ci if (ret_val) 16208c2ecf20Sopenharmony_ci return ret_val; 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* If we are forcing speed/duplex, then we simply return since 16248c2ecf20Sopenharmony_ci * we have already determined whether we have link or not. 16258c2ecf20Sopenharmony_ci */ 16268c2ecf20Sopenharmony_ci if (!mac->autoneg) 16278c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 16288c2ecf20Sopenharmony_ci 16298c2ecf20Sopenharmony_ci /* Auto-Neg is enabled. Auto Speed Detection takes care 16308c2ecf20Sopenharmony_ci * of MAC speed/duplex configuration. So we only need to 16318c2ecf20Sopenharmony_ci * configure Collision Distance in the MAC. 16328c2ecf20Sopenharmony_ci */ 16338c2ecf20Sopenharmony_ci mac->ops.config_collision_dist(hw); 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci /* Configure Flow Control now that Auto-Neg has completed. 16368c2ecf20Sopenharmony_ci * First, we need to restore the desired flow control 16378c2ecf20Sopenharmony_ci * settings because we may have had to re-autoneg with a 16388c2ecf20Sopenharmony_ci * different link partner. 16398c2ecf20Sopenharmony_ci */ 16408c2ecf20Sopenharmony_ci ret_val = e1000e_config_fc_after_link_up(hw); 16418c2ecf20Sopenharmony_ci if (ret_val) 16428c2ecf20Sopenharmony_ci e_dbg("Error configuring flow control\n"); 16438c2ecf20Sopenharmony_ci 16448c2ecf20Sopenharmony_ci return ret_val; 16458c2ecf20Sopenharmony_ci 16468c2ecf20Sopenharmony_ciout: 16478c2ecf20Sopenharmony_ci mac->get_link_status = true; 16488c2ecf20Sopenharmony_ci return ret_val; 16498c2ecf20Sopenharmony_ci} 16508c2ecf20Sopenharmony_ci 16518c2ecf20Sopenharmony_cistatic s32 e1000_get_variants_ich8lan(struct e1000_adapter *adapter) 16528c2ecf20Sopenharmony_ci{ 16538c2ecf20Sopenharmony_ci struct e1000_hw *hw = &adapter->hw; 16548c2ecf20Sopenharmony_ci s32 rc; 16558c2ecf20Sopenharmony_ci 16568c2ecf20Sopenharmony_ci rc = e1000_init_mac_params_ich8lan(hw); 16578c2ecf20Sopenharmony_ci if (rc) 16588c2ecf20Sopenharmony_ci return rc; 16598c2ecf20Sopenharmony_ci 16608c2ecf20Sopenharmony_ci rc = e1000_init_nvm_params_ich8lan(hw); 16618c2ecf20Sopenharmony_ci if (rc) 16628c2ecf20Sopenharmony_ci return rc; 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci switch (hw->mac.type) { 16658c2ecf20Sopenharmony_ci case e1000_ich8lan: 16668c2ecf20Sopenharmony_ci case e1000_ich9lan: 16678c2ecf20Sopenharmony_ci case e1000_ich10lan: 16688c2ecf20Sopenharmony_ci rc = e1000_init_phy_params_ich8lan(hw); 16698c2ecf20Sopenharmony_ci break; 16708c2ecf20Sopenharmony_ci case e1000_pchlan: 16718c2ecf20Sopenharmony_ci case e1000_pch2lan: 16728c2ecf20Sopenharmony_ci case e1000_pch_lpt: 16738c2ecf20Sopenharmony_ci case e1000_pch_spt: 16748c2ecf20Sopenharmony_ci case e1000_pch_cnp: 16758c2ecf20Sopenharmony_ci case e1000_pch_tgp: 16768c2ecf20Sopenharmony_ci case e1000_pch_adp: 16778c2ecf20Sopenharmony_ci case e1000_pch_mtp: 16788c2ecf20Sopenharmony_ci rc = e1000_init_phy_params_pchlan(hw); 16798c2ecf20Sopenharmony_ci break; 16808c2ecf20Sopenharmony_ci default: 16818c2ecf20Sopenharmony_ci break; 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci if (rc) 16848c2ecf20Sopenharmony_ci return rc; 16858c2ecf20Sopenharmony_ci 16868c2ecf20Sopenharmony_ci /* Disable Jumbo Frame support on parts with Intel 10/100 PHY or 16878c2ecf20Sopenharmony_ci * on parts with MACsec enabled in NVM (reflected in CTRL_EXT). 16888c2ecf20Sopenharmony_ci */ 16898c2ecf20Sopenharmony_ci if ((adapter->hw.phy.type == e1000_phy_ife) || 16908c2ecf20Sopenharmony_ci ((adapter->hw.mac.type >= e1000_pch2lan) && 16918c2ecf20Sopenharmony_ci (!(er32(CTRL_EXT) & E1000_CTRL_EXT_LSECCK)))) { 16928c2ecf20Sopenharmony_ci adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; 16938c2ecf20Sopenharmony_ci adapter->max_hw_frame_size = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN; 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ci hw->mac.ops.blink_led = NULL; 16968c2ecf20Sopenharmony_ci } 16978c2ecf20Sopenharmony_ci 16988c2ecf20Sopenharmony_ci if ((adapter->hw.mac.type == e1000_ich8lan) && 16998c2ecf20Sopenharmony_ci (adapter->hw.phy.type != e1000_phy_ife)) 17008c2ecf20Sopenharmony_ci adapter->flags |= FLAG_LSC_GIG_SPEED_DROP; 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_ci /* Enable workaround for 82579 w/ ME enabled */ 17038c2ecf20Sopenharmony_ci if ((adapter->hw.mac.type == e1000_pch2lan) && 17048c2ecf20Sopenharmony_ci (er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) 17058c2ecf20Sopenharmony_ci adapter->flags2 |= FLAG2_PCIM2PCI_ARBITER_WA; 17068c2ecf20Sopenharmony_ci 17078c2ecf20Sopenharmony_ci return 0; 17088c2ecf20Sopenharmony_ci} 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(nvm_mutex); 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci/** 17138c2ecf20Sopenharmony_ci * e1000_acquire_nvm_ich8lan - Acquire NVM mutex 17148c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 17158c2ecf20Sopenharmony_ci * 17168c2ecf20Sopenharmony_ci * Acquires the mutex for performing NVM operations. 17178c2ecf20Sopenharmony_ci **/ 17188c2ecf20Sopenharmony_cistatic s32 e1000_acquire_nvm_ich8lan(struct e1000_hw __always_unused *hw) 17198c2ecf20Sopenharmony_ci{ 17208c2ecf20Sopenharmony_ci mutex_lock(&nvm_mutex); 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci return 0; 17238c2ecf20Sopenharmony_ci} 17248c2ecf20Sopenharmony_ci 17258c2ecf20Sopenharmony_ci/** 17268c2ecf20Sopenharmony_ci * e1000_release_nvm_ich8lan - Release NVM mutex 17278c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 17288c2ecf20Sopenharmony_ci * 17298c2ecf20Sopenharmony_ci * Releases the mutex used while performing NVM operations. 17308c2ecf20Sopenharmony_ci **/ 17318c2ecf20Sopenharmony_cistatic void e1000_release_nvm_ich8lan(struct e1000_hw __always_unused *hw) 17328c2ecf20Sopenharmony_ci{ 17338c2ecf20Sopenharmony_ci mutex_unlock(&nvm_mutex); 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci/** 17378c2ecf20Sopenharmony_ci * e1000_acquire_swflag_ich8lan - Acquire software control flag 17388c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 17398c2ecf20Sopenharmony_ci * 17408c2ecf20Sopenharmony_ci * Acquires the software control flag for performing PHY and select 17418c2ecf20Sopenharmony_ci * MAC CSR accesses. 17428c2ecf20Sopenharmony_ci **/ 17438c2ecf20Sopenharmony_cistatic s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci u32 extcnf_ctrl, timeout = PHY_CFG_TIMEOUT; 17468c2ecf20Sopenharmony_ci s32 ret_val = 0; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (test_and_set_bit(__E1000_ACCESS_SHARED_RESOURCE, 17498c2ecf20Sopenharmony_ci &hw->adapter->state)) { 17508c2ecf20Sopenharmony_ci e_dbg("contention for Phy access\n"); 17518c2ecf20Sopenharmony_ci return -E1000_ERR_PHY; 17528c2ecf20Sopenharmony_ci } 17538c2ecf20Sopenharmony_ci 17548c2ecf20Sopenharmony_ci while (timeout) { 17558c2ecf20Sopenharmony_ci extcnf_ctrl = er32(EXTCNF_CTRL); 17568c2ecf20Sopenharmony_ci if (!(extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG)) 17578c2ecf20Sopenharmony_ci break; 17588c2ecf20Sopenharmony_ci 17598c2ecf20Sopenharmony_ci mdelay(1); 17608c2ecf20Sopenharmony_ci timeout--; 17618c2ecf20Sopenharmony_ci } 17628c2ecf20Sopenharmony_ci 17638c2ecf20Sopenharmony_ci if (!timeout) { 17648c2ecf20Sopenharmony_ci e_dbg("SW has already locked the resource.\n"); 17658c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 17668c2ecf20Sopenharmony_ci goto out; 17678c2ecf20Sopenharmony_ci } 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci timeout = SW_FLAG_TIMEOUT; 17708c2ecf20Sopenharmony_ci 17718c2ecf20Sopenharmony_ci extcnf_ctrl |= E1000_EXTCNF_CTRL_SWFLAG; 17728c2ecf20Sopenharmony_ci ew32(EXTCNF_CTRL, extcnf_ctrl); 17738c2ecf20Sopenharmony_ci 17748c2ecf20Sopenharmony_ci while (timeout) { 17758c2ecf20Sopenharmony_ci extcnf_ctrl = er32(EXTCNF_CTRL); 17768c2ecf20Sopenharmony_ci if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) 17778c2ecf20Sopenharmony_ci break; 17788c2ecf20Sopenharmony_ci 17798c2ecf20Sopenharmony_ci mdelay(1); 17808c2ecf20Sopenharmony_ci timeout--; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (!timeout) { 17848c2ecf20Sopenharmony_ci e_dbg("Failed to acquire the semaphore, FW or HW has it: FWSM=0x%8.8x EXTCNF_CTRL=0x%8.8x)\n", 17858c2ecf20Sopenharmony_ci er32(FWSM), extcnf_ctrl); 17868c2ecf20Sopenharmony_ci extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 17878c2ecf20Sopenharmony_ci ew32(EXTCNF_CTRL, extcnf_ctrl); 17888c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 17898c2ecf20Sopenharmony_ci goto out; 17908c2ecf20Sopenharmony_ci } 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ciout: 17938c2ecf20Sopenharmony_ci if (ret_val) 17948c2ecf20Sopenharmony_ci clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci return ret_val; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci/** 18008c2ecf20Sopenharmony_ci * e1000_release_swflag_ich8lan - Release software control flag 18018c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 18028c2ecf20Sopenharmony_ci * 18038c2ecf20Sopenharmony_ci * Releases the software control flag for performing PHY and select 18048c2ecf20Sopenharmony_ci * MAC CSR accesses. 18058c2ecf20Sopenharmony_ci **/ 18068c2ecf20Sopenharmony_cistatic void e1000_release_swflag_ich8lan(struct e1000_hw *hw) 18078c2ecf20Sopenharmony_ci{ 18088c2ecf20Sopenharmony_ci u32 extcnf_ctrl; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci extcnf_ctrl = er32(EXTCNF_CTRL); 18118c2ecf20Sopenharmony_ci 18128c2ecf20Sopenharmony_ci if (extcnf_ctrl & E1000_EXTCNF_CTRL_SWFLAG) { 18138c2ecf20Sopenharmony_ci extcnf_ctrl &= ~E1000_EXTCNF_CTRL_SWFLAG; 18148c2ecf20Sopenharmony_ci ew32(EXTCNF_CTRL, extcnf_ctrl); 18158c2ecf20Sopenharmony_ci } else { 18168c2ecf20Sopenharmony_ci e_dbg("Semaphore unexpectedly released by sw/fw/hw\n"); 18178c2ecf20Sopenharmony_ci } 18188c2ecf20Sopenharmony_ci 18198c2ecf20Sopenharmony_ci clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state); 18208c2ecf20Sopenharmony_ci} 18218c2ecf20Sopenharmony_ci 18228c2ecf20Sopenharmony_ci/** 18238c2ecf20Sopenharmony_ci * e1000_check_mng_mode_ich8lan - Checks management mode 18248c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 18258c2ecf20Sopenharmony_ci * 18268c2ecf20Sopenharmony_ci * This checks if the adapter has any manageability enabled. 18278c2ecf20Sopenharmony_ci * This is a function pointer entry point only called by read/write 18288c2ecf20Sopenharmony_ci * routines for the PHY and NVM parts. 18298c2ecf20Sopenharmony_ci **/ 18308c2ecf20Sopenharmony_cistatic bool e1000_check_mng_mode_ich8lan(struct e1000_hw *hw) 18318c2ecf20Sopenharmony_ci{ 18328c2ecf20Sopenharmony_ci u32 fwsm; 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci fwsm = er32(FWSM); 18358c2ecf20Sopenharmony_ci return (fwsm & E1000_ICH_FWSM_FW_VALID) && 18368c2ecf20Sopenharmony_ci ((fwsm & E1000_FWSM_MODE_MASK) == 18378c2ecf20Sopenharmony_ci (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 18388c2ecf20Sopenharmony_ci} 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci/** 18418c2ecf20Sopenharmony_ci * e1000_check_mng_mode_pchlan - Checks management mode 18428c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 18438c2ecf20Sopenharmony_ci * 18448c2ecf20Sopenharmony_ci * This checks if the adapter has iAMT enabled. 18458c2ecf20Sopenharmony_ci * This is a function pointer entry point only called by read/write 18468c2ecf20Sopenharmony_ci * routines for the PHY and NVM parts. 18478c2ecf20Sopenharmony_ci **/ 18488c2ecf20Sopenharmony_cistatic bool e1000_check_mng_mode_pchlan(struct e1000_hw *hw) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci u32 fwsm; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci fwsm = er32(FWSM); 18538c2ecf20Sopenharmony_ci return (fwsm & E1000_ICH_FWSM_FW_VALID) && 18548c2ecf20Sopenharmony_ci (fwsm & (E1000_ICH_MNG_IAMT_MODE << E1000_FWSM_MODE_SHIFT)); 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci/** 18588c2ecf20Sopenharmony_ci * e1000_rar_set_pch2lan - Set receive address register 18598c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 18608c2ecf20Sopenharmony_ci * @addr: pointer to the receive address 18618c2ecf20Sopenharmony_ci * @index: receive address array register 18628c2ecf20Sopenharmony_ci * 18638c2ecf20Sopenharmony_ci * Sets the receive address array register at index to the address passed 18648c2ecf20Sopenharmony_ci * in by addr. For 82579, RAR[0] is the base address register that is to 18658c2ecf20Sopenharmony_ci * contain the MAC address but RAR[1-6] are reserved for manageability (ME). 18668c2ecf20Sopenharmony_ci * Use SHRA[0-3] in place of those reserved for ME. 18678c2ecf20Sopenharmony_ci **/ 18688c2ecf20Sopenharmony_cistatic int e1000_rar_set_pch2lan(struct e1000_hw *hw, u8 *addr, u32 index) 18698c2ecf20Sopenharmony_ci{ 18708c2ecf20Sopenharmony_ci u32 rar_low, rar_high; 18718c2ecf20Sopenharmony_ci 18728c2ecf20Sopenharmony_ci /* HW expects these in little endian so we reverse the byte order 18738c2ecf20Sopenharmony_ci * from network order (big endian) to little endian 18748c2ecf20Sopenharmony_ci */ 18758c2ecf20Sopenharmony_ci rar_low = ((u32)addr[0] | 18768c2ecf20Sopenharmony_ci ((u32)addr[1] << 8) | 18778c2ecf20Sopenharmony_ci ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); 18788c2ecf20Sopenharmony_ci 18798c2ecf20Sopenharmony_ci rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); 18808c2ecf20Sopenharmony_ci 18818c2ecf20Sopenharmony_ci /* If MAC address zero, no need to set the AV bit */ 18828c2ecf20Sopenharmony_ci if (rar_low || rar_high) 18838c2ecf20Sopenharmony_ci rar_high |= E1000_RAH_AV; 18848c2ecf20Sopenharmony_ci 18858c2ecf20Sopenharmony_ci if (index == 0) { 18868c2ecf20Sopenharmony_ci ew32(RAL(index), rar_low); 18878c2ecf20Sopenharmony_ci e1e_flush(); 18888c2ecf20Sopenharmony_ci ew32(RAH(index), rar_high); 18898c2ecf20Sopenharmony_ci e1e_flush(); 18908c2ecf20Sopenharmony_ci return 0; 18918c2ecf20Sopenharmony_ci } 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_ci /* RAR[1-6] are owned by manageability. Skip those and program the 18948c2ecf20Sopenharmony_ci * next address into the SHRA register array. 18958c2ecf20Sopenharmony_ci */ 18968c2ecf20Sopenharmony_ci if (index < (u32)(hw->mac.rar_entry_count)) { 18978c2ecf20Sopenharmony_ci s32 ret_val; 18988c2ecf20Sopenharmony_ci 18998c2ecf20Sopenharmony_ci ret_val = e1000_acquire_swflag_ich8lan(hw); 19008c2ecf20Sopenharmony_ci if (ret_val) 19018c2ecf20Sopenharmony_ci goto out; 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_ci ew32(SHRAL(index - 1), rar_low); 19048c2ecf20Sopenharmony_ci e1e_flush(); 19058c2ecf20Sopenharmony_ci ew32(SHRAH(index - 1), rar_high); 19068c2ecf20Sopenharmony_ci e1e_flush(); 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_ci e1000_release_swflag_ich8lan(hw); 19098c2ecf20Sopenharmony_ci 19108c2ecf20Sopenharmony_ci /* verify the register updates */ 19118c2ecf20Sopenharmony_ci if ((er32(SHRAL(index - 1)) == rar_low) && 19128c2ecf20Sopenharmony_ci (er32(SHRAH(index - 1)) == rar_high)) 19138c2ecf20Sopenharmony_ci return 0; 19148c2ecf20Sopenharmony_ci 19158c2ecf20Sopenharmony_ci e_dbg("SHRA[%d] might be locked by ME - FWSM=0x%8.8x\n", 19168c2ecf20Sopenharmony_ci (index - 1), er32(FWSM)); 19178c2ecf20Sopenharmony_ci } 19188c2ecf20Sopenharmony_ci 19198c2ecf20Sopenharmony_ciout: 19208c2ecf20Sopenharmony_ci e_dbg("Failed to write receive address at index %d\n", index); 19218c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 19228c2ecf20Sopenharmony_ci} 19238c2ecf20Sopenharmony_ci 19248c2ecf20Sopenharmony_ci/** 19258c2ecf20Sopenharmony_ci * e1000_rar_get_count_pch_lpt - Get the number of available SHRA 19268c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 19278c2ecf20Sopenharmony_ci * 19288c2ecf20Sopenharmony_ci * Get the number of available receive registers that the Host can 19298c2ecf20Sopenharmony_ci * program. SHRA[0-10] are the shared receive address registers 19308c2ecf20Sopenharmony_ci * that are shared between the Host and manageability engine (ME). 19318c2ecf20Sopenharmony_ci * ME can reserve any number of addresses and the host needs to be 19328c2ecf20Sopenharmony_ci * able to tell how many available registers it has access to. 19338c2ecf20Sopenharmony_ci **/ 19348c2ecf20Sopenharmony_cistatic u32 e1000_rar_get_count_pch_lpt(struct e1000_hw *hw) 19358c2ecf20Sopenharmony_ci{ 19368c2ecf20Sopenharmony_ci u32 wlock_mac; 19378c2ecf20Sopenharmony_ci u32 num_entries; 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci wlock_mac = er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK; 19408c2ecf20Sopenharmony_ci wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT; 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_ci switch (wlock_mac) { 19438c2ecf20Sopenharmony_ci case 0: 19448c2ecf20Sopenharmony_ci /* All SHRA[0..10] and RAR[0] available */ 19458c2ecf20Sopenharmony_ci num_entries = hw->mac.rar_entry_count; 19468c2ecf20Sopenharmony_ci break; 19478c2ecf20Sopenharmony_ci case 1: 19488c2ecf20Sopenharmony_ci /* Only RAR[0] available */ 19498c2ecf20Sopenharmony_ci num_entries = 1; 19508c2ecf20Sopenharmony_ci break; 19518c2ecf20Sopenharmony_ci default: 19528c2ecf20Sopenharmony_ci /* SHRA[0..(wlock_mac - 1)] available + RAR[0] */ 19538c2ecf20Sopenharmony_ci num_entries = wlock_mac + 1; 19548c2ecf20Sopenharmony_ci break; 19558c2ecf20Sopenharmony_ci } 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci return num_entries; 19588c2ecf20Sopenharmony_ci} 19598c2ecf20Sopenharmony_ci 19608c2ecf20Sopenharmony_ci/** 19618c2ecf20Sopenharmony_ci * e1000_rar_set_pch_lpt - Set receive address registers 19628c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 19638c2ecf20Sopenharmony_ci * @addr: pointer to the receive address 19648c2ecf20Sopenharmony_ci * @index: receive address array register 19658c2ecf20Sopenharmony_ci * 19668c2ecf20Sopenharmony_ci * Sets the receive address register array at index to the address passed 19678c2ecf20Sopenharmony_ci * in by addr. For LPT, RAR[0] is the base address register that is to 19688c2ecf20Sopenharmony_ci * contain the MAC address. SHRA[0-10] are the shared receive address 19698c2ecf20Sopenharmony_ci * registers that are shared between the Host and manageability engine (ME). 19708c2ecf20Sopenharmony_ci **/ 19718c2ecf20Sopenharmony_cistatic int e1000_rar_set_pch_lpt(struct e1000_hw *hw, u8 *addr, u32 index) 19728c2ecf20Sopenharmony_ci{ 19738c2ecf20Sopenharmony_ci u32 rar_low, rar_high; 19748c2ecf20Sopenharmony_ci u32 wlock_mac; 19758c2ecf20Sopenharmony_ci 19768c2ecf20Sopenharmony_ci /* HW expects these in little endian so we reverse the byte order 19778c2ecf20Sopenharmony_ci * from network order (big endian) to little endian 19788c2ecf20Sopenharmony_ci */ 19798c2ecf20Sopenharmony_ci rar_low = ((u32)addr[0] | ((u32)addr[1] << 8) | 19808c2ecf20Sopenharmony_ci ((u32)addr[2] << 16) | ((u32)addr[3] << 24)); 19818c2ecf20Sopenharmony_ci 19828c2ecf20Sopenharmony_ci rar_high = ((u32)addr[4] | ((u32)addr[5] << 8)); 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci /* If MAC address zero, no need to set the AV bit */ 19858c2ecf20Sopenharmony_ci if (rar_low || rar_high) 19868c2ecf20Sopenharmony_ci rar_high |= E1000_RAH_AV; 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci if (index == 0) { 19898c2ecf20Sopenharmony_ci ew32(RAL(index), rar_low); 19908c2ecf20Sopenharmony_ci e1e_flush(); 19918c2ecf20Sopenharmony_ci ew32(RAH(index), rar_high); 19928c2ecf20Sopenharmony_ci e1e_flush(); 19938c2ecf20Sopenharmony_ci return 0; 19948c2ecf20Sopenharmony_ci } 19958c2ecf20Sopenharmony_ci 19968c2ecf20Sopenharmony_ci /* The manageability engine (ME) can lock certain SHRAR registers that 19978c2ecf20Sopenharmony_ci * it is using - those registers are unavailable for use. 19988c2ecf20Sopenharmony_ci */ 19998c2ecf20Sopenharmony_ci if (index < hw->mac.rar_entry_count) { 20008c2ecf20Sopenharmony_ci wlock_mac = er32(FWSM) & E1000_FWSM_WLOCK_MAC_MASK; 20018c2ecf20Sopenharmony_ci wlock_mac >>= E1000_FWSM_WLOCK_MAC_SHIFT; 20028c2ecf20Sopenharmony_ci 20038c2ecf20Sopenharmony_ci /* Check if all SHRAR registers are locked */ 20048c2ecf20Sopenharmony_ci if (wlock_mac == 1) 20058c2ecf20Sopenharmony_ci goto out; 20068c2ecf20Sopenharmony_ci 20078c2ecf20Sopenharmony_ci if ((wlock_mac == 0) || (index <= wlock_mac)) { 20088c2ecf20Sopenharmony_ci s32 ret_val; 20098c2ecf20Sopenharmony_ci 20108c2ecf20Sopenharmony_ci ret_val = e1000_acquire_swflag_ich8lan(hw); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci if (ret_val) 20138c2ecf20Sopenharmony_ci goto out; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci ew32(SHRAL_PCH_LPT(index - 1), rar_low); 20168c2ecf20Sopenharmony_ci e1e_flush(); 20178c2ecf20Sopenharmony_ci ew32(SHRAH_PCH_LPT(index - 1), rar_high); 20188c2ecf20Sopenharmony_ci e1e_flush(); 20198c2ecf20Sopenharmony_ci 20208c2ecf20Sopenharmony_ci e1000_release_swflag_ich8lan(hw); 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_ci /* verify the register updates */ 20238c2ecf20Sopenharmony_ci if ((er32(SHRAL_PCH_LPT(index - 1)) == rar_low) && 20248c2ecf20Sopenharmony_ci (er32(SHRAH_PCH_LPT(index - 1)) == rar_high)) 20258c2ecf20Sopenharmony_ci return 0; 20268c2ecf20Sopenharmony_ci } 20278c2ecf20Sopenharmony_ci } 20288c2ecf20Sopenharmony_ci 20298c2ecf20Sopenharmony_ciout: 20308c2ecf20Sopenharmony_ci e_dbg("Failed to write receive address at index %d\n", index); 20318c2ecf20Sopenharmony_ci return -E1000_ERR_CONFIG; 20328c2ecf20Sopenharmony_ci} 20338c2ecf20Sopenharmony_ci 20348c2ecf20Sopenharmony_ci/** 20358c2ecf20Sopenharmony_ci * e1000_check_reset_block_ich8lan - Check if PHY reset is blocked 20368c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 20378c2ecf20Sopenharmony_ci * 20388c2ecf20Sopenharmony_ci * Checks if firmware is blocking the reset of the PHY. 20398c2ecf20Sopenharmony_ci * This is a function pointer entry point only called by 20408c2ecf20Sopenharmony_ci * reset routines. 20418c2ecf20Sopenharmony_ci **/ 20428c2ecf20Sopenharmony_cistatic s32 e1000_check_reset_block_ich8lan(struct e1000_hw *hw) 20438c2ecf20Sopenharmony_ci{ 20448c2ecf20Sopenharmony_ci bool blocked = false; 20458c2ecf20Sopenharmony_ci int i = 0; 20468c2ecf20Sopenharmony_ci 20478c2ecf20Sopenharmony_ci while ((blocked = !(er32(FWSM) & E1000_ICH_FWSM_RSPCIPHY)) && 20488c2ecf20Sopenharmony_ci (i++ < 30)) 20498c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 20508c2ecf20Sopenharmony_ci return blocked ? E1000_BLK_PHY_RESET : 0; 20518c2ecf20Sopenharmony_ci} 20528c2ecf20Sopenharmony_ci 20538c2ecf20Sopenharmony_ci/** 20548c2ecf20Sopenharmony_ci * e1000_write_smbus_addr - Write SMBus address to PHY needed during Sx states 20558c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 20568c2ecf20Sopenharmony_ci * 20578c2ecf20Sopenharmony_ci * Assumes semaphore already acquired. 20588c2ecf20Sopenharmony_ci * 20598c2ecf20Sopenharmony_ci **/ 20608c2ecf20Sopenharmony_cistatic s32 e1000_write_smbus_addr(struct e1000_hw *hw) 20618c2ecf20Sopenharmony_ci{ 20628c2ecf20Sopenharmony_ci u16 phy_data; 20638c2ecf20Sopenharmony_ci u32 strap = er32(STRAP); 20648c2ecf20Sopenharmony_ci u32 freq = (strap & E1000_STRAP_SMT_FREQ_MASK) >> 20658c2ecf20Sopenharmony_ci E1000_STRAP_SMT_FREQ_SHIFT; 20668c2ecf20Sopenharmony_ci s32 ret_val; 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ci strap &= E1000_STRAP_SMBUS_ADDRESS_MASK; 20698c2ecf20Sopenharmony_ci 20708c2ecf20Sopenharmony_ci ret_val = e1000_read_phy_reg_hv_locked(hw, HV_SMB_ADDR, &phy_data); 20718c2ecf20Sopenharmony_ci if (ret_val) 20728c2ecf20Sopenharmony_ci return ret_val; 20738c2ecf20Sopenharmony_ci 20748c2ecf20Sopenharmony_ci phy_data &= ~HV_SMB_ADDR_MASK; 20758c2ecf20Sopenharmony_ci phy_data |= (strap >> E1000_STRAP_SMBUS_ADDRESS_SHIFT); 20768c2ecf20Sopenharmony_ci phy_data |= HV_SMB_ADDR_PEC_EN | HV_SMB_ADDR_VALID; 20778c2ecf20Sopenharmony_ci 20788c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_i217) { 20798c2ecf20Sopenharmony_ci /* Restore SMBus frequency */ 20808c2ecf20Sopenharmony_ci if (freq--) { 20818c2ecf20Sopenharmony_ci phy_data &= ~HV_SMB_ADDR_FREQ_MASK; 20828c2ecf20Sopenharmony_ci phy_data |= (freq & BIT(0)) << 20838c2ecf20Sopenharmony_ci HV_SMB_ADDR_FREQ_LOW_SHIFT; 20848c2ecf20Sopenharmony_ci phy_data |= (freq & BIT(1)) << 20858c2ecf20Sopenharmony_ci (HV_SMB_ADDR_FREQ_HIGH_SHIFT - 1); 20868c2ecf20Sopenharmony_ci } else { 20878c2ecf20Sopenharmony_ci e_dbg("Unsupported SMB frequency in PHY\n"); 20888c2ecf20Sopenharmony_ci } 20898c2ecf20Sopenharmony_ci } 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci return e1000_write_phy_reg_hv_locked(hw, HV_SMB_ADDR, phy_data); 20928c2ecf20Sopenharmony_ci} 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci/** 20958c2ecf20Sopenharmony_ci * e1000_sw_lcd_config_ich8lan - SW-based LCD Configuration 20968c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 20978c2ecf20Sopenharmony_ci * 20988c2ecf20Sopenharmony_ci * SW should configure the LCD from the NVM extended configuration region 20998c2ecf20Sopenharmony_ci * as a workaround for certain parts. 21008c2ecf20Sopenharmony_ci **/ 21018c2ecf20Sopenharmony_cistatic s32 e1000_sw_lcd_config_ich8lan(struct e1000_hw *hw) 21028c2ecf20Sopenharmony_ci{ 21038c2ecf20Sopenharmony_ci struct e1000_phy_info *phy = &hw->phy; 21048c2ecf20Sopenharmony_ci u32 i, data, cnf_size, cnf_base_addr, sw_cfg_mask; 21058c2ecf20Sopenharmony_ci s32 ret_val = 0; 21068c2ecf20Sopenharmony_ci u16 word_addr, reg_data, reg_addr, phy_page = 0; 21078c2ecf20Sopenharmony_ci 21088c2ecf20Sopenharmony_ci /* Initialize the PHY from the NVM on ICH platforms. This 21098c2ecf20Sopenharmony_ci * is needed due to an issue where the NVM configuration is 21108c2ecf20Sopenharmony_ci * not properly autoloaded after power transitions. 21118c2ecf20Sopenharmony_ci * Therefore, after each PHY reset, we will load the 21128c2ecf20Sopenharmony_ci * configuration data out of the NVM manually. 21138c2ecf20Sopenharmony_ci */ 21148c2ecf20Sopenharmony_ci switch (hw->mac.type) { 21158c2ecf20Sopenharmony_ci case e1000_ich8lan: 21168c2ecf20Sopenharmony_ci if (phy->type != e1000_phy_igp_3) 21178c2ecf20Sopenharmony_ci return ret_val; 21188c2ecf20Sopenharmony_ci 21198c2ecf20Sopenharmony_ci if ((hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_AMT) || 21208c2ecf20Sopenharmony_ci (hw->adapter->pdev->device == E1000_DEV_ID_ICH8_IGP_C)) { 21218c2ecf20Sopenharmony_ci sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG; 21228c2ecf20Sopenharmony_ci break; 21238c2ecf20Sopenharmony_ci } 21248c2ecf20Sopenharmony_ci fallthrough; 21258c2ecf20Sopenharmony_ci case e1000_pchlan: 21268c2ecf20Sopenharmony_ci case e1000_pch2lan: 21278c2ecf20Sopenharmony_ci case e1000_pch_lpt: 21288c2ecf20Sopenharmony_ci case e1000_pch_spt: 21298c2ecf20Sopenharmony_ci case e1000_pch_cnp: 21308c2ecf20Sopenharmony_ci case e1000_pch_tgp: 21318c2ecf20Sopenharmony_ci case e1000_pch_adp: 21328c2ecf20Sopenharmony_ci case e1000_pch_mtp: 21338c2ecf20Sopenharmony_ci sw_cfg_mask = E1000_FEXTNVM_SW_CONFIG_ICH8M; 21348c2ecf20Sopenharmony_ci break; 21358c2ecf20Sopenharmony_ci default: 21368c2ecf20Sopenharmony_ci return ret_val; 21378c2ecf20Sopenharmony_ci } 21388c2ecf20Sopenharmony_ci 21398c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 21408c2ecf20Sopenharmony_ci if (ret_val) 21418c2ecf20Sopenharmony_ci return ret_val; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci data = er32(FEXTNVM); 21448c2ecf20Sopenharmony_ci if (!(data & sw_cfg_mask)) 21458c2ecf20Sopenharmony_ci goto release; 21468c2ecf20Sopenharmony_ci 21478c2ecf20Sopenharmony_ci /* Make sure HW does not configure LCD from PHY 21488c2ecf20Sopenharmony_ci * extended configuration before SW configuration 21498c2ecf20Sopenharmony_ci */ 21508c2ecf20Sopenharmony_ci data = er32(EXTCNF_CTRL); 21518c2ecf20Sopenharmony_ci if ((hw->mac.type < e1000_pch2lan) && 21528c2ecf20Sopenharmony_ci (data & E1000_EXTCNF_CTRL_LCD_WRITE_ENABLE)) 21538c2ecf20Sopenharmony_ci goto release; 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci cnf_size = er32(EXTCNF_SIZE); 21568c2ecf20Sopenharmony_ci cnf_size &= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_MASK; 21578c2ecf20Sopenharmony_ci cnf_size >>= E1000_EXTCNF_SIZE_EXT_PCIE_LENGTH_SHIFT; 21588c2ecf20Sopenharmony_ci if (!cnf_size) 21598c2ecf20Sopenharmony_ci goto release; 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_ci cnf_base_addr = data & E1000_EXTCNF_CTRL_EXT_CNF_POINTER_MASK; 21628c2ecf20Sopenharmony_ci cnf_base_addr >>= E1000_EXTCNF_CTRL_EXT_CNF_POINTER_SHIFT; 21638c2ecf20Sopenharmony_ci 21648c2ecf20Sopenharmony_ci if (((hw->mac.type == e1000_pchlan) && 21658c2ecf20Sopenharmony_ci !(data & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE)) || 21668c2ecf20Sopenharmony_ci (hw->mac.type > e1000_pchlan)) { 21678c2ecf20Sopenharmony_ci /* HW configures the SMBus address and LEDs when the 21688c2ecf20Sopenharmony_ci * OEM and LCD Write Enable bits are set in the NVM. 21698c2ecf20Sopenharmony_ci * When both NVM bits are cleared, SW will configure 21708c2ecf20Sopenharmony_ci * them instead. 21718c2ecf20Sopenharmony_ci */ 21728c2ecf20Sopenharmony_ci ret_val = e1000_write_smbus_addr(hw); 21738c2ecf20Sopenharmony_ci if (ret_val) 21748c2ecf20Sopenharmony_ci goto release; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci data = er32(LEDCTL); 21778c2ecf20Sopenharmony_ci ret_val = e1000_write_phy_reg_hv_locked(hw, HV_LED_CONFIG, 21788c2ecf20Sopenharmony_ci (u16)data); 21798c2ecf20Sopenharmony_ci if (ret_val) 21808c2ecf20Sopenharmony_ci goto release; 21818c2ecf20Sopenharmony_ci } 21828c2ecf20Sopenharmony_ci 21838c2ecf20Sopenharmony_ci /* Configure LCD from extended configuration region. */ 21848c2ecf20Sopenharmony_ci 21858c2ecf20Sopenharmony_ci /* cnf_base_addr is in DWORD */ 21868c2ecf20Sopenharmony_ci word_addr = (u16)(cnf_base_addr << 1); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci for (i = 0; i < cnf_size; i++) { 21898c2ecf20Sopenharmony_ci ret_val = e1000_read_nvm(hw, (word_addr + i * 2), 1, ®_data); 21908c2ecf20Sopenharmony_ci if (ret_val) 21918c2ecf20Sopenharmony_ci goto release; 21928c2ecf20Sopenharmony_ci 21938c2ecf20Sopenharmony_ci ret_val = e1000_read_nvm(hw, (word_addr + i * 2 + 1), 21948c2ecf20Sopenharmony_ci 1, ®_addr); 21958c2ecf20Sopenharmony_ci if (ret_val) 21968c2ecf20Sopenharmony_ci goto release; 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci /* Save off the PHY page for future writes. */ 21998c2ecf20Sopenharmony_ci if (reg_addr == IGP01E1000_PHY_PAGE_SELECT) { 22008c2ecf20Sopenharmony_ci phy_page = reg_data; 22018c2ecf20Sopenharmony_ci continue; 22028c2ecf20Sopenharmony_ci } 22038c2ecf20Sopenharmony_ci 22048c2ecf20Sopenharmony_ci reg_addr &= PHY_REG_MASK; 22058c2ecf20Sopenharmony_ci reg_addr |= phy_page; 22068c2ecf20Sopenharmony_ci 22078c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, (u32)reg_addr, reg_data); 22088c2ecf20Sopenharmony_ci if (ret_val) 22098c2ecf20Sopenharmony_ci goto release; 22108c2ecf20Sopenharmony_ci } 22118c2ecf20Sopenharmony_ci 22128c2ecf20Sopenharmony_cirelease: 22138c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 22148c2ecf20Sopenharmony_ci return ret_val; 22158c2ecf20Sopenharmony_ci} 22168c2ecf20Sopenharmony_ci 22178c2ecf20Sopenharmony_ci/** 22188c2ecf20Sopenharmony_ci * e1000_k1_gig_workaround_hv - K1 Si workaround 22198c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 22208c2ecf20Sopenharmony_ci * @link: link up bool flag 22218c2ecf20Sopenharmony_ci * 22228c2ecf20Sopenharmony_ci * If K1 is enabled for 1Gbps, the MAC might stall when transitioning 22238c2ecf20Sopenharmony_ci * from a lower speed. This workaround disables K1 whenever link is at 1Gig 22248c2ecf20Sopenharmony_ci * If link is down, the function will restore the default K1 setting located 22258c2ecf20Sopenharmony_ci * in the NVM. 22268c2ecf20Sopenharmony_ci **/ 22278c2ecf20Sopenharmony_cistatic s32 e1000_k1_gig_workaround_hv(struct e1000_hw *hw, bool link) 22288c2ecf20Sopenharmony_ci{ 22298c2ecf20Sopenharmony_ci s32 ret_val = 0; 22308c2ecf20Sopenharmony_ci u16 status_reg = 0; 22318c2ecf20Sopenharmony_ci bool k1_enable = hw->dev_spec.ich8lan.nvm_k1_enabled; 22328c2ecf20Sopenharmony_ci 22338c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_pchlan) 22348c2ecf20Sopenharmony_ci return 0; 22358c2ecf20Sopenharmony_ci 22368c2ecf20Sopenharmony_ci /* Wrap the whole flow with the sw flag */ 22378c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 22388c2ecf20Sopenharmony_ci if (ret_val) 22398c2ecf20Sopenharmony_ci return ret_val; 22408c2ecf20Sopenharmony_ci 22418c2ecf20Sopenharmony_ci /* Disable K1 when link is 1Gbps, otherwise use the NVM setting */ 22428c2ecf20Sopenharmony_ci if (link) { 22438c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82578) { 22448c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, BM_CS_STATUS, 22458c2ecf20Sopenharmony_ci &status_reg); 22468c2ecf20Sopenharmony_ci if (ret_val) 22478c2ecf20Sopenharmony_ci goto release; 22488c2ecf20Sopenharmony_ci 22498c2ecf20Sopenharmony_ci status_reg &= (BM_CS_STATUS_LINK_UP | 22508c2ecf20Sopenharmony_ci BM_CS_STATUS_RESOLVED | 22518c2ecf20Sopenharmony_ci BM_CS_STATUS_SPEED_MASK); 22528c2ecf20Sopenharmony_ci 22538c2ecf20Sopenharmony_ci if (status_reg == (BM_CS_STATUS_LINK_UP | 22548c2ecf20Sopenharmony_ci BM_CS_STATUS_RESOLVED | 22558c2ecf20Sopenharmony_ci BM_CS_STATUS_SPEED_1000)) 22568c2ecf20Sopenharmony_ci k1_enable = false; 22578c2ecf20Sopenharmony_ci } 22588c2ecf20Sopenharmony_ci 22598c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82577) { 22608c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, HV_M_STATUS, &status_reg); 22618c2ecf20Sopenharmony_ci if (ret_val) 22628c2ecf20Sopenharmony_ci goto release; 22638c2ecf20Sopenharmony_ci 22648c2ecf20Sopenharmony_ci status_reg &= (HV_M_STATUS_LINK_UP | 22658c2ecf20Sopenharmony_ci HV_M_STATUS_AUTONEG_COMPLETE | 22668c2ecf20Sopenharmony_ci HV_M_STATUS_SPEED_MASK); 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_ci if (status_reg == (HV_M_STATUS_LINK_UP | 22698c2ecf20Sopenharmony_ci HV_M_STATUS_AUTONEG_COMPLETE | 22708c2ecf20Sopenharmony_ci HV_M_STATUS_SPEED_1000)) 22718c2ecf20Sopenharmony_ci k1_enable = false; 22728c2ecf20Sopenharmony_ci } 22738c2ecf20Sopenharmony_ci 22748c2ecf20Sopenharmony_ci /* Link stall fix for link up */ 22758c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, PHY_REG(770, 19), 0x0100); 22768c2ecf20Sopenharmony_ci if (ret_val) 22778c2ecf20Sopenharmony_ci goto release; 22788c2ecf20Sopenharmony_ci 22798c2ecf20Sopenharmony_ci } else { 22808c2ecf20Sopenharmony_ci /* Link stall fix for link down */ 22818c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, PHY_REG(770, 19), 0x4100); 22828c2ecf20Sopenharmony_ci if (ret_val) 22838c2ecf20Sopenharmony_ci goto release; 22848c2ecf20Sopenharmony_ci } 22858c2ecf20Sopenharmony_ci 22868c2ecf20Sopenharmony_ci ret_val = e1000_configure_k1_ich8lan(hw, k1_enable); 22878c2ecf20Sopenharmony_ci 22888c2ecf20Sopenharmony_cirelease: 22898c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 22908c2ecf20Sopenharmony_ci 22918c2ecf20Sopenharmony_ci return ret_val; 22928c2ecf20Sopenharmony_ci} 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci/** 22958c2ecf20Sopenharmony_ci * e1000_configure_k1_ich8lan - Configure K1 power state 22968c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 22978c2ecf20Sopenharmony_ci * @k1_enable: K1 state to configure 22988c2ecf20Sopenharmony_ci * 22998c2ecf20Sopenharmony_ci * Configure the K1 power state based on the provided parameter. 23008c2ecf20Sopenharmony_ci * Assumes semaphore already acquired. 23018c2ecf20Sopenharmony_ci * 23028c2ecf20Sopenharmony_ci * Success returns 0, Failure returns -E1000_ERR_PHY (-2) 23038c2ecf20Sopenharmony_ci **/ 23048c2ecf20Sopenharmony_cis32 e1000_configure_k1_ich8lan(struct e1000_hw *hw, bool k1_enable) 23058c2ecf20Sopenharmony_ci{ 23068c2ecf20Sopenharmony_ci s32 ret_val; 23078c2ecf20Sopenharmony_ci u32 ctrl_reg = 0; 23088c2ecf20Sopenharmony_ci u32 ctrl_ext = 0; 23098c2ecf20Sopenharmony_ci u32 reg = 0; 23108c2ecf20Sopenharmony_ci u16 kmrn_reg = 0; 23118c2ecf20Sopenharmony_ci 23128c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 23138c2ecf20Sopenharmony_ci &kmrn_reg); 23148c2ecf20Sopenharmony_ci if (ret_val) 23158c2ecf20Sopenharmony_ci return ret_val; 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci if (k1_enable) 23188c2ecf20Sopenharmony_ci kmrn_reg |= E1000_KMRNCTRLSTA_K1_ENABLE; 23198c2ecf20Sopenharmony_ci else 23208c2ecf20Sopenharmony_ci kmrn_reg &= ~E1000_KMRNCTRLSTA_K1_ENABLE; 23218c2ecf20Sopenharmony_ci 23228c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg_locked(hw, E1000_KMRNCTRLSTA_K1_CONFIG, 23238c2ecf20Sopenharmony_ci kmrn_reg); 23248c2ecf20Sopenharmony_ci if (ret_val) 23258c2ecf20Sopenharmony_ci return ret_val; 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci usleep_range(20, 40); 23288c2ecf20Sopenharmony_ci ctrl_ext = er32(CTRL_EXT); 23298c2ecf20Sopenharmony_ci ctrl_reg = er32(CTRL); 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci reg = ctrl_reg & ~(E1000_CTRL_SPD_1000 | E1000_CTRL_SPD_100); 23328c2ecf20Sopenharmony_ci reg |= E1000_CTRL_FRCSPD; 23338c2ecf20Sopenharmony_ci ew32(CTRL, reg); 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci ew32(CTRL_EXT, ctrl_ext | E1000_CTRL_EXT_SPD_BYPS); 23368c2ecf20Sopenharmony_ci e1e_flush(); 23378c2ecf20Sopenharmony_ci usleep_range(20, 40); 23388c2ecf20Sopenharmony_ci ew32(CTRL, ctrl_reg); 23398c2ecf20Sopenharmony_ci ew32(CTRL_EXT, ctrl_ext); 23408c2ecf20Sopenharmony_ci e1e_flush(); 23418c2ecf20Sopenharmony_ci usleep_range(20, 40); 23428c2ecf20Sopenharmony_ci 23438c2ecf20Sopenharmony_ci return 0; 23448c2ecf20Sopenharmony_ci} 23458c2ecf20Sopenharmony_ci 23468c2ecf20Sopenharmony_ci/** 23478c2ecf20Sopenharmony_ci * e1000_oem_bits_config_ich8lan - SW-based LCD Configuration 23488c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 23498c2ecf20Sopenharmony_ci * @d0_state: boolean if entering d0 or d3 device state 23508c2ecf20Sopenharmony_ci * 23518c2ecf20Sopenharmony_ci * SW will configure Gbe Disable and LPLU based on the NVM. The four bits are 23528c2ecf20Sopenharmony_ci * collectively called OEM bits. The OEM Write Enable bit and SW Config bit 23538c2ecf20Sopenharmony_ci * in NVM determines whether HW should configure LPLU and Gbe Disable. 23548c2ecf20Sopenharmony_ci **/ 23558c2ecf20Sopenharmony_cistatic s32 e1000_oem_bits_config_ich8lan(struct e1000_hw *hw, bool d0_state) 23568c2ecf20Sopenharmony_ci{ 23578c2ecf20Sopenharmony_ci s32 ret_val = 0; 23588c2ecf20Sopenharmony_ci u32 mac_reg; 23598c2ecf20Sopenharmony_ci u16 oem_reg; 23608c2ecf20Sopenharmony_ci 23618c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pchlan) 23628c2ecf20Sopenharmony_ci return ret_val; 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 23658c2ecf20Sopenharmony_ci if (ret_val) 23668c2ecf20Sopenharmony_ci return ret_val; 23678c2ecf20Sopenharmony_ci 23688c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) { 23698c2ecf20Sopenharmony_ci mac_reg = er32(EXTCNF_CTRL); 23708c2ecf20Sopenharmony_ci if (mac_reg & E1000_EXTCNF_CTRL_OEM_WRITE_ENABLE) 23718c2ecf20Sopenharmony_ci goto release; 23728c2ecf20Sopenharmony_ci } 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM); 23758c2ecf20Sopenharmony_ci if (!(mac_reg & E1000_FEXTNVM_SW_CONFIG_ICH8M)) 23768c2ecf20Sopenharmony_ci goto release; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci mac_reg = er32(PHY_CTRL); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, HV_OEM_BITS, &oem_reg); 23818c2ecf20Sopenharmony_ci if (ret_val) 23828c2ecf20Sopenharmony_ci goto release; 23838c2ecf20Sopenharmony_ci 23848c2ecf20Sopenharmony_ci oem_reg &= ~(HV_OEM_BITS_GBE_DIS | HV_OEM_BITS_LPLU); 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci if (d0_state) { 23878c2ecf20Sopenharmony_ci if (mac_reg & E1000_PHY_CTRL_GBE_DISABLE) 23888c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_GBE_DIS; 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci if (mac_reg & E1000_PHY_CTRL_D0A_LPLU) 23918c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_LPLU; 23928c2ecf20Sopenharmony_ci } else { 23938c2ecf20Sopenharmony_ci if (mac_reg & (E1000_PHY_CTRL_GBE_DISABLE | 23948c2ecf20Sopenharmony_ci E1000_PHY_CTRL_NOND0A_GBE_DISABLE)) 23958c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_GBE_DIS; 23968c2ecf20Sopenharmony_ci 23978c2ecf20Sopenharmony_ci if (mac_reg & (E1000_PHY_CTRL_D0A_LPLU | 23988c2ecf20Sopenharmony_ci E1000_PHY_CTRL_NOND0A_LPLU)) 23998c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_LPLU; 24008c2ecf20Sopenharmony_ci } 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci /* Set Restart auto-neg to activate the bits */ 24038c2ecf20Sopenharmony_ci if ((d0_state || (hw->mac.type != e1000_pchlan)) && 24048c2ecf20Sopenharmony_ci !hw->phy.ops.check_reset_block(hw)) 24058c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_RESTART_AN; 24068c2ecf20Sopenharmony_ci 24078c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, HV_OEM_BITS, oem_reg); 24088c2ecf20Sopenharmony_ci 24098c2ecf20Sopenharmony_cirelease: 24108c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 24118c2ecf20Sopenharmony_ci 24128c2ecf20Sopenharmony_ci return ret_val; 24138c2ecf20Sopenharmony_ci} 24148c2ecf20Sopenharmony_ci 24158c2ecf20Sopenharmony_ci/** 24168c2ecf20Sopenharmony_ci * e1000_set_mdio_slow_mode_hv - Set slow MDIO access mode 24178c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 24188c2ecf20Sopenharmony_ci **/ 24198c2ecf20Sopenharmony_cistatic s32 e1000_set_mdio_slow_mode_hv(struct e1000_hw *hw) 24208c2ecf20Sopenharmony_ci{ 24218c2ecf20Sopenharmony_ci s32 ret_val; 24228c2ecf20Sopenharmony_ci u16 data; 24238c2ecf20Sopenharmony_ci 24248c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, HV_KMRN_MODE_CTRL, &data); 24258c2ecf20Sopenharmony_ci if (ret_val) 24268c2ecf20Sopenharmony_ci return ret_val; 24278c2ecf20Sopenharmony_ci 24288c2ecf20Sopenharmony_ci data |= HV_KMRN_MDIO_SLOW; 24298c2ecf20Sopenharmony_ci 24308c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, HV_KMRN_MODE_CTRL, data); 24318c2ecf20Sopenharmony_ci 24328c2ecf20Sopenharmony_ci return ret_val; 24338c2ecf20Sopenharmony_ci} 24348c2ecf20Sopenharmony_ci 24358c2ecf20Sopenharmony_ci/** 24368c2ecf20Sopenharmony_ci * e1000_hv_phy_workarounds_ich8lan - apply PHY workarounds 24378c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 24388c2ecf20Sopenharmony_ci * 24398c2ecf20Sopenharmony_ci * A series of PHY workarounds to be done after every PHY reset. 24408c2ecf20Sopenharmony_ci **/ 24418c2ecf20Sopenharmony_cistatic s32 e1000_hv_phy_workarounds_ich8lan(struct e1000_hw *hw) 24428c2ecf20Sopenharmony_ci{ 24438c2ecf20Sopenharmony_ci s32 ret_val = 0; 24448c2ecf20Sopenharmony_ci u16 phy_data; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_pchlan) 24478c2ecf20Sopenharmony_ci return 0; 24488c2ecf20Sopenharmony_ci 24498c2ecf20Sopenharmony_ci /* Set MDIO slow mode before any other MDIO access */ 24508c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82577) { 24518c2ecf20Sopenharmony_ci ret_val = e1000_set_mdio_slow_mode_hv(hw); 24528c2ecf20Sopenharmony_ci if (ret_val) 24538c2ecf20Sopenharmony_ci return ret_val; 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci if (((hw->phy.type == e1000_phy_82577) && 24578c2ecf20Sopenharmony_ci ((hw->phy.revision == 1) || (hw->phy.revision == 2))) || 24588c2ecf20Sopenharmony_ci ((hw->phy.type == e1000_phy_82578) && (hw->phy.revision == 1))) { 24598c2ecf20Sopenharmony_ci /* Disable generation of early preamble */ 24608c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 25), 0x4431); 24618c2ecf20Sopenharmony_ci if (ret_val) 24628c2ecf20Sopenharmony_ci return ret_val; 24638c2ecf20Sopenharmony_ci 24648c2ecf20Sopenharmony_ci /* Preamble tuning for SSC */ 24658c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, HV_KMRN_FIFO_CTRLSTA, 0xA204); 24668c2ecf20Sopenharmony_ci if (ret_val) 24678c2ecf20Sopenharmony_ci return ret_val; 24688c2ecf20Sopenharmony_ci } 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82578) { 24718c2ecf20Sopenharmony_ci /* Return registers to default by doing a soft reset then 24728c2ecf20Sopenharmony_ci * writing 0x3140 to the control register. 24738c2ecf20Sopenharmony_ci */ 24748c2ecf20Sopenharmony_ci if (hw->phy.revision < 2) { 24758c2ecf20Sopenharmony_ci e1000e_phy_sw_reset(hw); 24768c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, MII_BMCR, 0x3140); 24778c2ecf20Sopenharmony_ci if (ret_val) 24788c2ecf20Sopenharmony_ci return ret_val; 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci } 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci /* Select page 0 */ 24838c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 24848c2ecf20Sopenharmony_ci if (ret_val) 24858c2ecf20Sopenharmony_ci return ret_val; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci hw->phy.addr = 1; 24888c2ecf20Sopenharmony_ci ret_val = e1000e_write_phy_reg_mdic(hw, IGP01E1000_PHY_PAGE_SELECT, 0); 24898c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 24908c2ecf20Sopenharmony_ci if (ret_val) 24918c2ecf20Sopenharmony_ci return ret_val; 24928c2ecf20Sopenharmony_ci 24938c2ecf20Sopenharmony_ci /* Configure the K1 Si workaround during phy reset assuming there is 24948c2ecf20Sopenharmony_ci * link so that it disables K1 if link is in 1Gbps. 24958c2ecf20Sopenharmony_ci */ 24968c2ecf20Sopenharmony_ci ret_val = e1000_k1_gig_workaround_hv(hw, true); 24978c2ecf20Sopenharmony_ci if (ret_val) 24988c2ecf20Sopenharmony_ci return ret_val; 24998c2ecf20Sopenharmony_ci 25008c2ecf20Sopenharmony_ci /* Workaround for link disconnects on a busy hub in half duplex */ 25018c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 25028c2ecf20Sopenharmony_ci if (ret_val) 25038c2ecf20Sopenharmony_ci return ret_val; 25048c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, BM_PORT_GEN_CFG, &phy_data); 25058c2ecf20Sopenharmony_ci if (ret_val) 25068c2ecf20Sopenharmony_ci goto release; 25078c2ecf20Sopenharmony_ci ret_val = e1e_wphy_locked(hw, BM_PORT_GEN_CFG, phy_data & 0x00FF); 25088c2ecf20Sopenharmony_ci if (ret_val) 25098c2ecf20Sopenharmony_ci goto release; 25108c2ecf20Sopenharmony_ci 25118c2ecf20Sopenharmony_ci /* set MSE higher to enable link to stay up when noise is high */ 25128c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, I82577_MSE_THRESHOLD, 0x0034); 25138c2ecf20Sopenharmony_cirelease: 25148c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci return ret_val; 25178c2ecf20Sopenharmony_ci} 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci/** 25208c2ecf20Sopenharmony_ci * e1000_copy_rx_addrs_to_phy_ich8lan - Copy Rx addresses from MAC to PHY 25218c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 25228c2ecf20Sopenharmony_ci **/ 25238c2ecf20Sopenharmony_civoid e1000_copy_rx_addrs_to_phy_ich8lan(struct e1000_hw *hw) 25248c2ecf20Sopenharmony_ci{ 25258c2ecf20Sopenharmony_ci u32 mac_reg; 25268c2ecf20Sopenharmony_ci u16 i, phy_reg = 0; 25278c2ecf20Sopenharmony_ci s32 ret_val; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 25308c2ecf20Sopenharmony_ci if (ret_val) 25318c2ecf20Sopenharmony_ci return; 25328c2ecf20Sopenharmony_ci ret_val = e1000_enable_phy_wakeup_reg_access_bm(hw, &phy_reg); 25338c2ecf20Sopenharmony_ci if (ret_val) 25348c2ecf20Sopenharmony_ci goto release; 25358c2ecf20Sopenharmony_ci 25368c2ecf20Sopenharmony_ci /* Copy both RAL/H (rar_entry_count) and SHRAL/H to PHY */ 25378c2ecf20Sopenharmony_ci for (i = 0; i < (hw->mac.rar_entry_count); i++) { 25388c2ecf20Sopenharmony_ci mac_reg = er32(RAL(i)); 25398c2ecf20Sopenharmony_ci hw->phy.ops.write_reg_page(hw, BM_RAR_L(i), 25408c2ecf20Sopenharmony_ci (u16)(mac_reg & 0xFFFF)); 25418c2ecf20Sopenharmony_ci hw->phy.ops.write_reg_page(hw, BM_RAR_M(i), 25428c2ecf20Sopenharmony_ci (u16)((mac_reg >> 16) & 0xFFFF)); 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_ci mac_reg = er32(RAH(i)); 25458c2ecf20Sopenharmony_ci hw->phy.ops.write_reg_page(hw, BM_RAR_H(i), 25468c2ecf20Sopenharmony_ci (u16)(mac_reg & 0xFFFF)); 25478c2ecf20Sopenharmony_ci hw->phy.ops.write_reg_page(hw, BM_RAR_CTRL(i), 25488c2ecf20Sopenharmony_ci (u16)((mac_reg & E1000_RAH_AV) 25498c2ecf20Sopenharmony_ci >> 16)); 25508c2ecf20Sopenharmony_ci } 25518c2ecf20Sopenharmony_ci 25528c2ecf20Sopenharmony_ci e1000_disable_phy_wakeup_reg_access_bm(hw, &phy_reg); 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_cirelease: 25558c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 25568c2ecf20Sopenharmony_ci} 25578c2ecf20Sopenharmony_ci 25588c2ecf20Sopenharmony_ci/** 25598c2ecf20Sopenharmony_ci * e1000_lv_jumbo_workaround_ich8lan - required for jumbo frame operation 25608c2ecf20Sopenharmony_ci * with 82579 PHY 25618c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 25628c2ecf20Sopenharmony_ci * @enable: flag to enable/disable workaround when enabling/disabling jumbos 25638c2ecf20Sopenharmony_ci **/ 25648c2ecf20Sopenharmony_cis32 e1000_lv_jumbo_workaround_ich8lan(struct e1000_hw *hw, bool enable) 25658c2ecf20Sopenharmony_ci{ 25668c2ecf20Sopenharmony_ci s32 ret_val = 0; 25678c2ecf20Sopenharmony_ci u16 phy_reg, data; 25688c2ecf20Sopenharmony_ci u32 mac_reg; 25698c2ecf20Sopenharmony_ci u16 i; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch2lan) 25728c2ecf20Sopenharmony_ci return 0; 25738c2ecf20Sopenharmony_ci 25748c2ecf20Sopenharmony_ci /* disable Rx path while enabling/disabling workaround */ 25758c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(769, 20), &phy_reg); 25768c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 20), phy_reg | BIT(14)); 25778c2ecf20Sopenharmony_ci if (ret_val) 25788c2ecf20Sopenharmony_ci return ret_val; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci if (enable) { 25818c2ecf20Sopenharmony_ci /* Write Rx addresses (rar_entry_count for RAL/H, and 25828c2ecf20Sopenharmony_ci * SHRAL/H) and initial CRC values to the MAC 25838c2ecf20Sopenharmony_ci */ 25848c2ecf20Sopenharmony_ci for (i = 0; i < hw->mac.rar_entry_count; i++) { 25858c2ecf20Sopenharmony_ci u8 mac_addr[ETH_ALEN] = { 0 }; 25868c2ecf20Sopenharmony_ci u32 addr_high, addr_low; 25878c2ecf20Sopenharmony_ci 25888c2ecf20Sopenharmony_ci addr_high = er32(RAH(i)); 25898c2ecf20Sopenharmony_ci if (!(addr_high & E1000_RAH_AV)) 25908c2ecf20Sopenharmony_ci continue; 25918c2ecf20Sopenharmony_ci addr_low = er32(RAL(i)); 25928c2ecf20Sopenharmony_ci mac_addr[0] = (addr_low & 0xFF); 25938c2ecf20Sopenharmony_ci mac_addr[1] = ((addr_low >> 8) & 0xFF); 25948c2ecf20Sopenharmony_ci mac_addr[2] = ((addr_low >> 16) & 0xFF); 25958c2ecf20Sopenharmony_ci mac_addr[3] = ((addr_low >> 24) & 0xFF); 25968c2ecf20Sopenharmony_ci mac_addr[4] = (addr_high & 0xFF); 25978c2ecf20Sopenharmony_ci mac_addr[5] = ((addr_high >> 8) & 0xFF); 25988c2ecf20Sopenharmony_ci 25998c2ecf20Sopenharmony_ci ew32(PCH_RAICC(i), ~ether_crc_le(ETH_ALEN, mac_addr)); 26008c2ecf20Sopenharmony_ci } 26018c2ecf20Sopenharmony_ci 26028c2ecf20Sopenharmony_ci /* Write Rx addresses to the PHY */ 26038c2ecf20Sopenharmony_ci e1000_copy_rx_addrs_to_phy_ich8lan(hw); 26048c2ecf20Sopenharmony_ci 26058c2ecf20Sopenharmony_ci /* Enable jumbo frame workaround in the MAC */ 26068c2ecf20Sopenharmony_ci mac_reg = er32(FFLT_DBG); 26078c2ecf20Sopenharmony_ci mac_reg &= ~BIT(14); 26088c2ecf20Sopenharmony_ci mac_reg |= (7 << 15); 26098c2ecf20Sopenharmony_ci ew32(FFLT_DBG, mac_reg); 26108c2ecf20Sopenharmony_ci 26118c2ecf20Sopenharmony_ci mac_reg = er32(RCTL); 26128c2ecf20Sopenharmony_ci mac_reg |= E1000_RCTL_SECRC; 26138c2ecf20Sopenharmony_ci ew32(RCTL, mac_reg); 26148c2ecf20Sopenharmony_ci 26158c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, 26168c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_CTRL_OFFSET, 26178c2ecf20Sopenharmony_ci &data); 26188c2ecf20Sopenharmony_ci if (ret_val) 26198c2ecf20Sopenharmony_ci return ret_val; 26208c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, 26218c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_CTRL_OFFSET, 26228c2ecf20Sopenharmony_ci data | BIT(0)); 26238c2ecf20Sopenharmony_ci if (ret_val) 26248c2ecf20Sopenharmony_ci return ret_val; 26258c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, 26268c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_HD_CTRL, 26278c2ecf20Sopenharmony_ci &data); 26288c2ecf20Sopenharmony_ci if (ret_val) 26298c2ecf20Sopenharmony_ci return ret_val; 26308c2ecf20Sopenharmony_ci data &= ~(0xF << 8); 26318c2ecf20Sopenharmony_ci data |= (0xB << 8); 26328c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, 26338c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_HD_CTRL, 26348c2ecf20Sopenharmony_ci data); 26358c2ecf20Sopenharmony_ci if (ret_val) 26368c2ecf20Sopenharmony_ci return ret_val; 26378c2ecf20Sopenharmony_ci 26388c2ecf20Sopenharmony_ci /* Enable jumbo frame workaround in the PHY */ 26398c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(769, 23), &data); 26408c2ecf20Sopenharmony_ci data &= ~(0x7F << 5); 26418c2ecf20Sopenharmony_ci data |= (0x37 << 5); 26428c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 23), data); 26438c2ecf20Sopenharmony_ci if (ret_val) 26448c2ecf20Sopenharmony_ci return ret_val; 26458c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(769, 16), &data); 26468c2ecf20Sopenharmony_ci data &= ~BIT(13); 26478c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 16), data); 26488c2ecf20Sopenharmony_ci if (ret_val) 26498c2ecf20Sopenharmony_ci return ret_val; 26508c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(776, 20), &data); 26518c2ecf20Sopenharmony_ci data &= ~(0x3FF << 2); 26528c2ecf20Sopenharmony_ci data |= (E1000_TX_PTR_GAP << 2); 26538c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(776, 20), data); 26548c2ecf20Sopenharmony_ci if (ret_val) 26558c2ecf20Sopenharmony_ci return ret_val; 26568c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0xF100); 26578c2ecf20Sopenharmony_ci if (ret_val) 26588c2ecf20Sopenharmony_ci return ret_val; 26598c2ecf20Sopenharmony_ci e1e_rphy(hw, HV_PM_CTRL, &data); 26608c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, HV_PM_CTRL, data | BIT(10)); 26618c2ecf20Sopenharmony_ci if (ret_val) 26628c2ecf20Sopenharmony_ci return ret_val; 26638c2ecf20Sopenharmony_ci } else { 26648c2ecf20Sopenharmony_ci /* Write MAC register values back to h/w defaults */ 26658c2ecf20Sopenharmony_ci mac_reg = er32(FFLT_DBG); 26668c2ecf20Sopenharmony_ci mac_reg &= ~(0xF << 14); 26678c2ecf20Sopenharmony_ci ew32(FFLT_DBG, mac_reg); 26688c2ecf20Sopenharmony_ci 26698c2ecf20Sopenharmony_ci mac_reg = er32(RCTL); 26708c2ecf20Sopenharmony_ci mac_reg &= ~E1000_RCTL_SECRC; 26718c2ecf20Sopenharmony_ci ew32(RCTL, mac_reg); 26728c2ecf20Sopenharmony_ci 26738c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, 26748c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_CTRL_OFFSET, 26758c2ecf20Sopenharmony_ci &data); 26768c2ecf20Sopenharmony_ci if (ret_val) 26778c2ecf20Sopenharmony_ci return ret_val; 26788c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, 26798c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_CTRL_OFFSET, 26808c2ecf20Sopenharmony_ci data & ~BIT(0)); 26818c2ecf20Sopenharmony_ci if (ret_val) 26828c2ecf20Sopenharmony_ci return ret_val; 26838c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, 26848c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_HD_CTRL, 26858c2ecf20Sopenharmony_ci &data); 26868c2ecf20Sopenharmony_ci if (ret_val) 26878c2ecf20Sopenharmony_ci return ret_val; 26888c2ecf20Sopenharmony_ci data &= ~(0xF << 8); 26898c2ecf20Sopenharmony_ci data |= (0xB << 8); 26908c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, 26918c2ecf20Sopenharmony_ci E1000_KMRNCTRLSTA_HD_CTRL, 26928c2ecf20Sopenharmony_ci data); 26938c2ecf20Sopenharmony_ci if (ret_val) 26948c2ecf20Sopenharmony_ci return ret_val; 26958c2ecf20Sopenharmony_ci 26968c2ecf20Sopenharmony_ci /* Write PHY register values back to h/w defaults */ 26978c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(769, 23), &data); 26988c2ecf20Sopenharmony_ci data &= ~(0x7F << 5); 26998c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 23), data); 27008c2ecf20Sopenharmony_ci if (ret_val) 27018c2ecf20Sopenharmony_ci return ret_val; 27028c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(769, 16), &data); 27038c2ecf20Sopenharmony_ci data |= BIT(13); 27048c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(769, 16), data); 27058c2ecf20Sopenharmony_ci if (ret_val) 27068c2ecf20Sopenharmony_ci return ret_val; 27078c2ecf20Sopenharmony_ci e1e_rphy(hw, PHY_REG(776, 20), &data); 27088c2ecf20Sopenharmony_ci data &= ~(0x3FF << 2); 27098c2ecf20Sopenharmony_ci data |= (0x8 << 2); 27108c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(776, 20), data); 27118c2ecf20Sopenharmony_ci if (ret_val) 27128c2ecf20Sopenharmony_ci return ret_val; 27138c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(776, 23), 0x7E00); 27148c2ecf20Sopenharmony_ci if (ret_val) 27158c2ecf20Sopenharmony_ci return ret_val; 27168c2ecf20Sopenharmony_ci e1e_rphy(hw, HV_PM_CTRL, &data); 27178c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, HV_PM_CTRL, data & ~BIT(10)); 27188c2ecf20Sopenharmony_ci if (ret_val) 27198c2ecf20Sopenharmony_ci return ret_val; 27208c2ecf20Sopenharmony_ci } 27218c2ecf20Sopenharmony_ci 27228c2ecf20Sopenharmony_ci /* re-enable Rx path after enabling/disabling workaround */ 27238c2ecf20Sopenharmony_ci return e1e_wphy(hw, PHY_REG(769, 20), phy_reg & ~BIT(14)); 27248c2ecf20Sopenharmony_ci} 27258c2ecf20Sopenharmony_ci 27268c2ecf20Sopenharmony_ci/** 27278c2ecf20Sopenharmony_ci * e1000_lv_phy_workarounds_ich8lan - apply ich8 specific workarounds 27288c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 27298c2ecf20Sopenharmony_ci * 27308c2ecf20Sopenharmony_ci * A series of PHY workarounds to be done after every PHY reset. 27318c2ecf20Sopenharmony_ci **/ 27328c2ecf20Sopenharmony_cistatic s32 e1000_lv_phy_workarounds_ich8lan(struct e1000_hw *hw) 27338c2ecf20Sopenharmony_ci{ 27348c2ecf20Sopenharmony_ci s32 ret_val = 0; 27358c2ecf20Sopenharmony_ci 27368c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_pch2lan) 27378c2ecf20Sopenharmony_ci return 0; 27388c2ecf20Sopenharmony_ci 27398c2ecf20Sopenharmony_ci /* Set MDIO slow mode before any other MDIO access */ 27408c2ecf20Sopenharmony_ci ret_val = e1000_set_mdio_slow_mode_hv(hw); 27418c2ecf20Sopenharmony_ci if (ret_val) 27428c2ecf20Sopenharmony_ci return ret_val; 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 27458c2ecf20Sopenharmony_ci if (ret_val) 27468c2ecf20Sopenharmony_ci return ret_val; 27478c2ecf20Sopenharmony_ci /* set MSE higher to enable link to stay up when noise is high */ 27488c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_THRESHOLD, 0x0034); 27498c2ecf20Sopenharmony_ci if (ret_val) 27508c2ecf20Sopenharmony_ci goto release; 27518c2ecf20Sopenharmony_ci /* drop link after 5 times MSE threshold was reached */ 27528c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, I82579_MSE_LINK_DOWN, 0x0005); 27538c2ecf20Sopenharmony_cirelease: 27548c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 27558c2ecf20Sopenharmony_ci 27568c2ecf20Sopenharmony_ci return ret_val; 27578c2ecf20Sopenharmony_ci} 27588c2ecf20Sopenharmony_ci 27598c2ecf20Sopenharmony_ci/** 27608c2ecf20Sopenharmony_ci * e1000_k1_gig_workaround_lv - K1 Si workaround 27618c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 27628c2ecf20Sopenharmony_ci * 27638c2ecf20Sopenharmony_ci * Workaround to set the K1 beacon duration for 82579 parts in 10Mbps 27648c2ecf20Sopenharmony_ci * Disable K1 in 1000Mbps and 100Mbps 27658c2ecf20Sopenharmony_ci **/ 27668c2ecf20Sopenharmony_cistatic s32 e1000_k1_workaround_lv(struct e1000_hw *hw) 27678c2ecf20Sopenharmony_ci{ 27688c2ecf20Sopenharmony_ci s32 ret_val = 0; 27698c2ecf20Sopenharmony_ci u16 status_reg = 0; 27708c2ecf20Sopenharmony_ci 27718c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_pch2lan) 27728c2ecf20Sopenharmony_ci return 0; 27738c2ecf20Sopenharmony_ci 27748c2ecf20Sopenharmony_ci /* Set K1 beacon duration based on 10Mbs speed */ 27758c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, HV_M_STATUS, &status_reg); 27768c2ecf20Sopenharmony_ci if (ret_val) 27778c2ecf20Sopenharmony_ci return ret_val; 27788c2ecf20Sopenharmony_ci 27798c2ecf20Sopenharmony_ci if ((status_reg & (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) 27808c2ecf20Sopenharmony_ci == (HV_M_STATUS_LINK_UP | HV_M_STATUS_AUTONEG_COMPLETE)) { 27818c2ecf20Sopenharmony_ci if (status_reg & 27828c2ecf20Sopenharmony_ci (HV_M_STATUS_SPEED_1000 | HV_M_STATUS_SPEED_100)) { 27838c2ecf20Sopenharmony_ci u16 pm_phy_reg; 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci /* LV 1G/100 Packet drop issue wa */ 27868c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, HV_PM_CTRL, &pm_phy_reg); 27878c2ecf20Sopenharmony_ci if (ret_val) 27888c2ecf20Sopenharmony_ci return ret_val; 27898c2ecf20Sopenharmony_ci pm_phy_reg &= ~HV_PM_CTRL_K1_ENABLE; 27908c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, HV_PM_CTRL, pm_phy_reg); 27918c2ecf20Sopenharmony_ci if (ret_val) 27928c2ecf20Sopenharmony_ci return ret_val; 27938c2ecf20Sopenharmony_ci } else { 27948c2ecf20Sopenharmony_ci u32 mac_reg; 27958c2ecf20Sopenharmony_ci 27968c2ecf20Sopenharmony_ci mac_reg = er32(FEXTNVM4); 27978c2ecf20Sopenharmony_ci mac_reg &= ~E1000_FEXTNVM4_BEACON_DURATION_MASK; 27988c2ecf20Sopenharmony_ci mac_reg |= E1000_FEXTNVM4_BEACON_DURATION_16USEC; 27998c2ecf20Sopenharmony_ci ew32(FEXTNVM4, mac_reg); 28008c2ecf20Sopenharmony_ci } 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci return ret_val; 28048c2ecf20Sopenharmony_ci} 28058c2ecf20Sopenharmony_ci 28068c2ecf20Sopenharmony_ci/** 28078c2ecf20Sopenharmony_ci * e1000_gate_hw_phy_config_ich8lan - disable PHY config via hardware 28088c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 28098c2ecf20Sopenharmony_ci * @gate: boolean set to true to gate, false to ungate 28108c2ecf20Sopenharmony_ci * 28118c2ecf20Sopenharmony_ci * Gate/ungate the automatic PHY configuration via hardware; perform 28128c2ecf20Sopenharmony_ci * the configuration via software instead. 28138c2ecf20Sopenharmony_ci **/ 28148c2ecf20Sopenharmony_cistatic void e1000_gate_hw_phy_config_ich8lan(struct e1000_hw *hw, bool gate) 28158c2ecf20Sopenharmony_ci{ 28168c2ecf20Sopenharmony_ci u32 extcnf_ctrl; 28178c2ecf20Sopenharmony_ci 28188c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch2lan) 28198c2ecf20Sopenharmony_ci return; 28208c2ecf20Sopenharmony_ci 28218c2ecf20Sopenharmony_ci extcnf_ctrl = er32(EXTCNF_CTRL); 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_ci if (gate) 28248c2ecf20Sopenharmony_ci extcnf_ctrl |= E1000_EXTCNF_CTRL_GATE_PHY_CFG; 28258c2ecf20Sopenharmony_ci else 28268c2ecf20Sopenharmony_ci extcnf_ctrl &= ~E1000_EXTCNF_CTRL_GATE_PHY_CFG; 28278c2ecf20Sopenharmony_ci 28288c2ecf20Sopenharmony_ci ew32(EXTCNF_CTRL, extcnf_ctrl); 28298c2ecf20Sopenharmony_ci} 28308c2ecf20Sopenharmony_ci 28318c2ecf20Sopenharmony_ci/** 28328c2ecf20Sopenharmony_ci * e1000_lan_init_done_ich8lan - Check for PHY config completion 28338c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 28348c2ecf20Sopenharmony_ci * 28358c2ecf20Sopenharmony_ci * Check the appropriate indication the MAC has finished configuring the 28368c2ecf20Sopenharmony_ci * PHY after a software reset. 28378c2ecf20Sopenharmony_ci **/ 28388c2ecf20Sopenharmony_cistatic void e1000_lan_init_done_ich8lan(struct e1000_hw *hw) 28398c2ecf20Sopenharmony_ci{ 28408c2ecf20Sopenharmony_ci u32 data, loop = E1000_ICH8_LAN_INIT_TIMEOUT; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci /* Wait for basic configuration completes before proceeding */ 28438c2ecf20Sopenharmony_ci do { 28448c2ecf20Sopenharmony_ci data = er32(STATUS); 28458c2ecf20Sopenharmony_ci data &= E1000_STATUS_LAN_INIT_DONE; 28468c2ecf20Sopenharmony_ci usleep_range(100, 200); 28478c2ecf20Sopenharmony_ci } while ((!data) && --loop); 28488c2ecf20Sopenharmony_ci 28498c2ecf20Sopenharmony_ci /* If basic configuration is incomplete before the above loop 28508c2ecf20Sopenharmony_ci * count reaches 0, loading the configuration from NVM will 28518c2ecf20Sopenharmony_ci * leave the PHY in a bad state possibly resulting in no link. 28528c2ecf20Sopenharmony_ci */ 28538c2ecf20Sopenharmony_ci if (loop == 0) 28548c2ecf20Sopenharmony_ci e_dbg("LAN_INIT_DONE not set, increase timeout\n"); 28558c2ecf20Sopenharmony_ci 28568c2ecf20Sopenharmony_ci /* Clear the Init Done bit for the next init event */ 28578c2ecf20Sopenharmony_ci data = er32(STATUS); 28588c2ecf20Sopenharmony_ci data &= ~E1000_STATUS_LAN_INIT_DONE; 28598c2ecf20Sopenharmony_ci ew32(STATUS, data); 28608c2ecf20Sopenharmony_ci} 28618c2ecf20Sopenharmony_ci 28628c2ecf20Sopenharmony_ci/** 28638c2ecf20Sopenharmony_ci * e1000_post_phy_reset_ich8lan - Perform steps required after a PHY reset 28648c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 28658c2ecf20Sopenharmony_ci **/ 28668c2ecf20Sopenharmony_cistatic s32 e1000_post_phy_reset_ich8lan(struct e1000_hw *hw) 28678c2ecf20Sopenharmony_ci{ 28688c2ecf20Sopenharmony_ci s32 ret_val = 0; 28698c2ecf20Sopenharmony_ci u16 reg; 28708c2ecf20Sopenharmony_ci 28718c2ecf20Sopenharmony_ci if (hw->phy.ops.check_reset_block(hw)) 28728c2ecf20Sopenharmony_ci return 0; 28738c2ecf20Sopenharmony_ci 28748c2ecf20Sopenharmony_ci /* Allow time for h/w to get to quiescent state after reset */ 28758c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 28768c2ecf20Sopenharmony_ci 28778c2ecf20Sopenharmony_ci /* Perform any necessary post-reset workarounds */ 28788c2ecf20Sopenharmony_ci switch (hw->mac.type) { 28798c2ecf20Sopenharmony_ci case e1000_pchlan: 28808c2ecf20Sopenharmony_ci ret_val = e1000_hv_phy_workarounds_ich8lan(hw); 28818c2ecf20Sopenharmony_ci if (ret_val) 28828c2ecf20Sopenharmony_ci return ret_val; 28838c2ecf20Sopenharmony_ci break; 28848c2ecf20Sopenharmony_ci case e1000_pch2lan: 28858c2ecf20Sopenharmony_ci ret_val = e1000_lv_phy_workarounds_ich8lan(hw); 28868c2ecf20Sopenharmony_ci if (ret_val) 28878c2ecf20Sopenharmony_ci return ret_val; 28888c2ecf20Sopenharmony_ci break; 28898c2ecf20Sopenharmony_ci default: 28908c2ecf20Sopenharmony_ci break; 28918c2ecf20Sopenharmony_ci } 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci /* Clear the host wakeup bit after lcd reset */ 28948c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pchlan) { 28958c2ecf20Sopenharmony_ci e1e_rphy(hw, BM_PORT_GEN_CFG, ®); 28968c2ecf20Sopenharmony_ci reg &= ~BM_WUC_HOST_WU_BIT; 28978c2ecf20Sopenharmony_ci e1e_wphy(hw, BM_PORT_GEN_CFG, reg); 28988c2ecf20Sopenharmony_ci } 28998c2ecf20Sopenharmony_ci 29008c2ecf20Sopenharmony_ci /* Configure the LCD with the extended configuration region in NVM */ 29018c2ecf20Sopenharmony_ci ret_val = e1000_sw_lcd_config_ich8lan(hw); 29028c2ecf20Sopenharmony_ci if (ret_val) 29038c2ecf20Sopenharmony_ci return ret_val; 29048c2ecf20Sopenharmony_ci 29058c2ecf20Sopenharmony_ci /* Configure the LCD with the OEM bits in NVM */ 29068c2ecf20Sopenharmony_ci ret_val = e1000_oem_bits_config_ich8lan(hw, true); 29078c2ecf20Sopenharmony_ci 29088c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pch2lan) { 29098c2ecf20Sopenharmony_ci /* Ungate automatic PHY configuration on non-managed 82579 */ 29108c2ecf20Sopenharmony_ci if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { 29118c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 29128c2ecf20Sopenharmony_ci e1000_gate_hw_phy_config_ich8lan(hw, false); 29138c2ecf20Sopenharmony_ci } 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci /* Set EEE LPI Update Timer to 200usec */ 29168c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 29178c2ecf20Sopenharmony_ci if (ret_val) 29188c2ecf20Sopenharmony_ci return ret_val; 29198c2ecf20Sopenharmony_ci ret_val = e1000_write_emi_reg_locked(hw, 29208c2ecf20Sopenharmony_ci I82579_LPI_UPDATE_TIMER, 29218c2ecf20Sopenharmony_ci 0x1387); 29228c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 29238c2ecf20Sopenharmony_ci } 29248c2ecf20Sopenharmony_ci 29258c2ecf20Sopenharmony_ci return ret_val; 29268c2ecf20Sopenharmony_ci} 29278c2ecf20Sopenharmony_ci 29288c2ecf20Sopenharmony_ci/** 29298c2ecf20Sopenharmony_ci * e1000_phy_hw_reset_ich8lan - Performs a PHY reset 29308c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 29318c2ecf20Sopenharmony_ci * 29328c2ecf20Sopenharmony_ci * Resets the PHY 29338c2ecf20Sopenharmony_ci * This is a function pointer entry point called by drivers 29348c2ecf20Sopenharmony_ci * or other shared routines. 29358c2ecf20Sopenharmony_ci **/ 29368c2ecf20Sopenharmony_cistatic s32 e1000_phy_hw_reset_ich8lan(struct e1000_hw *hw) 29378c2ecf20Sopenharmony_ci{ 29388c2ecf20Sopenharmony_ci s32 ret_val = 0; 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci /* Gate automatic PHY configuration by hardware on non-managed 82579 */ 29418c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_pch2lan) && 29428c2ecf20Sopenharmony_ci !(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) 29438c2ecf20Sopenharmony_ci e1000_gate_hw_phy_config_ich8lan(hw, true); 29448c2ecf20Sopenharmony_ci 29458c2ecf20Sopenharmony_ci ret_val = e1000e_phy_hw_reset_generic(hw); 29468c2ecf20Sopenharmony_ci if (ret_val) 29478c2ecf20Sopenharmony_ci return ret_val; 29488c2ecf20Sopenharmony_ci 29498c2ecf20Sopenharmony_ci return e1000_post_phy_reset_ich8lan(hw); 29508c2ecf20Sopenharmony_ci} 29518c2ecf20Sopenharmony_ci 29528c2ecf20Sopenharmony_ci/** 29538c2ecf20Sopenharmony_ci * e1000_set_lplu_state_pchlan - Set Low Power Link Up state 29548c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 29558c2ecf20Sopenharmony_ci * @active: true to enable LPLU, false to disable 29568c2ecf20Sopenharmony_ci * 29578c2ecf20Sopenharmony_ci * Sets the LPLU state according to the active flag. For PCH, if OEM write 29588c2ecf20Sopenharmony_ci * bit are disabled in the NVM, writing the LPLU bits in the MAC will not set 29598c2ecf20Sopenharmony_ci * the phy speed. This function will manually set the LPLU bit and restart 29608c2ecf20Sopenharmony_ci * auto-neg as hw would do. D3 and D0 LPLU will call the same function 29618c2ecf20Sopenharmony_ci * since it configures the same bit. 29628c2ecf20Sopenharmony_ci **/ 29638c2ecf20Sopenharmony_cistatic s32 e1000_set_lplu_state_pchlan(struct e1000_hw *hw, bool active) 29648c2ecf20Sopenharmony_ci{ 29658c2ecf20Sopenharmony_ci s32 ret_val; 29668c2ecf20Sopenharmony_ci u16 oem_reg; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, HV_OEM_BITS, &oem_reg); 29698c2ecf20Sopenharmony_ci if (ret_val) 29708c2ecf20Sopenharmony_ci return ret_val; 29718c2ecf20Sopenharmony_ci 29728c2ecf20Sopenharmony_ci if (active) 29738c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_LPLU; 29748c2ecf20Sopenharmony_ci else 29758c2ecf20Sopenharmony_ci oem_reg &= ~HV_OEM_BITS_LPLU; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci if (!hw->phy.ops.check_reset_block(hw)) 29788c2ecf20Sopenharmony_ci oem_reg |= HV_OEM_BITS_RESTART_AN; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci return e1e_wphy(hw, HV_OEM_BITS, oem_reg); 29818c2ecf20Sopenharmony_ci} 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci/** 29848c2ecf20Sopenharmony_ci * e1000_set_d0_lplu_state_ich8lan - Set Low Power Linkup D0 state 29858c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 29868c2ecf20Sopenharmony_ci * @active: true to enable LPLU, false to disable 29878c2ecf20Sopenharmony_ci * 29888c2ecf20Sopenharmony_ci * Sets the LPLU D0 state according to the active flag. When 29898c2ecf20Sopenharmony_ci * activating LPLU this function also disables smart speed 29908c2ecf20Sopenharmony_ci * and vice versa. LPLU will not be activated unless the 29918c2ecf20Sopenharmony_ci * device autonegotiation advertisement meets standards of 29928c2ecf20Sopenharmony_ci * either 10 or 10/100 or 10/100/1000 at all duplexes. 29938c2ecf20Sopenharmony_ci * This is a function pointer entry point only called by 29948c2ecf20Sopenharmony_ci * PHY setup routines. 29958c2ecf20Sopenharmony_ci **/ 29968c2ecf20Sopenharmony_cistatic s32 e1000_set_d0_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 29978c2ecf20Sopenharmony_ci{ 29988c2ecf20Sopenharmony_ci struct e1000_phy_info *phy = &hw->phy; 29998c2ecf20Sopenharmony_ci u32 phy_ctrl; 30008c2ecf20Sopenharmony_ci s32 ret_val = 0; 30018c2ecf20Sopenharmony_ci u16 data; 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci if (phy->type == e1000_phy_ife) 30048c2ecf20Sopenharmony_ci return 0; 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci phy_ctrl = er32(PHY_CTRL); 30078c2ecf20Sopenharmony_ci 30088c2ecf20Sopenharmony_ci if (active) { 30098c2ecf20Sopenharmony_ci phy_ctrl |= E1000_PHY_CTRL_D0A_LPLU; 30108c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci if (phy->type != e1000_phy_igp_3) 30138c2ecf20Sopenharmony_ci return 0; 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci /* Call gig speed drop workaround on LPLU before accessing 30168c2ecf20Sopenharmony_ci * any PHY registers 30178c2ecf20Sopenharmony_ci */ 30188c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 30198c2ecf20Sopenharmony_ci e1000e_gig_downshift_workaround_ich8lan(hw); 30208c2ecf20Sopenharmony_ci 30218c2ecf20Sopenharmony_ci /* When LPLU is enabled, we should disable SmartSpeed */ 30228c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); 30238c2ecf20Sopenharmony_ci if (ret_val) 30248c2ecf20Sopenharmony_ci return ret_val; 30258c2ecf20Sopenharmony_ci data &= ~IGP01E1000_PSCFR_SMART_SPEED; 30268c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); 30278c2ecf20Sopenharmony_ci if (ret_val) 30288c2ecf20Sopenharmony_ci return ret_val; 30298c2ecf20Sopenharmony_ci } else { 30308c2ecf20Sopenharmony_ci phy_ctrl &= ~E1000_PHY_CTRL_D0A_LPLU; 30318c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 30328c2ecf20Sopenharmony_ci 30338c2ecf20Sopenharmony_ci if (phy->type != e1000_phy_igp_3) 30348c2ecf20Sopenharmony_ci return 0; 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 30378c2ecf20Sopenharmony_ci * during Dx states where the power conservation is most 30388c2ecf20Sopenharmony_ci * important. During driver activity we should enable 30398c2ecf20Sopenharmony_ci * SmartSpeed, so performance is maintained. 30408c2ecf20Sopenharmony_ci */ 30418c2ecf20Sopenharmony_ci if (phy->smart_speed == e1000_smart_speed_on) { 30428c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, 30438c2ecf20Sopenharmony_ci &data); 30448c2ecf20Sopenharmony_ci if (ret_val) 30458c2ecf20Sopenharmony_ci return ret_val; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci data |= IGP01E1000_PSCFR_SMART_SPEED; 30488c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, 30498c2ecf20Sopenharmony_ci data); 30508c2ecf20Sopenharmony_ci if (ret_val) 30518c2ecf20Sopenharmony_ci return ret_val; 30528c2ecf20Sopenharmony_ci } else if (phy->smart_speed == e1000_smart_speed_off) { 30538c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, 30548c2ecf20Sopenharmony_ci &data); 30558c2ecf20Sopenharmony_ci if (ret_val) 30568c2ecf20Sopenharmony_ci return ret_val; 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci data &= ~IGP01E1000_PSCFR_SMART_SPEED; 30598c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, 30608c2ecf20Sopenharmony_ci data); 30618c2ecf20Sopenharmony_ci if (ret_val) 30628c2ecf20Sopenharmony_ci return ret_val; 30638c2ecf20Sopenharmony_ci } 30648c2ecf20Sopenharmony_ci } 30658c2ecf20Sopenharmony_ci 30668c2ecf20Sopenharmony_ci return 0; 30678c2ecf20Sopenharmony_ci} 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci/** 30708c2ecf20Sopenharmony_ci * e1000_set_d3_lplu_state_ich8lan - Set Low Power Linkup D3 state 30718c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 30728c2ecf20Sopenharmony_ci * @active: true to enable LPLU, false to disable 30738c2ecf20Sopenharmony_ci * 30748c2ecf20Sopenharmony_ci * Sets the LPLU D3 state according to the active flag. When 30758c2ecf20Sopenharmony_ci * activating LPLU this function also disables smart speed 30768c2ecf20Sopenharmony_ci * and vice versa. LPLU will not be activated unless the 30778c2ecf20Sopenharmony_ci * device autonegotiation advertisement meets standards of 30788c2ecf20Sopenharmony_ci * either 10 or 10/100 or 10/100/1000 at all duplexes. 30798c2ecf20Sopenharmony_ci * This is a function pointer entry point only called by 30808c2ecf20Sopenharmony_ci * PHY setup routines. 30818c2ecf20Sopenharmony_ci **/ 30828c2ecf20Sopenharmony_cistatic s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) 30838c2ecf20Sopenharmony_ci{ 30848c2ecf20Sopenharmony_ci struct e1000_phy_info *phy = &hw->phy; 30858c2ecf20Sopenharmony_ci u32 phy_ctrl; 30868c2ecf20Sopenharmony_ci s32 ret_val = 0; 30878c2ecf20Sopenharmony_ci u16 data; 30888c2ecf20Sopenharmony_ci 30898c2ecf20Sopenharmony_ci phy_ctrl = er32(PHY_CTRL); 30908c2ecf20Sopenharmony_ci 30918c2ecf20Sopenharmony_ci if (!active) { 30928c2ecf20Sopenharmony_ci phy_ctrl &= ~E1000_PHY_CTRL_NOND0A_LPLU; 30938c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci if (phy->type != e1000_phy_igp_3) 30968c2ecf20Sopenharmony_ci return 0; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ci /* LPLU and SmartSpeed are mutually exclusive. LPLU is used 30998c2ecf20Sopenharmony_ci * during Dx states where the power conservation is most 31008c2ecf20Sopenharmony_ci * important. During driver activity we should enable 31018c2ecf20Sopenharmony_ci * SmartSpeed, so performance is maintained. 31028c2ecf20Sopenharmony_ci */ 31038c2ecf20Sopenharmony_ci if (phy->smart_speed == e1000_smart_speed_on) { 31048c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, 31058c2ecf20Sopenharmony_ci &data); 31068c2ecf20Sopenharmony_ci if (ret_val) 31078c2ecf20Sopenharmony_ci return ret_val; 31088c2ecf20Sopenharmony_ci 31098c2ecf20Sopenharmony_ci data |= IGP01E1000_PSCFR_SMART_SPEED; 31108c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, 31118c2ecf20Sopenharmony_ci data); 31128c2ecf20Sopenharmony_ci if (ret_val) 31138c2ecf20Sopenharmony_ci return ret_val; 31148c2ecf20Sopenharmony_ci } else if (phy->smart_speed == e1000_smart_speed_off) { 31158c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, 31168c2ecf20Sopenharmony_ci &data); 31178c2ecf20Sopenharmony_ci if (ret_val) 31188c2ecf20Sopenharmony_ci return ret_val; 31198c2ecf20Sopenharmony_ci 31208c2ecf20Sopenharmony_ci data &= ~IGP01E1000_PSCFR_SMART_SPEED; 31218c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, 31228c2ecf20Sopenharmony_ci data); 31238c2ecf20Sopenharmony_ci if (ret_val) 31248c2ecf20Sopenharmony_ci return ret_val; 31258c2ecf20Sopenharmony_ci } 31268c2ecf20Sopenharmony_ci } else if ((phy->autoneg_advertised == E1000_ALL_SPEED_DUPLEX) || 31278c2ecf20Sopenharmony_ci (phy->autoneg_advertised == E1000_ALL_NOT_GIG) || 31288c2ecf20Sopenharmony_ci (phy->autoneg_advertised == E1000_ALL_10_SPEED)) { 31298c2ecf20Sopenharmony_ci phy_ctrl |= E1000_PHY_CTRL_NOND0A_LPLU; 31308c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 31318c2ecf20Sopenharmony_ci 31328c2ecf20Sopenharmony_ci if (phy->type != e1000_phy_igp_3) 31338c2ecf20Sopenharmony_ci return 0; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_ci /* Call gig speed drop workaround on LPLU before accessing 31368c2ecf20Sopenharmony_ci * any PHY registers 31378c2ecf20Sopenharmony_ci */ 31388c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 31398c2ecf20Sopenharmony_ci e1000e_gig_downshift_workaround_ich8lan(hw); 31408c2ecf20Sopenharmony_ci 31418c2ecf20Sopenharmony_ci /* When LPLU is enabled, we should disable SmartSpeed */ 31428c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP01E1000_PHY_PORT_CONFIG, &data); 31438c2ecf20Sopenharmony_ci if (ret_val) 31448c2ecf20Sopenharmony_ci return ret_val; 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci data &= ~IGP01E1000_PSCFR_SMART_SPEED; 31478c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IGP01E1000_PHY_PORT_CONFIG, data); 31488c2ecf20Sopenharmony_ci } 31498c2ecf20Sopenharmony_ci 31508c2ecf20Sopenharmony_ci return ret_val; 31518c2ecf20Sopenharmony_ci} 31528c2ecf20Sopenharmony_ci 31538c2ecf20Sopenharmony_ci/** 31548c2ecf20Sopenharmony_ci * e1000_valid_nvm_bank_detect_ich8lan - finds out the valid bank 0 or 1 31558c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 31568c2ecf20Sopenharmony_ci * @bank: pointer to the variable that returns the active bank 31578c2ecf20Sopenharmony_ci * 31588c2ecf20Sopenharmony_ci * Reads signature byte from the NVM using the flash access registers. 31598c2ecf20Sopenharmony_ci * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. 31608c2ecf20Sopenharmony_ci **/ 31618c2ecf20Sopenharmony_cistatic s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) 31628c2ecf20Sopenharmony_ci{ 31638c2ecf20Sopenharmony_ci u32 eecd; 31648c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 31658c2ecf20Sopenharmony_ci u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); 31668c2ecf20Sopenharmony_ci u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; 31678c2ecf20Sopenharmony_ci u32 nvm_dword = 0; 31688c2ecf20Sopenharmony_ci u8 sig_byte = 0; 31698c2ecf20Sopenharmony_ci s32 ret_val; 31708c2ecf20Sopenharmony_ci 31718c2ecf20Sopenharmony_ci switch (hw->mac.type) { 31728c2ecf20Sopenharmony_ci case e1000_pch_spt: 31738c2ecf20Sopenharmony_ci case e1000_pch_cnp: 31748c2ecf20Sopenharmony_ci case e1000_pch_tgp: 31758c2ecf20Sopenharmony_ci case e1000_pch_adp: 31768c2ecf20Sopenharmony_ci case e1000_pch_mtp: 31778c2ecf20Sopenharmony_ci bank1_offset = nvm->flash_bank_size; 31788c2ecf20Sopenharmony_ci act_offset = E1000_ICH_NVM_SIG_WORD; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci /* set bank to 0 in case flash read fails */ 31818c2ecf20Sopenharmony_ci *bank = 0; 31828c2ecf20Sopenharmony_ci 31838c2ecf20Sopenharmony_ci /* Check bank 0 */ 31848c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, 31858c2ecf20Sopenharmony_ci &nvm_dword); 31868c2ecf20Sopenharmony_ci if (ret_val) 31878c2ecf20Sopenharmony_ci return ret_val; 31888c2ecf20Sopenharmony_ci sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 31898c2ecf20Sopenharmony_ci if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 31908c2ecf20Sopenharmony_ci E1000_ICH_NVM_SIG_VALUE) { 31918c2ecf20Sopenharmony_ci *bank = 0; 31928c2ecf20Sopenharmony_ci return 0; 31938c2ecf20Sopenharmony_ci } 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci /* Check bank 1 */ 31968c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset + 31978c2ecf20Sopenharmony_ci bank1_offset, 31988c2ecf20Sopenharmony_ci &nvm_dword); 31998c2ecf20Sopenharmony_ci if (ret_val) 32008c2ecf20Sopenharmony_ci return ret_val; 32018c2ecf20Sopenharmony_ci sig_byte = (u8)((nvm_dword & 0xFF00) >> 8); 32028c2ecf20Sopenharmony_ci if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 32038c2ecf20Sopenharmony_ci E1000_ICH_NVM_SIG_VALUE) { 32048c2ecf20Sopenharmony_ci *bank = 1; 32058c2ecf20Sopenharmony_ci return 0; 32068c2ecf20Sopenharmony_ci } 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_ci e_dbg("ERROR: No valid NVM bank present\n"); 32098c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 32108c2ecf20Sopenharmony_ci case e1000_ich8lan: 32118c2ecf20Sopenharmony_ci case e1000_ich9lan: 32128c2ecf20Sopenharmony_ci eecd = er32(EECD); 32138c2ecf20Sopenharmony_ci if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == 32148c2ecf20Sopenharmony_ci E1000_EECD_SEC1VAL_VALID_MASK) { 32158c2ecf20Sopenharmony_ci if (eecd & E1000_EECD_SEC1VAL) 32168c2ecf20Sopenharmony_ci *bank = 1; 32178c2ecf20Sopenharmony_ci else 32188c2ecf20Sopenharmony_ci *bank = 0; 32198c2ecf20Sopenharmony_ci 32208c2ecf20Sopenharmony_ci return 0; 32218c2ecf20Sopenharmony_ci } 32228c2ecf20Sopenharmony_ci e_dbg("Unable to determine valid NVM bank via EEC - reading flash signature\n"); 32238c2ecf20Sopenharmony_ci fallthrough; 32248c2ecf20Sopenharmony_ci default: 32258c2ecf20Sopenharmony_ci /* set bank to 0 in case flash read fails */ 32268c2ecf20Sopenharmony_ci *bank = 0; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci /* Check bank 0 */ 32298c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, 32308c2ecf20Sopenharmony_ci &sig_byte); 32318c2ecf20Sopenharmony_ci if (ret_val) 32328c2ecf20Sopenharmony_ci return ret_val; 32338c2ecf20Sopenharmony_ci if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 32348c2ecf20Sopenharmony_ci E1000_ICH_NVM_SIG_VALUE) { 32358c2ecf20Sopenharmony_ci *bank = 0; 32368c2ecf20Sopenharmony_ci return 0; 32378c2ecf20Sopenharmony_ci } 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_ci /* Check bank 1 */ 32408c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + 32418c2ecf20Sopenharmony_ci bank1_offset, 32428c2ecf20Sopenharmony_ci &sig_byte); 32438c2ecf20Sopenharmony_ci if (ret_val) 32448c2ecf20Sopenharmony_ci return ret_val; 32458c2ecf20Sopenharmony_ci if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == 32468c2ecf20Sopenharmony_ci E1000_ICH_NVM_SIG_VALUE) { 32478c2ecf20Sopenharmony_ci *bank = 1; 32488c2ecf20Sopenharmony_ci return 0; 32498c2ecf20Sopenharmony_ci } 32508c2ecf20Sopenharmony_ci 32518c2ecf20Sopenharmony_ci e_dbg("ERROR: No valid NVM bank present\n"); 32528c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 32538c2ecf20Sopenharmony_ci } 32548c2ecf20Sopenharmony_ci} 32558c2ecf20Sopenharmony_ci 32568c2ecf20Sopenharmony_ci/** 32578c2ecf20Sopenharmony_ci * e1000_read_nvm_spt - NVM access for SPT 32588c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 32598c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the word(s) to read. 32608c2ecf20Sopenharmony_ci * @words: Size of data to read in words. 32618c2ecf20Sopenharmony_ci * @data: pointer to the word(s) to read at offset. 32628c2ecf20Sopenharmony_ci * 32638c2ecf20Sopenharmony_ci * Reads a word(s) from the NVM 32648c2ecf20Sopenharmony_ci **/ 32658c2ecf20Sopenharmony_cistatic s32 e1000_read_nvm_spt(struct e1000_hw *hw, u16 offset, u16 words, 32668c2ecf20Sopenharmony_ci u16 *data) 32678c2ecf20Sopenharmony_ci{ 32688c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 32698c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 32708c2ecf20Sopenharmony_ci u32 act_offset; 32718c2ecf20Sopenharmony_ci s32 ret_val = 0; 32728c2ecf20Sopenharmony_ci u32 bank = 0; 32738c2ecf20Sopenharmony_ci u32 dword = 0; 32748c2ecf20Sopenharmony_ci u16 offset_to_read; 32758c2ecf20Sopenharmony_ci u16 i; 32768c2ecf20Sopenharmony_ci 32778c2ecf20Sopenharmony_ci if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 32788c2ecf20Sopenharmony_ci (words == 0)) { 32798c2ecf20Sopenharmony_ci e_dbg("nvm parameter(s) out of bounds\n"); 32808c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_NVM; 32818c2ecf20Sopenharmony_ci goto out; 32828c2ecf20Sopenharmony_ci } 32838c2ecf20Sopenharmony_ci 32848c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 32858c2ecf20Sopenharmony_ci 32868c2ecf20Sopenharmony_ci ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 32878c2ecf20Sopenharmony_ci if (ret_val) { 32888c2ecf20Sopenharmony_ci e_dbg("Could not detect valid bank, assuming bank 0\n"); 32898c2ecf20Sopenharmony_ci bank = 0; 32908c2ecf20Sopenharmony_ci } 32918c2ecf20Sopenharmony_ci 32928c2ecf20Sopenharmony_ci act_offset = (bank) ? nvm->flash_bank_size : 0; 32938c2ecf20Sopenharmony_ci act_offset += offset; 32948c2ecf20Sopenharmony_ci 32958c2ecf20Sopenharmony_ci ret_val = 0; 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci for (i = 0; i < words; i += 2) { 32988c2ecf20Sopenharmony_ci if (words - i == 1) { 32998c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[offset + i].modified) { 33008c2ecf20Sopenharmony_ci data[i] = 33018c2ecf20Sopenharmony_ci dev_spec->shadow_ram[offset + i].value; 33028c2ecf20Sopenharmony_ci } else { 33038c2ecf20Sopenharmony_ci offset_to_read = act_offset + i - 33048c2ecf20Sopenharmony_ci ((act_offset + i) % 2); 33058c2ecf20Sopenharmony_ci ret_val = 33068c2ecf20Sopenharmony_ci e1000_read_flash_dword_ich8lan(hw, 33078c2ecf20Sopenharmony_ci offset_to_read, 33088c2ecf20Sopenharmony_ci &dword); 33098c2ecf20Sopenharmony_ci if (ret_val) 33108c2ecf20Sopenharmony_ci break; 33118c2ecf20Sopenharmony_ci if ((act_offset + i) % 2 == 0) 33128c2ecf20Sopenharmony_ci data[i] = (u16)(dword & 0xFFFF); 33138c2ecf20Sopenharmony_ci else 33148c2ecf20Sopenharmony_ci data[i] = (u16)((dword >> 16) & 0xFFFF); 33158c2ecf20Sopenharmony_ci } 33168c2ecf20Sopenharmony_ci } else { 33178c2ecf20Sopenharmony_ci offset_to_read = act_offset + i; 33188c2ecf20Sopenharmony_ci if (!(dev_spec->shadow_ram[offset + i].modified) || 33198c2ecf20Sopenharmony_ci !(dev_spec->shadow_ram[offset + i + 1].modified)) { 33208c2ecf20Sopenharmony_ci ret_val = 33218c2ecf20Sopenharmony_ci e1000_read_flash_dword_ich8lan(hw, 33228c2ecf20Sopenharmony_ci offset_to_read, 33238c2ecf20Sopenharmony_ci &dword); 33248c2ecf20Sopenharmony_ci if (ret_val) 33258c2ecf20Sopenharmony_ci break; 33268c2ecf20Sopenharmony_ci } 33278c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[offset + i].modified) 33288c2ecf20Sopenharmony_ci data[i] = 33298c2ecf20Sopenharmony_ci dev_spec->shadow_ram[offset + i].value; 33308c2ecf20Sopenharmony_ci else 33318c2ecf20Sopenharmony_ci data[i] = (u16)(dword & 0xFFFF); 33328c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[offset + i].modified) 33338c2ecf20Sopenharmony_ci data[i + 1] = 33348c2ecf20Sopenharmony_ci dev_spec->shadow_ram[offset + i + 1].value; 33358c2ecf20Sopenharmony_ci else 33368c2ecf20Sopenharmony_ci data[i + 1] = (u16)(dword >> 16 & 0xFFFF); 33378c2ecf20Sopenharmony_ci } 33388c2ecf20Sopenharmony_ci } 33398c2ecf20Sopenharmony_ci 33408c2ecf20Sopenharmony_ci nvm->ops.release(hw); 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ciout: 33438c2ecf20Sopenharmony_ci if (ret_val) 33448c2ecf20Sopenharmony_ci e_dbg("NVM read error: %d\n", ret_val); 33458c2ecf20Sopenharmony_ci 33468c2ecf20Sopenharmony_ci return ret_val; 33478c2ecf20Sopenharmony_ci} 33488c2ecf20Sopenharmony_ci 33498c2ecf20Sopenharmony_ci/** 33508c2ecf20Sopenharmony_ci * e1000_read_nvm_ich8lan - Read word(s) from the NVM 33518c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 33528c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the word(s) to read. 33538c2ecf20Sopenharmony_ci * @words: Size of data to read in words 33548c2ecf20Sopenharmony_ci * @data: Pointer to the word(s) to read at offset. 33558c2ecf20Sopenharmony_ci * 33568c2ecf20Sopenharmony_ci * Reads a word(s) from the NVM using the flash access registers. 33578c2ecf20Sopenharmony_ci **/ 33588c2ecf20Sopenharmony_cistatic s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 33598c2ecf20Sopenharmony_ci u16 *data) 33608c2ecf20Sopenharmony_ci{ 33618c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 33628c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 33638c2ecf20Sopenharmony_ci u32 act_offset; 33648c2ecf20Sopenharmony_ci s32 ret_val = 0; 33658c2ecf20Sopenharmony_ci u32 bank = 0; 33668c2ecf20Sopenharmony_ci u16 i, word; 33678c2ecf20Sopenharmony_ci 33688c2ecf20Sopenharmony_ci if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 33698c2ecf20Sopenharmony_ci (words == 0)) { 33708c2ecf20Sopenharmony_ci e_dbg("nvm parameter(s) out of bounds\n"); 33718c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_NVM; 33728c2ecf20Sopenharmony_ci goto out; 33738c2ecf20Sopenharmony_ci } 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 33788c2ecf20Sopenharmony_ci if (ret_val) { 33798c2ecf20Sopenharmony_ci e_dbg("Could not detect valid bank, assuming bank 0\n"); 33808c2ecf20Sopenharmony_ci bank = 0; 33818c2ecf20Sopenharmony_ci } 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci act_offset = (bank) ? nvm->flash_bank_size : 0; 33848c2ecf20Sopenharmony_ci act_offset += offset; 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_ci ret_val = 0; 33878c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 33888c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[offset + i].modified) { 33898c2ecf20Sopenharmony_ci data[i] = dev_spec->shadow_ram[offset + i].value; 33908c2ecf20Sopenharmony_ci } else { 33918c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_word_ich8lan(hw, 33928c2ecf20Sopenharmony_ci act_offset + i, 33938c2ecf20Sopenharmony_ci &word); 33948c2ecf20Sopenharmony_ci if (ret_val) 33958c2ecf20Sopenharmony_ci break; 33968c2ecf20Sopenharmony_ci data[i] = word; 33978c2ecf20Sopenharmony_ci } 33988c2ecf20Sopenharmony_ci } 33998c2ecf20Sopenharmony_ci 34008c2ecf20Sopenharmony_ci nvm->ops.release(hw); 34018c2ecf20Sopenharmony_ci 34028c2ecf20Sopenharmony_ciout: 34038c2ecf20Sopenharmony_ci if (ret_val) 34048c2ecf20Sopenharmony_ci e_dbg("NVM read error: %d\n", ret_val); 34058c2ecf20Sopenharmony_ci 34068c2ecf20Sopenharmony_ci return ret_val; 34078c2ecf20Sopenharmony_ci} 34088c2ecf20Sopenharmony_ci 34098c2ecf20Sopenharmony_ci/** 34108c2ecf20Sopenharmony_ci * e1000_flash_cycle_init_ich8lan - Initialize flash 34118c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 34128c2ecf20Sopenharmony_ci * 34138c2ecf20Sopenharmony_ci * This function does initial flash setup so that a new read/write/erase cycle 34148c2ecf20Sopenharmony_ci * can be started. 34158c2ecf20Sopenharmony_ci **/ 34168c2ecf20Sopenharmony_cistatic s32 e1000_flash_cycle_init_ich8lan(struct e1000_hw *hw) 34178c2ecf20Sopenharmony_ci{ 34188c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 34198c2ecf20Sopenharmony_ci s32 ret_val = -E1000_ERR_NVM; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 34228c2ecf20Sopenharmony_ci 34238c2ecf20Sopenharmony_ci /* Check if the flash descriptor is valid */ 34248c2ecf20Sopenharmony_ci if (!hsfsts.hsf_status.fldesvalid) { 34258c2ecf20Sopenharmony_ci e_dbg("Flash descriptor invalid. SW Sequencing must be used.\n"); 34268c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 34278c2ecf20Sopenharmony_ci } 34288c2ecf20Sopenharmony_ci 34298c2ecf20Sopenharmony_ci /* Clear FCERR and DAEL in hw status by writing 1 */ 34308c2ecf20Sopenharmony_ci hsfsts.hsf_status.flcerr = 1; 34318c2ecf20Sopenharmony_ci hsfsts.hsf_status.dael = 1; 34328c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 34338c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF); 34348c2ecf20Sopenharmony_ci else 34358c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_ci /* Either we should have a hardware SPI cycle in progress 34388c2ecf20Sopenharmony_ci * bit to check against, in order to start a new cycle or 34398c2ecf20Sopenharmony_ci * FDONE bit should be changed in the hardware so that it 34408c2ecf20Sopenharmony_ci * is 1 after hardware reset, which can then be used as an 34418c2ecf20Sopenharmony_ci * indication whether a cycle is in progress or has been 34428c2ecf20Sopenharmony_ci * completed. 34438c2ecf20Sopenharmony_ci */ 34448c2ecf20Sopenharmony_ci 34458c2ecf20Sopenharmony_ci if (!hsfsts.hsf_status.flcinprog) { 34468c2ecf20Sopenharmony_ci /* There is no cycle running at present, 34478c2ecf20Sopenharmony_ci * so we can start a cycle. 34488c2ecf20Sopenharmony_ci * Begin by setting Flash Cycle Done. 34498c2ecf20Sopenharmony_ci */ 34508c2ecf20Sopenharmony_ci hsfsts.hsf_status.flcdone = 1; 34518c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 34528c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval & 0xFFFF); 34538c2ecf20Sopenharmony_ci else 34548c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); 34558c2ecf20Sopenharmony_ci ret_val = 0; 34568c2ecf20Sopenharmony_ci } else { 34578c2ecf20Sopenharmony_ci s32 i; 34588c2ecf20Sopenharmony_ci 34598c2ecf20Sopenharmony_ci /* Otherwise poll for sometime so the current 34608c2ecf20Sopenharmony_ci * cycle has a chance to end before giving up. 34618c2ecf20Sopenharmony_ci */ 34628c2ecf20Sopenharmony_ci for (i = 0; i < ICH_FLASH_READ_COMMAND_TIMEOUT; i++) { 34638c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 34648c2ecf20Sopenharmony_ci if (!hsfsts.hsf_status.flcinprog) { 34658c2ecf20Sopenharmony_ci ret_val = 0; 34668c2ecf20Sopenharmony_ci break; 34678c2ecf20Sopenharmony_ci } 34688c2ecf20Sopenharmony_ci udelay(1); 34698c2ecf20Sopenharmony_ci } 34708c2ecf20Sopenharmony_ci if (!ret_val) { 34718c2ecf20Sopenharmony_ci /* Successful in waiting for previous cycle to timeout, 34728c2ecf20Sopenharmony_ci * now set the Flash Cycle Done. 34738c2ecf20Sopenharmony_ci */ 34748c2ecf20Sopenharmony_ci hsfsts.hsf_status.flcdone = 1; 34758c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 34768c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, 34778c2ecf20Sopenharmony_ci hsfsts.regval & 0xFFFF); 34788c2ecf20Sopenharmony_ci else 34798c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFSTS, hsfsts.regval); 34808c2ecf20Sopenharmony_ci } else { 34818c2ecf20Sopenharmony_ci e_dbg("Flash controller busy, cannot get access\n"); 34828c2ecf20Sopenharmony_ci } 34838c2ecf20Sopenharmony_ci } 34848c2ecf20Sopenharmony_ci 34858c2ecf20Sopenharmony_ci return ret_val; 34868c2ecf20Sopenharmony_ci} 34878c2ecf20Sopenharmony_ci 34888c2ecf20Sopenharmony_ci/** 34898c2ecf20Sopenharmony_ci * e1000_flash_cycle_ich8lan - Starts flash cycle (read/write/erase) 34908c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 34918c2ecf20Sopenharmony_ci * @timeout: maximum time to wait for completion 34928c2ecf20Sopenharmony_ci * 34938c2ecf20Sopenharmony_ci * This function starts a flash cycle and waits for its completion. 34948c2ecf20Sopenharmony_ci **/ 34958c2ecf20Sopenharmony_cistatic s32 e1000_flash_cycle_ich8lan(struct e1000_hw *hw, u32 timeout) 34968c2ecf20Sopenharmony_ci{ 34978c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 34988c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 34998c2ecf20Sopenharmony_ci u32 i = 0; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci /* Start a cycle by writing 1 in Flash Cycle Go in Hw Flash Control */ 35028c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 35038c2ecf20Sopenharmony_ci hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16; 35048c2ecf20Sopenharmony_ci else 35058c2ecf20Sopenharmony_ci hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); 35068c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcgo = 1; 35078c2ecf20Sopenharmony_ci 35088c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 35098c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16); 35108c2ecf20Sopenharmony_ci else 35118c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci /* wait till FDONE bit is set to 1 */ 35148c2ecf20Sopenharmony_ci do { 35158c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 35168c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcdone) 35178c2ecf20Sopenharmony_ci break; 35188c2ecf20Sopenharmony_ci udelay(1); 35198c2ecf20Sopenharmony_ci } while (i++ < timeout); 35208c2ecf20Sopenharmony_ci 35218c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcdone && !hsfsts.hsf_status.flcerr) 35228c2ecf20Sopenharmony_ci return 0; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 35258c2ecf20Sopenharmony_ci} 35268c2ecf20Sopenharmony_ci 35278c2ecf20Sopenharmony_ci/** 35288c2ecf20Sopenharmony_ci * e1000_read_flash_dword_ich8lan - Read dword from flash 35298c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 35308c2ecf20Sopenharmony_ci * @offset: offset to data location 35318c2ecf20Sopenharmony_ci * @data: pointer to the location for storing the data 35328c2ecf20Sopenharmony_ci * 35338c2ecf20Sopenharmony_ci * Reads the flash dword at offset into data. Offset is converted 35348c2ecf20Sopenharmony_ci * to bytes before read. 35358c2ecf20Sopenharmony_ci **/ 35368c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_dword_ich8lan(struct e1000_hw *hw, u32 offset, 35378c2ecf20Sopenharmony_ci u32 *data) 35388c2ecf20Sopenharmony_ci{ 35398c2ecf20Sopenharmony_ci /* Must convert word offset into bytes. */ 35408c2ecf20Sopenharmony_ci offset <<= 1; 35418c2ecf20Sopenharmony_ci return e1000_read_flash_data32_ich8lan(hw, offset, data); 35428c2ecf20Sopenharmony_ci} 35438c2ecf20Sopenharmony_ci 35448c2ecf20Sopenharmony_ci/** 35458c2ecf20Sopenharmony_ci * e1000_read_flash_word_ich8lan - Read word from flash 35468c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 35478c2ecf20Sopenharmony_ci * @offset: offset to data location 35488c2ecf20Sopenharmony_ci * @data: pointer to the location for storing the data 35498c2ecf20Sopenharmony_ci * 35508c2ecf20Sopenharmony_ci * Reads the flash word at offset into data. Offset is converted 35518c2ecf20Sopenharmony_ci * to bytes before read. 35528c2ecf20Sopenharmony_ci **/ 35538c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_word_ich8lan(struct e1000_hw *hw, u32 offset, 35548c2ecf20Sopenharmony_ci u16 *data) 35558c2ecf20Sopenharmony_ci{ 35568c2ecf20Sopenharmony_ci /* Must convert offset into bytes. */ 35578c2ecf20Sopenharmony_ci offset <<= 1; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci return e1000_read_flash_data_ich8lan(hw, offset, 2, data); 35608c2ecf20Sopenharmony_ci} 35618c2ecf20Sopenharmony_ci 35628c2ecf20Sopenharmony_ci/** 35638c2ecf20Sopenharmony_ci * e1000_read_flash_byte_ich8lan - Read byte from flash 35648c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 35658c2ecf20Sopenharmony_ci * @offset: The offset of the byte to read. 35668c2ecf20Sopenharmony_ci * @data: Pointer to a byte to store the value read. 35678c2ecf20Sopenharmony_ci * 35688c2ecf20Sopenharmony_ci * Reads a single byte from the NVM using the flash access registers. 35698c2ecf20Sopenharmony_ci **/ 35708c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 35718c2ecf20Sopenharmony_ci u8 *data) 35728c2ecf20Sopenharmony_ci{ 35738c2ecf20Sopenharmony_ci s32 ret_val; 35748c2ecf20Sopenharmony_ci u16 word = 0; 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci /* In SPT, only 32 bits access is supported, 35778c2ecf20Sopenharmony_ci * so this function should not be called. 35788c2ecf20Sopenharmony_ci */ 35798c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 35808c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 35818c2ecf20Sopenharmony_ci else 35828c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_data_ich8lan(hw, offset, 1, &word); 35838c2ecf20Sopenharmony_ci 35848c2ecf20Sopenharmony_ci if (ret_val) 35858c2ecf20Sopenharmony_ci return ret_val; 35868c2ecf20Sopenharmony_ci 35878c2ecf20Sopenharmony_ci *data = (u8)word; 35888c2ecf20Sopenharmony_ci 35898c2ecf20Sopenharmony_ci return 0; 35908c2ecf20Sopenharmony_ci} 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci/** 35938c2ecf20Sopenharmony_ci * e1000_read_flash_data_ich8lan - Read byte or word from NVM 35948c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 35958c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the byte or word to read. 35968c2ecf20Sopenharmony_ci * @size: Size of data to read, 1=byte 2=word 35978c2ecf20Sopenharmony_ci * @data: Pointer to the word to store the value read. 35988c2ecf20Sopenharmony_ci * 35998c2ecf20Sopenharmony_ci * Reads a byte or word from the NVM using the flash access registers. 36008c2ecf20Sopenharmony_ci **/ 36018c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 36028c2ecf20Sopenharmony_ci u8 size, u16 *data) 36038c2ecf20Sopenharmony_ci{ 36048c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 36058c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 36068c2ecf20Sopenharmony_ci u32 flash_linear_addr; 36078c2ecf20Sopenharmony_ci u32 flash_data = 0; 36088c2ecf20Sopenharmony_ci s32 ret_val = -E1000_ERR_NVM; 36098c2ecf20Sopenharmony_ci u8 count = 0; 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 36128c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 36138c2ecf20Sopenharmony_ci 36148c2ecf20Sopenharmony_ci flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 36158c2ecf20Sopenharmony_ci hw->nvm.flash_base_addr); 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci do { 36188c2ecf20Sopenharmony_ci udelay(1); 36198c2ecf20Sopenharmony_ci /* Steps */ 36208c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_init_ich8lan(hw); 36218c2ecf20Sopenharmony_ci if (ret_val) 36228c2ecf20Sopenharmony_ci break; 36238c2ecf20Sopenharmony_ci 36248c2ecf20Sopenharmony_ci hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); 36258c2ecf20Sopenharmony_ci /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 36268c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.fldbcount = size - 1; 36278c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 36288c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); 36298c2ecf20Sopenharmony_ci 36308c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FADDR, flash_linear_addr); 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci ret_val = 36338c2ecf20Sopenharmony_ci e1000_flash_cycle_ich8lan(hw, 36348c2ecf20Sopenharmony_ci ICH_FLASH_READ_COMMAND_TIMEOUT); 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci /* Check if FCERR is set to 1, if set to 1, clear it 36378c2ecf20Sopenharmony_ci * and try the whole sequence a few more times, else 36388c2ecf20Sopenharmony_ci * read in (shift in) the Flash Data0, the order is 36398c2ecf20Sopenharmony_ci * least significant byte first msb to lsb 36408c2ecf20Sopenharmony_ci */ 36418c2ecf20Sopenharmony_ci if (!ret_val) { 36428c2ecf20Sopenharmony_ci flash_data = er32flash(ICH_FLASH_FDATA0); 36438c2ecf20Sopenharmony_ci if (size == 1) 36448c2ecf20Sopenharmony_ci *data = (u8)(flash_data & 0x000000FF); 36458c2ecf20Sopenharmony_ci else if (size == 2) 36468c2ecf20Sopenharmony_ci *data = (u16)(flash_data & 0x0000FFFF); 36478c2ecf20Sopenharmony_ci break; 36488c2ecf20Sopenharmony_ci } else { 36498c2ecf20Sopenharmony_ci /* If we've gotten here, then things are probably 36508c2ecf20Sopenharmony_ci * completely hosed, but if the error condition is 36518c2ecf20Sopenharmony_ci * detected, it won't hurt to give it another try... 36528c2ecf20Sopenharmony_ci * ICH_FLASH_CYCLE_REPEAT_COUNT times. 36538c2ecf20Sopenharmony_ci */ 36548c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 36558c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcerr) { 36568c2ecf20Sopenharmony_ci /* Repeat for some time before giving up. */ 36578c2ecf20Sopenharmony_ci continue; 36588c2ecf20Sopenharmony_ci } else if (!hsfsts.hsf_status.flcdone) { 36598c2ecf20Sopenharmony_ci e_dbg("Timeout error - flash cycle did not complete.\n"); 36608c2ecf20Sopenharmony_ci break; 36618c2ecf20Sopenharmony_ci } 36628c2ecf20Sopenharmony_ci } 36638c2ecf20Sopenharmony_ci } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 36648c2ecf20Sopenharmony_ci 36658c2ecf20Sopenharmony_ci return ret_val; 36668c2ecf20Sopenharmony_ci} 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci/** 36698c2ecf20Sopenharmony_ci * e1000_read_flash_data32_ich8lan - Read dword from NVM 36708c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 36718c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the dword to read. 36728c2ecf20Sopenharmony_ci * @data: Pointer to the dword to store the value read. 36738c2ecf20Sopenharmony_ci * 36748c2ecf20Sopenharmony_ci * Reads a byte or word from the NVM using the flash access registers. 36758c2ecf20Sopenharmony_ci **/ 36768c2ecf20Sopenharmony_ci 36778c2ecf20Sopenharmony_cistatic s32 e1000_read_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 36788c2ecf20Sopenharmony_ci u32 *data) 36798c2ecf20Sopenharmony_ci{ 36808c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 36818c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 36828c2ecf20Sopenharmony_ci u32 flash_linear_addr; 36838c2ecf20Sopenharmony_ci s32 ret_val = -E1000_ERR_NVM; 36848c2ecf20Sopenharmony_ci u8 count = 0; 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci if (offset > ICH_FLASH_LINEAR_ADDR_MASK || hw->mac.type < e1000_pch_spt) 36878c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 36888c2ecf20Sopenharmony_ci flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 36898c2ecf20Sopenharmony_ci hw->nvm.flash_base_addr); 36908c2ecf20Sopenharmony_ci 36918c2ecf20Sopenharmony_ci do { 36928c2ecf20Sopenharmony_ci udelay(1); 36938c2ecf20Sopenharmony_ci /* Steps */ 36948c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_init_ich8lan(hw); 36958c2ecf20Sopenharmony_ci if (ret_val) 36968c2ecf20Sopenharmony_ci break; 36978c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, not flash. 36988c2ecf20Sopenharmony_ci * Therefore, only 32 bit access is supported 36998c2ecf20Sopenharmony_ci */ 37008c2ecf20Sopenharmony_ci hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16; 37018c2ecf20Sopenharmony_ci 37028c2ecf20Sopenharmony_ci /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 37038c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 37048c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_READ; 37058c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, not flash. 37068c2ecf20Sopenharmony_ci * Therefore, only 32 bit access is supported 37078c2ecf20Sopenharmony_ci */ 37088c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, (u32)hsflctl.regval << 16); 37098c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FADDR, flash_linear_addr); 37108c2ecf20Sopenharmony_ci 37118c2ecf20Sopenharmony_ci ret_val = 37128c2ecf20Sopenharmony_ci e1000_flash_cycle_ich8lan(hw, 37138c2ecf20Sopenharmony_ci ICH_FLASH_READ_COMMAND_TIMEOUT); 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci /* Check if FCERR is set to 1, if set to 1, clear it 37168c2ecf20Sopenharmony_ci * and try the whole sequence a few more times, else 37178c2ecf20Sopenharmony_ci * read in (shift in) the Flash Data0, the order is 37188c2ecf20Sopenharmony_ci * least significant byte first msb to lsb 37198c2ecf20Sopenharmony_ci */ 37208c2ecf20Sopenharmony_ci if (!ret_val) { 37218c2ecf20Sopenharmony_ci *data = er32flash(ICH_FLASH_FDATA0); 37228c2ecf20Sopenharmony_ci break; 37238c2ecf20Sopenharmony_ci } else { 37248c2ecf20Sopenharmony_ci /* If we've gotten here, then things are probably 37258c2ecf20Sopenharmony_ci * completely hosed, but if the error condition is 37268c2ecf20Sopenharmony_ci * detected, it won't hurt to give it another try... 37278c2ecf20Sopenharmony_ci * ICH_FLASH_CYCLE_REPEAT_COUNT times. 37288c2ecf20Sopenharmony_ci */ 37298c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 37308c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcerr) { 37318c2ecf20Sopenharmony_ci /* Repeat for some time before giving up. */ 37328c2ecf20Sopenharmony_ci continue; 37338c2ecf20Sopenharmony_ci } else if (!hsfsts.hsf_status.flcdone) { 37348c2ecf20Sopenharmony_ci e_dbg("Timeout error - flash cycle did not complete.\n"); 37358c2ecf20Sopenharmony_ci break; 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci } 37388c2ecf20Sopenharmony_ci } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci return ret_val; 37418c2ecf20Sopenharmony_ci} 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_ci/** 37448c2ecf20Sopenharmony_ci * e1000_write_nvm_ich8lan - Write word(s) to the NVM 37458c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 37468c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the word(s) to write. 37478c2ecf20Sopenharmony_ci * @words: Size of data to write in words 37488c2ecf20Sopenharmony_ci * @data: Pointer to the word(s) to write at offset. 37498c2ecf20Sopenharmony_ci * 37508c2ecf20Sopenharmony_ci * Writes a byte or word to the NVM using the flash access registers. 37518c2ecf20Sopenharmony_ci **/ 37528c2ecf20Sopenharmony_cistatic s32 e1000_write_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, 37538c2ecf20Sopenharmony_ci u16 *data) 37548c2ecf20Sopenharmony_ci{ 37558c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 37568c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 37578c2ecf20Sopenharmony_ci u16 i; 37588c2ecf20Sopenharmony_ci 37598c2ecf20Sopenharmony_ci if ((offset >= nvm->word_size) || (words > nvm->word_size - offset) || 37608c2ecf20Sopenharmony_ci (words == 0)) { 37618c2ecf20Sopenharmony_ci e_dbg("nvm parameter(s) out of bounds\n"); 37628c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 37638c2ecf20Sopenharmony_ci } 37648c2ecf20Sopenharmony_ci 37658c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 37668c2ecf20Sopenharmony_ci 37678c2ecf20Sopenharmony_ci for (i = 0; i < words; i++) { 37688c2ecf20Sopenharmony_ci dev_spec->shadow_ram[offset + i].modified = true; 37698c2ecf20Sopenharmony_ci dev_spec->shadow_ram[offset + i].value = data[i]; 37708c2ecf20Sopenharmony_ci } 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci nvm->ops.release(hw); 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci return 0; 37758c2ecf20Sopenharmony_ci} 37768c2ecf20Sopenharmony_ci 37778c2ecf20Sopenharmony_ci/** 37788c2ecf20Sopenharmony_ci * e1000_update_nvm_checksum_spt - Update the checksum for NVM 37798c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 37808c2ecf20Sopenharmony_ci * 37818c2ecf20Sopenharmony_ci * The NVM checksum is updated by calling the generic update_nvm_checksum, 37828c2ecf20Sopenharmony_ci * which writes the checksum to the shadow ram. The changes in the shadow 37838c2ecf20Sopenharmony_ci * ram are then committed to the EEPROM by processing each bank at a time 37848c2ecf20Sopenharmony_ci * checking for the modified bit and writing only the pending changes. 37858c2ecf20Sopenharmony_ci * After a successful commit, the shadow ram is cleared and is ready for 37868c2ecf20Sopenharmony_ci * future writes. 37878c2ecf20Sopenharmony_ci **/ 37888c2ecf20Sopenharmony_cistatic s32 e1000_update_nvm_checksum_spt(struct e1000_hw *hw) 37898c2ecf20Sopenharmony_ci{ 37908c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 37918c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 37928c2ecf20Sopenharmony_ci u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 37938c2ecf20Sopenharmony_ci s32 ret_val; 37948c2ecf20Sopenharmony_ci u32 dword = 0; 37958c2ecf20Sopenharmony_ci 37968c2ecf20Sopenharmony_ci ret_val = e1000e_update_nvm_checksum_generic(hw); 37978c2ecf20Sopenharmony_ci if (ret_val) 37988c2ecf20Sopenharmony_ci goto out; 37998c2ecf20Sopenharmony_ci 38008c2ecf20Sopenharmony_ci if (nvm->type != e1000_nvm_flash_sw) 38018c2ecf20Sopenharmony_ci goto out; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 38048c2ecf20Sopenharmony_ci 38058c2ecf20Sopenharmony_ci /* We're writing to the opposite bank so if we're on bank 1, 38068c2ecf20Sopenharmony_ci * write to bank 0 etc. We also need to erase the segment that 38078c2ecf20Sopenharmony_ci * is going to be written 38088c2ecf20Sopenharmony_ci */ 38098c2ecf20Sopenharmony_ci ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 38108c2ecf20Sopenharmony_ci if (ret_val) { 38118c2ecf20Sopenharmony_ci e_dbg("Could not detect valid bank, assuming bank 0\n"); 38128c2ecf20Sopenharmony_ci bank = 0; 38138c2ecf20Sopenharmony_ci } 38148c2ecf20Sopenharmony_ci 38158c2ecf20Sopenharmony_ci if (bank == 0) { 38168c2ecf20Sopenharmony_ci new_bank_offset = nvm->flash_bank_size; 38178c2ecf20Sopenharmony_ci old_bank_offset = 0; 38188c2ecf20Sopenharmony_ci ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 38198c2ecf20Sopenharmony_ci if (ret_val) 38208c2ecf20Sopenharmony_ci goto release; 38218c2ecf20Sopenharmony_ci } else { 38228c2ecf20Sopenharmony_ci old_bank_offset = nvm->flash_bank_size; 38238c2ecf20Sopenharmony_ci new_bank_offset = 0; 38248c2ecf20Sopenharmony_ci ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 38258c2ecf20Sopenharmony_ci if (ret_val) 38268c2ecf20Sopenharmony_ci goto release; 38278c2ecf20Sopenharmony_ci } 38288c2ecf20Sopenharmony_ci for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i += 2) { 38298c2ecf20Sopenharmony_ci /* Determine whether to write the value stored 38308c2ecf20Sopenharmony_ci * in the other NVM bank or a modified value stored 38318c2ecf20Sopenharmony_ci * in the shadow RAM 38328c2ecf20Sopenharmony_ci */ 38338c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_dword_ich8lan(hw, 38348c2ecf20Sopenharmony_ci i + old_bank_offset, 38358c2ecf20Sopenharmony_ci &dword); 38368c2ecf20Sopenharmony_ci 38378c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[i].modified) { 38388c2ecf20Sopenharmony_ci dword &= 0xffff0000; 38398c2ecf20Sopenharmony_ci dword |= (dev_spec->shadow_ram[i].value & 0xffff); 38408c2ecf20Sopenharmony_ci } 38418c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[i + 1].modified) { 38428c2ecf20Sopenharmony_ci dword &= 0x0000ffff; 38438c2ecf20Sopenharmony_ci dword |= ((dev_spec->shadow_ram[i + 1].value & 0xffff) 38448c2ecf20Sopenharmony_ci << 16); 38458c2ecf20Sopenharmony_ci } 38468c2ecf20Sopenharmony_ci if (ret_val) 38478c2ecf20Sopenharmony_ci break; 38488c2ecf20Sopenharmony_ci 38498c2ecf20Sopenharmony_ci /* If the word is 0x13, then make sure the signature bits 38508c2ecf20Sopenharmony_ci * (15:14) are 11b until the commit has completed. 38518c2ecf20Sopenharmony_ci * This will allow us to write 10b which indicates the 38528c2ecf20Sopenharmony_ci * signature is valid. We want to do this after the write 38538c2ecf20Sopenharmony_ci * has completed so that we don't mark the segment valid 38548c2ecf20Sopenharmony_ci * while the write is still in progress 38558c2ecf20Sopenharmony_ci */ 38568c2ecf20Sopenharmony_ci if (i == E1000_ICH_NVM_SIG_WORD - 1) 38578c2ecf20Sopenharmony_ci dword |= E1000_ICH_NVM_SIG_MASK << 16; 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci /* Convert offset to bytes. */ 38608c2ecf20Sopenharmony_ci act_offset = (i + new_bank_offset) << 1; 38618c2ecf20Sopenharmony_ci 38628c2ecf20Sopenharmony_ci usleep_range(100, 200); 38638c2ecf20Sopenharmony_ci 38648c2ecf20Sopenharmony_ci /* Write the data to the new bank. Offset in words */ 38658c2ecf20Sopenharmony_ci act_offset = i + new_bank_offset; 38668c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, 38678c2ecf20Sopenharmony_ci dword); 38688c2ecf20Sopenharmony_ci if (ret_val) 38698c2ecf20Sopenharmony_ci break; 38708c2ecf20Sopenharmony_ci } 38718c2ecf20Sopenharmony_ci 38728c2ecf20Sopenharmony_ci /* Don't bother writing the segment valid bits if sector 38738c2ecf20Sopenharmony_ci * programming failed. 38748c2ecf20Sopenharmony_ci */ 38758c2ecf20Sopenharmony_ci if (ret_val) { 38768c2ecf20Sopenharmony_ci /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ 38778c2ecf20Sopenharmony_ci e_dbg("Flash commit failed.\n"); 38788c2ecf20Sopenharmony_ci goto release; 38798c2ecf20Sopenharmony_ci } 38808c2ecf20Sopenharmony_ci 38818c2ecf20Sopenharmony_ci /* Finally validate the new segment by setting bit 15:14 38828c2ecf20Sopenharmony_ci * to 10b in word 0x13 , this can be done without an 38838c2ecf20Sopenharmony_ci * erase as well since these bits are 11 to start with 38848c2ecf20Sopenharmony_ci * and we need to change bit 14 to 0b 38858c2ecf20Sopenharmony_ci */ 38868c2ecf20Sopenharmony_ci act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci /*offset in words but we read dword */ 38898c2ecf20Sopenharmony_ci --act_offset; 38908c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 38918c2ecf20Sopenharmony_ci 38928c2ecf20Sopenharmony_ci if (ret_val) 38938c2ecf20Sopenharmony_ci goto release; 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci dword &= 0xBFFFFFFF; 38968c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_ci if (ret_val) 38998c2ecf20Sopenharmony_ci goto release; 39008c2ecf20Sopenharmony_ci 39018c2ecf20Sopenharmony_ci /* And invalidate the previously valid segment by setting 39028c2ecf20Sopenharmony_ci * its signature word (0x13) high_byte to 0b. This can be 39038c2ecf20Sopenharmony_ci * done without an erase because flash erase sets all bits 39048c2ecf20Sopenharmony_ci * to 1's. We can write 1's to 0's without an erase 39058c2ecf20Sopenharmony_ci */ 39068c2ecf20Sopenharmony_ci act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 39078c2ecf20Sopenharmony_ci 39088c2ecf20Sopenharmony_ci /* offset in words but we read dword */ 39098c2ecf20Sopenharmony_ci act_offset = old_bank_offset + E1000_ICH_NVM_SIG_WORD - 1; 39108c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_dword_ich8lan(hw, act_offset, &dword); 39118c2ecf20Sopenharmony_ci 39128c2ecf20Sopenharmony_ci if (ret_val) 39138c2ecf20Sopenharmony_ci goto release; 39148c2ecf20Sopenharmony_ci 39158c2ecf20Sopenharmony_ci dword &= 0x00FFFFFF; 39168c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_dword_ich8lan(hw, act_offset, dword); 39178c2ecf20Sopenharmony_ci 39188c2ecf20Sopenharmony_ci if (ret_val) 39198c2ecf20Sopenharmony_ci goto release; 39208c2ecf20Sopenharmony_ci 39218c2ecf20Sopenharmony_ci /* Great! Everything worked, we can now clear the cached entries. */ 39228c2ecf20Sopenharmony_ci for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { 39238c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].modified = false; 39248c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].value = 0xFFFF; 39258c2ecf20Sopenharmony_ci } 39268c2ecf20Sopenharmony_ci 39278c2ecf20Sopenharmony_cirelease: 39288c2ecf20Sopenharmony_ci nvm->ops.release(hw); 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci /* Reload the EEPROM, or else modifications will not appear 39318c2ecf20Sopenharmony_ci * until after the next adapter reset. 39328c2ecf20Sopenharmony_ci */ 39338c2ecf20Sopenharmony_ci if (!ret_val) { 39348c2ecf20Sopenharmony_ci nvm->ops.reload(hw); 39358c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 39368c2ecf20Sopenharmony_ci } 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ciout: 39398c2ecf20Sopenharmony_ci if (ret_val) 39408c2ecf20Sopenharmony_ci e_dbg("NVM update error: %d\n", ret_val); 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci return ret_val; 39438c2ecf20Sopenharmony_ci} 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci/** 39468c2ecf20Sopenharmony_ci * e1000_update_nvm_checksum_ich8lan - Update the checksum for NVM 39478c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 39488c2ecf20Sopenharmony_ci * 39498c2ecf20Sopenharmony_ci * The NVM checksum is updated by calling the generic update_nvm_checksum, 39508c2ecf20Sopenharmony_ci * which writes the checksum to the shadow ram. The changes in the shadow 39518c2ecf20Sopenharmony_ci * ram are then committed to the EEPROM by processing each bank at a time 39528c2ecf20Sopenharmony_ci * checking for the modified bit and writing only the pending changes. 39538c2ecf20Sopenharmony_ci * After a successful commit, the shadow ram is cleared and is ready for 39548c2ecf20Sopenharmony_ci * future writes. 39558c2ecf20Sopenharmony_ci **/ 39568c2ecf20Sopenharmony_cistatic s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) 39578c2ecf20Sopenharmony_ci{ 39588c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 39598c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 39608c2ecf20Sopenharmony_ci u32 i, act_offset, new_bank_offset, old_bank_offset, bank; 39618c2ecf20Sopenharmony_ci s32 ret_val; 39628c2ecf20Sopenharmony_ci u16 data = 0; 39638c2ecf20Sopenharmony_ci 39648c2ecf20Sopenharmony_ci ret_val = e1000e_update_nvm_checksum_generic(hw); 39658c2ecf20Sopenharmony_ci if (ret_val) 39668c2ecf20Sopenharmony_ci goto out; 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci if (nvm->type != e1000_nvm_flash_sw) 39698c2ecf20Sopenharmony_ci goto out; 39708c2ecf20Sopenharmony_ci 39718c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 39728c2ecf20Sopenharmony_ci 39738c2ecf20Sopenharmony_ci /* We're writing to the opposite bank so if we're on bank 1, 39748c2ecf20Sopenharmony_ci * write to bank 0 etc. We also need to erase the segment that 39758c2ecf20Sopenharmony_ci * is going to be written 39768c2ecf20Sopenharmony_ci */ 39778c2ecf20Sopenharmony_ci ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); 39788c2ecf20Sopenharmony_ci if (ret_val) { 39798c2ecf20Sopenharmony_ci e_dbg("Could not detect valid bank, assuming bank 0\n"); 39808c2ecf20Sopenharmony_ci bank = 0; 39818c2ecf20Sopenharmony_ci } 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci if (bank == 0) { 39848c2ecf20Sopenharmony_ci new_bank_offset = nvm->flash_bank_size; 39858c2ecf20Sopenharmony_ci old_bank_offset = 0; 39868c2ecf20Sopenharmony_ci ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); 39878c2ecf20Sopenharmony_ci if (ret_val) 39888c2ecf20Sopenharmony_ci goto release; 39898c2ecf20Sopenharmony_ci } else { 39908c2ecf20Sopenharmony_ci old_bank_offset = nvm->flash_bank_size; 39918c2ecf20Sopenharmony_ci new_bank_offset = 0; 39928c2ecf20Sopenharmony_ci ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); 39938c2ecf20Sopenharmony_ci if (ret_val) 39948c2ecf20Sopenharmony_ci goto release; 39958c2ecf20Sopenharmony_ci } 39968c2ecf20Sopenharmony_ci for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { 39978c2ecf20Sopenharmony_ci if (dev_spec->shadow_ram[i].modified) { 39988c2ecf20Sopenharmony_ci data = dev_spec->shadow_ram[i].value; 39998c2ecf20Sopenharmony_ci } else { 40008c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_word_ich8lan(hw, i + 40018c2ecf20Sopenharmony_ci old_bank_offset, 40028c2ecf20Sopenharmony_ci &data); 40038c2ecf20Sopenharmony_ci if (ret_val) 40048c2ecf20Sopenharmony_ci break; 40058c2ecf20Sopenharmony_ci } 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci /* If the word is 0x13, then make sure the signature bits 40088c2ecf20Sopenharmony_ci * (15:14) are 11b until the commit has completed. 40098c2ecf20Sopenharmony_ci * This will allow us to write 10b which indicates the 40108c2ecf20Sopenharmony_ci * signature is valid. We want to do this after the write 40118c2ecf20Sopenharmony_ci * has completed so that we don't mark the segment valid 40128c2ecf20Sopenharmony_ci * while the write is still in progress 40138c2ecf20Sopenharmony_ci */ 40148c2ecf20Sopenharmony_ci if (i == E1000_ICH_NVM_SIG_WORD) 40158c2ecf20Sopenharmony_ci data |= E1000_ICH_NVM_SIG_MASK; 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci /* Convert offset to bytes. */ 40188c2ecf20Sopenharmony_ci act_offset = (i + new_bank_offset) << 1; 40198c2ecf20Sopenharmony_ci 40208c2ecf20Sopenharmony_ci usleep_range(100, 200); 40218c2ecf20Sopenharmony_ci /* Write the bytes to the new bank. */ 40228c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 40238c2ecf20Sopenharmony_ci act_offset, 40248c2ecf20Sopenharmony_ci (u8)data); 40258c2ecf20Sopenharmony_ci if (ret_val) 40268c2ecf20Sopenharmony_ci break; 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci usleep_range(100, 200); 40298c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 40308c2ecf20Sopenharmony_ci act_offset + 1, 40318c2ecf20Sopenharmony_ci (u8)(data >> 8)); 40328c2ecf20Sopenharmony_ci if (ret_val) 40338c2ecf20Sopenharmony_ci break; 40348c2ecf20Sopenharmony_ci } 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci /* Don't bother writing the segment valid bits if sector 40378c2ecf20Sopenharmony_ci * programming failed. 40388c2ecf20Sopenharmony_ci */ 40398c2ecf20Sopenharmony_ci if (ret_val) { 40408c2ecf20Sopenharmony_ci /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ 40418c2ecf20Sopenharmony_ci e_dbg("Flash commit failed.\n"); 40428c2ecf20Sopenharmony_ci goto release; 40438c2ecf20Sopenharmony_ci } 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci /* Finally validate the new segment by setting bit 15:14 40468c2ecf20Sopenharmony_ci * to 10b in word 0x13 , this can be done without an 40478c2ecf20Sopenharmony_ci * erase as well since these bits are 11 to start with 40488c2ecf20Sopenharmony_ci * and we need to change bit 14 to 0b 40498c2ecf20Sopenharmony_ci */ 40508c2ecf20Sopenharmony_ci act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; 40518c2ecf20Sopenharmony_ci ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); 40528c2ecf20Sopenharmony_ci if (ret_val) 40538c2ecf20Sopenharmony_ci goto release; 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci data &= 0xBFFF; 40568c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_byte_ich8lan(hw, 40578c2ecf20Sopenharmony_ci act_offset * 2 + 1, 40588c2ecf20Sopenharmony_ci (u8)(data >> 8)); 40598c2ecf20Sopenharmony_ci if (ret_val) 40608c2ecf20Sopenharmony_ci goto release; 40618c2ecf20Sopenharmony_ci 40628c2ecf20Sopenharmony_ci /* And invalidate the previously valid segment by setting 40638c2ecf20Sopenharmony_ci * its signature word (0x13) high_byte to 0b. This can be 40648c2ecf20Sopenharmony_ci * done without an erase because flash erase sets all bits 40658c2ecf20Sopenharmony_ci * to 1's. We can write 1's to 0's without an erase 40668c2ecf20Sopenharmony_ci */ 40678c2ecf20Sopenharmony_ci act_offset = (old_bank_offset + E1000_ICH_NVM_SIG_WORD) * 2 + 1; 40688c2ecf20Sopenharmony_ci ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); 40698c2ecf20Sopenharmony_ci if (ret_val) 40708c2ecf20Sopenharmony_ci goto release; 40718c2ecf20Sopenharmony_ci 40728c2ecf20Sopenharmony_ci /* Great! Everything worked, we can now clear the cached entries. */ 40738c2ecf20Sopenharmony_ci for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { 40748c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].modified = false; 40758c2ecf20Sopenharmony_ci dev_spec->shadow_ram[i].value = 0xFFFF; 40768c2ecf20Sopenharmony_ci } 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_cirelease: 40798c2ecf20Sopenharmony_ci nvm->ops.release(hw); 40808c2ecf20Sopenharmony_ci 40818c2ecf20Sopenharmony_ci /* Reload the EEPROM, or else modifications will not appear 40828c2ecf20Sopenharmony_ci * until after the next adapter reset. 40838c2ecf20Sopenharmony_ci */ 40848c2ecf20Sopenharmony_ci if (!ret_val) { 40858c2ecf20Sopenharmony_ci nvm->ops.reload(hw); 40868c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 40878c2ecf20Sopenharmony_ci } 40888c2ecf20Sopenharmony_ci 40898c2ecf20Sopenharmony_ciout: 40908c2ecf20Sopenharmony_ci if (ret_val) 40918c2ecf20Sopenharmony_ci e_dbg("NVM update error: %d\n", ret_val); 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci return ret_val; 40948c2ecf20Sopenharmony_ci} 40958c2ecf20Sopenharmony_ci 40968c2ecf20Sopenharmony_ci/** 40978c2ecf20Sopenharmony_ci * e1000_validate_nvm_checksum_ich8lan - Validate EEPROM checksum 40988c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 40998c2ecf20Sopenharmony_ci * 41008c2ecf20Sopenharmony_ci * Check to see if checksum needs to be fixed by reading bit 6 in word 0x19. 41018c2ecf20Sopenharmony_ci * If the bit is 0, that the EEPROM had been modified, but the checksum was not 41028c2ecf20Sopenharmony_ci * calculated, in which case we need to calculate the checksum and set bit 6. 41038c2ecf20Sopenharmony_ci **/ 41048c2ecf20Sopenharmony_cistatic s32 e1000_validate_nvm_checksum_ich8lan(struct e1000_hw *hw) 41058c2ecf20Sopenharmony_ci{ 41068c2ecf20Sopenharmony_ci s32 ret_val; 41078c2ecf20Sopenharmony_ci u16 data; 41088c2ecf20Sopenharmony_ci u16 word; 41098c2ecf20Sopenharmony_ci u16 valid_csum_mask; 41108c2ecf20Sopenharmony_ci 41118c2ecf20Sopenharmony_ci /* Read NVM and check Invalid Image CSUM bit. If this bit is 0, 41128c2ecf20Sopenharmony_ci * the checksum needs to be fixed. This bit is an indication that 41138c2ecf20Sopenharmony_ci * the NVM was prepared by OEM software and did not calculate 41148c2ecf20Sopenharmony_ci * the checksum...a likely scenario. 41158c2ecf20Sopenharmony_ci */ 41168c2ecf20Sopenharmony_ci switch (hw->mac.type) { 41178c2ecf20Sopenharmony_ci case e1000_pch_lpt: 41188c2ecf20Sopenharmony_ci case e1000_pch_spt: 41198c2ecf20Sopenharmony_ci case e1000_pch_cnp: 41208c2ecf20Sopenharmony_ci case e1000_pch_tgp: 41218c2ecf20Sopenharmony_ci case e1000_pch_adp: 41228c2ecf20Sopenharmony_ci case e1000_pch_mtp: 41238c2ecf20Sopenharmony_ci word = NVM_COMPAT; 41248c2ecf20Sopenharmony_ci valid_csum_mask = NVM_COMPAT_VALID_CSUM; 41258c2ecf20Sopenharmony_ci break; 41268c2ecf20Sopenharmony_ci default: 41278c2ecf20Sopenharmony_ci word = NVM_FUTURE_INIT_WORD1; 41288c2ecf20Sopenharmony_ci valid_csum_mask = NVM_FUTURE_INIT_WORD1_VALID_CSUM; 41298c2ecf20Sopenharmony_ci break; 41308c2ecf20Sopenharmony_ci } 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci ret_val = e1000_read_nvm(hw, word, 1, &data); 41338c2ecf20Sopenharmony_ci if (ret_val) 41348c2ecf20Sopenharmony_ci return ret_val; 41358c2ecf20Sopenharmony_ci 41368c2ecf20Sopenharmony_ci if (!(data & valid_csum_mask)) { 41378c2ecf20Sopenharmony_ci e_dbg("NVM Checksum valid bit not set\n"); 41388c2ecf20Sopenharmony_ci 41398c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch_tgp) { 41408c2ecf20Sopenharmony_ci data |= valid_csum_mask; 41418c2ecf20Sopenharmony_ci ret_val = e1000_write_nvm(hw, word, 1, &data); 41428c2ecf20Sopenharmony_ci if (ret_val) 41438c2ecf20Sopenharmony_ci return ret_val; 41448c2ecf20Sopenharmony_ci ret_val = e1000e_update_nvm_checksum(hw); 41458c2ecf20Sopenharmony_ci if (ret_val) 41468c2ecf20Sopenharmony_ci return ret_val; 41478c2ecf20Sopenharmony_ci } 41488c2ecf20Sopenharmony_ci } 41498c2ecf20Sopenharmony_ci 41508c2ecf20Sopenharmony_ci return e1000e_validate_nvm_checksum_generic(hw); 41518c2ecf20Sopenharmony_ci} 41528c2ecf20Sopenharmony_ci 41538c2ecf20Sopenharmony_ci/** 41548c2ecf20Sopenharmony_ci * e1000e_write_protect_nvm_ich8lan - Make the NVM read-only 41558c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 41568c2ecf20Sopenharmony_ci * 41578c2ecf20Sopenharmony_ci * To prevent malicious write/erase of the NVM, set it to be read-only 41588c2ecf20Sopenharmony_ci * so that the hardware ignores all write/erase cycles of the NVM via 41598c2ecf20Sopenharmony_ci * the flash control registers. The shadow-ram copy of the NVM will 41608c2ecf20Sopenharmony_ci * still be updated, however any updates to this copy will not stick 41618c2ecf20Sopenharmony_ci * across driver reloads. 41628c2ecf20Sopenharmony_ci **/ 41638c2ecf20Sopenharmony_civoid e1000e_write_protect_nvm_ich8lan(struct e1000_hw *hw) 41648c2ecf20Sopenharmony_ci{ 41658c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 41668c2ecf20Sopenharmony_ci union ich8_flash_protected_range pr0; 41678c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 41688c2ecf20Sopenharmony_ci u32 gfpreg; 41698c2ecf20Sopenharmony_ci 41708c2ecf20Sopenharmony_ci nvm->ops.acquire(hw); 41718c2ecf20Sopenharmony_ci 41728c2ecf20Sopenharmony_ci gfpreg = er32flash(ICH_FLASH_GFPREG); 41738c2ecf20Sopenharmony_ci 41748c2ecf20Sopenharmony_ci /* Write-protect GbE Sector of NVM */ 41758c2ecf20Sopenharmony_ci pr0.regval = er32flash(ICH_FLASH_PR0); 41768c2ecf20Sopenharmony_ci pr0.range.base = gfpreg & FLASH_GFPREG_BASE_MASK; 41778c2ecf20Sopenharmony_ci pr0.range.limit = ((gfpreg >> 16) & FLASH_GFPREG_BASE_MASK); 41788c2ecf20Sopenharmony_ci pr0.range.wpe = true; 41798c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_PR0, pr0.regval); 41808c2ecf20Sopenharmony_ci 41818c2ecf20Sopenharmony_ci /* Lock down a subset of GbE Flash Control Registers, e.g. 41828c2ecf20Sopenharmony_ci * PR0 to prevent the write-protection from being lifted. 41838c2ecf20Sopenharmony_ci * Once FLOCKDN is set, the registers protected by it cannot 41848c2ecf20Sopenharmony_ci * be written until FLOCKDN is cleared by a hardware reset. 41858c2ecf20Sopenharmony_ci */ 41868c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 41878c2ecf20Sopenharmony_ci hsfsts.hsf_status.flockdn = true; 41888c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsfsts.regval); 41898c2ecf20Sopenharmony_ci 41908c2ecf20Sopenharmony_ci nvm->ops.release(hw); 41918c2ecf20Sopenharmony_ci} 41928c2ecf20Sopenharmony_ci 41938c2ecf20Sopenharmony_ci/** 41948c2ecf20Sopenharmony_ci * e1000_write_flash_data_ich8lan - Writes bytes to the NVM 41958c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 41968c2ecf20Sopenharmony_ci * @offset: The offset (in bytes) of the byte/word to read. 41978c2ecf20Sopenharmony_ci * @size: Size of data to read, 1=byte 2=word 41988c2ecf20Sopenharmony_ci * @data: The byte(s) to write to the NVM. 41998c2ecf20Sopenharmony_ci * 42008c2ecf20Sopenharmony_ci * Writes one/two bytes to the NVM using the flash access registers. 42018c2ecf20Sopenharmony_ci **/ 42028c2ecf20Sopenharmony_cistatic s32 e1000_write_flash_data_ich8lan(struct e1000_hw *hw, u32 offset, 42038c2ecf20Sopenharmony_ci u8 size, u16 data) 42048c2ecf20Sopenharmony_ci{ 42058c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 42068c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 42078c2ecf20Sopenharmony_ci u32 flash_linear_addr; 42088c2ecf20Sopenharmony_ci u32 flash_data = 0; 42098c2ecf20Sopenharmony_ci s32 ret_val; 42108c2ecf20Sopenharmony_ci u8 count = 0; 42118c2ecf20Sopenharmony_ci 42128c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) { 42138c2ecf20Sopenharmony_ci if (size != 4 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 42148c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 42158c2ecf20Sopenharmony_ci } else { 42168c2ecf20Sopenharmony_ci if (size < 1 || size > 2 || offset > ICH_FLASH_LINEAR_ADDR_MASK) 42178c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 42188c2ecf20Sopenharmony_ci } 42198c2ecf20Sopenharmony_ci 42208c2ecf20Sopenharmony_ci flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 42218c2ecf20Sopenharmony_ci hw->nvm.flash_base_addr); 42228c2ecf20Sopenharmony_ci 42238c2ecf20Sopenharmony_ci do { 42248c2ecf20Sopenharmony_ci udelay(1); 42258c2ecf20Sopenharmony_ci /* Steps */ 42268c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_init_ich8lan(hw); 42278c2ecf20Sopenharmony_ci if (ret_val) 42288c2ecf20Sopenharmony_ci break; 42298c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, not 42308c2ecf20Sopenharmony_ci * flash. Therefore, only 32 bit access is supported 42318c2ecf20Sopenharmony_ci */ 42328c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 42338c2ecf20Sopenharmony_ci hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) >> 16; 42348c2ecf20Sopenharmony_ci else 42358c2ecf20Sopenharmony_ci hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); 42368c2ecf20Sopenharmony_ci 42378c2ecf20Sopenharmony_ci /* 0b/1b corresponds to 1 or 2 byte size, respectively. */ 42388c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.fldbcount = size - 1; 42398c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 42408c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, 42418c2ecf20Sopenharmony_ci * not flash. Therefore, only 32 bit access is 42428c2ecf20Sopenharmony_ci * supported 42438c2ecf20Sopenharmony_ci */ 42448c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 42458c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16); 42468c2ecf20Sopenharmony_ci else 42478c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); 42488c2ecf20Sopenharmony_ci 42498c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FADDR, flash_linear_addr); 42508c2ecf20Sopenharmony_ci 42518c2ecf20Sopenharmony_ci if (size == 1) 42528c2ecf20Sopenharmony_ci flash_data = (u32)data & 0x00FF; 42538c2ecf20Sopenharmony_ci else 42548c2ecf20Sopenharmony_ci flash_data = (u32)data; 42558c2ecf20Sopenharmony_ci 42568c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FDATA0, flash_data); 42578c2ecf20Sopenharmony_ci 42588c2ecf20Sopenharmony_ci /* check if FCERR is set to 1 , if set to 1, clear it 42598c2ecf20Sopenharmony_ci * and try the whole sequence a few more times else done 42608c2ecf20Sopenharmony_ci */ 42618c2ecf20Sopenharmony_ci ret_val = 42628c2ecf20Sopenharmony_ci e1000_flash_cycle_ich8lan(hw, 42638c2ecf20Sopenharmony_ci ICH_FLASH_WRITE_COMMAND_TIMEOUT); 42648c2ecf20Sopenharmony_ci if (!ret_val) 42658c2ecf20Sopenharmony_ci break; 42668c2ecf20Sopenharmony_ci 42678c2ecf20Sopenharmony_ci /* If we're here, then things are most likely 42688c2ecf20Sopenharmony_ci * completely hosed, but if the error condition 42698c2ecf20Sopenharmony_ci * is detected, it won't hurt to give it another 42708c2ecf20Sopenharmony_ci * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 42718c2ecf20Sopenharmony_ci */ 42728c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 42738c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcerr) 42748c2ecf20Sopenharmony_ci /* Repeat for some time before giving up. */ 42758c2ecf20Sopenharmony_ci continue; 42768c2ecf20Sopenharmony_ci if (!hsfsts.hsf_status.flcdone) { 42778c2ecf20Sopenharmony_ci e_dbg("Timeout error - flash cycle did not complete.\n"); 42788c2ecf20Sopenharmony_ci break; 42798c2ecf20Sopenharmony_ci } 42808c2ecf20Sopenharmony_ci } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 42818c2ecf20Sopenharmony_ci 42828c2ecf20Sopenharmony_ci return ret_val; 42838c2ecf20Sopenharmony_ci} 42848c2ecf20Sopenharmony_ci 42858c2ecf20Sopenharmony_ci/** 42868c2ecf20Sopenharmony_ci* e1000_write_flash_data32_ich8lan - Writes 4 bytes to the NVM 42878c2ecf20Sopenharmony_ci* @hw: pointer to the HW structure 42888c2ecf20Sopenharmony_ci* @offset: The offset (in bytes) of the dwords to read. 42898c2ecf20Sopenharmony_ci* @data: The 4 bytes to write to the NVM. 42908c2ecf20Sopenharmony_ci* 42918c2ecf20Sopenharmony_ci* Writes one/two/four bytes to the NVM using the flash access registers. 42928c2ecf20Sopenharmony_ci**/ 42938c2ecf20Sopenharmony_cistatic s32 e1000_write_flash_data32_ich8lan(struct e1000_hw *hw, u32 offset, 42948c2ecf20Sopenharmony_ci u32 data) 42958c2ecf20Sopenharmony_ci{ 42968c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 42978c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 42988c2ecf20Sopenharmony_ci u32 flash_linear_addr; 42998c2ecf20Sopenharmony_ci s32 ret_val; 43008c2ecf20Sopenharmony_ci u8 count = 0; 43018c2ecf20Sopenharmony_ci 43028c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) { 43038c2ecf20Sopenharmony_ci if (offset > ICH_FLASH_LINEAR_ADDR_MASK) 43048c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 43058c2ecf20Sopenharmony_ci } 43068c2ecf20Sopenharmony_ci flash_linear_addr = ((ICH_FLASH_LINEAR_ADDR_MASK & offset) + 43078c2ecf20Sopenharmony_ci hw->nvm.flash_base_addr); 43088c2ecf20Sopenharmony_ci do { 43098c2ecf20Sopenharmony_ci udelay(1); 43108c2ecf20Sopenharmony_ci /* Steps */ 43118c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_init_ich8lan(hw); 43128c2ecf20Sopenharmony_ci if (ret_val) 43138c2ecf20Sopenharmony_ci break; 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, not 43168c2ecf20Sopenharmony_ci * flash. Therefore, only 32 bit access is supported 43178c2ecf20Sopenharmony_ci */ 43188c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 43198c2ecf20Sopenharmony_ci hsflctl.regval = er32flash(ICH_FLASH_HSFSTS) 43208c2ecf20Sopenharmony_ci >> 16; 43218c2ecf20Sopenharmony_ci else 43228c2ecf20Sopenharmony_ci hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); 43238c2ecf20Sopenharmony_ci 43248c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.fldbcount = sizeof(u32) - 1; 43258c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_WRITE; 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci /* In SPT, This register is in Lan memory space, 43288c2ecf20Sopenharmony_ci * not flash. Therefore, only 32 bit access is 43298c2ecf20Sopenharmony_ci * supported 43308c2ecf20Sopenharmony_ci */ 43318c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 43328c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, hsflctl.regval << 16); 43338c2ecf20Sopenharmony_ci else 43348c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); 43358c2ecf20Sopenharmony_ci 43368c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FADDR, flash_linear_addr); 43378c2ecf20Sopenharmony_ci 43388c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FDATA0, data); 43398c2ecf20Sopenharmony_ci 43408c2ecf20Sopenharmony_ci /* check if FCERR is set to 1 , if set to 1, clear it 43418c2ecf20Sopenharmony_ci * and try the whole sequence a few more times else done 43428c2ecf20Sopenharmony_ci */ 43438c2ecf20Sopenharmony_ci ret_val = 43448c2ecf20Sopenharmony_ci e1000_flash_cycle_ich8lan(hw, 43458c2ecf20Sopenharmony_ci ICH_FLASH_WRITE_COMMAND_TIMEOUT); 43468c2ecf20Sopenharmony_ci 43478c2ecf20Sopenharmony_ci if (!ret_val) 43488c2ecf20Sopenharmony_ci break; 43498c2ecf20Sopenharmony_ci 43508c2ecf20Sopenharmony_ci /* If we're here, then things are most likely 43518c2ecf20Sopenharmony_ci * completely hosed, but if the error condition 43528c2ecf20Sopenharmony_ci * is detected, it won't hurt to give it another 43538c2ecf20Sopenharmony_ci * try...ICH_FLASH_CYCLE_REPEAT_COUNT times. 43548c2ecf20Sopenharmony_ci */ 43558c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 43568c2ecf20Sopenharmony_ci 43578c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcerr) 43588c2ecf20Sopenharmony_ci /* Repeat for some time before giving up. */ 43598c2ecf20Sopenharmony_ci continue; 43608c2ecf20Sopenharmony_ci if (!hsfsts.hsf_status.flcdone) { 43618c2ecf20Sopenharmony_ci e_dbg("Timeout error - flash cycle did not complete.\n"); 43628c2ecf20Sopenharmony_ci break; 43638c2ecf20Sopenharmony_ci } 43648c2ecf20Sopenharmony_ci } while (count++ < ICH_FLASH_CYCLE_REPEAT_COUNT); 43658c2ecf20Sopenharmony_ci 43668c2ecf20Sopenharmony_ci return ret_val; 43678c2ecf20Sopenharmony_ci} 43688c2ecf20Sopenharmony_ci 43698c2ecf20Sopenharmony_ci/** 43708c2ecf20Sopenharmony_ci * e1000_write_flash_byte_ich8lan - Write a single byte to NVM 43718c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 43728c2ecf20Sopenharmony_ci * @offset: The index of the byte to read. 43738c2ecf20Sopenharmony_ci * @data: The byte to write to the NVM. 43748c2ecf20Sopenharmony_ci * 43758c2ecf20Sopenharmony_ci * Writes a single byte to the NVM using the flash access registers. 43768c2ecf20Sopenharmony_ci **/ 43778c2ecf20Sopenharmony_cistatic s32 e1000_write_flash_byte_ich8lan(struct e1000_hw *hw, u32 offset, 43788c2ecf20Sopenharmony_ci u8 data) 43798c2ecf20Sopenharmony_ci{ 43808c2ecf20Sopenharmony_ci u16 word = (u16)data; 43818c2ecf20Sopenharmony_ci 43828c2ecf20Sopenharmony_ci return e1000_write_flash_data_ich8lan(hw, offset, 1, word); 43838c2ecf20Sopenharmony_ci} 43848c2ecf20Sopenharmony_ci 43858c2ecf20Sopenharmony_ci/** 43868c2ecf20Sopenharmony_ci* e1000_retry_write_flash_dword_ich8lan - Writes a dword to NVM 43878c2ecf20Sopenharmony_ci* @hw: pointer to the HW structure 43888c2ecf20Sopenharmony_ci* @offset: The offset of the word to write. 43898c2ecf20Sopenharmony_ci* @dword: The dword to write to the NVM. 43908c2ecf20Sopenharmony_ci* 43918c2ecf20Sopenharmony_ci* Writes a single dword to the NVM using the flash access registers. 43928c2ecf20Sopenharmony_ci* Goes through a retry algorithm before giving up. 43938c2ecf20Sopenharmony_ci**/ 43948c2ecf20Sopenharmony_cistatic s32 e1000_retry_write_flash_dword_ich8lan(struct e1000_hw *hw, 43958c2ecf20Sopenharmony_ci u32 offset, u32 dword) 43968c2ecf20Sopenharmony_ci{ 43978c2ecf20Sopenharmony_ci s32 ret_val; 43988c2ecf20Sopenharmony_ci u16 program_retries; 43998c2ecf20Sopenharmony_ci 44008c2ecf20Sopenharmony_ci /* Must convert word offset into bytes. */ 44018c2ecf20Sopenharmony_ci offset <<= 1; 44028c2ecf20Sopenharmony_ci ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 44038c2ecf20Sopenharmony_ci 44048c2ecf20Sopenharmony_ci if (!ret_val) 44058c2ecf20Sopenharmony_ci return ret_val; 44068c2ecf20Sopenharmony_ci for (program_retries = 0; program_retries < 100; program_retries++) { 44078c2ecf20Sopenharmony_ci e_dbg("Retrying Byte %8.8X at offset %u\n", dword, offset); 44088c2ecf20Sopenharmony_ci usleep_range(100, 200); 44098c2ecf20Sopenharmony_ci ret_val = e1000_write_flash_data32_ich8lan(hw, offset, dword); 44108c2ecf20Sopenharmony_ci if (!ret_val) 44118c2ecf20Sopenharmony_ci break; 44128c2ecf20Sopenharmony_ci } 44138c2ecf20Sopenharmony_ci if (program_retries == 100) 44148c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 44158c2ecf20Sopenharmony_ci 44168c2ecf20Sopenharmony_ci return 0; 44178c2ecf20Sopenharmony_ci} 44188c2ecf20Sopenharmony_ci 44198c2ecf20Sopenharmony_ci/** 44208c2ecf20Sopenharmony_ci * e1000_retry_write_flash_byte_ich8lan - Writes a single byte to NVM 44218c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 44228c2ecf20Sopenharmony_ci * @offset: The offset of the byte to write. 44238c2ecf20Sopenharmony_ci * @byte: The byte to write to the NVM. 44248c2ecf20Sopenharmony_ci * 44258c2ecf20Sopenharmony_ci * Writes a single byte to the NVM using the flash access registers. 44268c2ecf20Sopenharmony_ci * Goes through a retry algorithm before giving up. 44278c2ecf20Sopenharmony_ci **/ 44288c2ecf20Sopenharmony_cistatic s32 e1000_retry_write_flash_byte_ich8lan(struct e1000_hw *hw, 44298c2ecf20Sopenharmony_ci u32 offset, u8 byte) 44308c2ecf20Sopenharmony_ci{ 44318c2ecf20Sopenharmony_ci s32 ret_val; 44328c2ecf20Sopenharmony_ci u16 program_retries; 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_ci ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 44358c2ecf20Sopenharmony_ci if (!ret_val) 44368c2ecf20Sopenharmony_ci return ret_val; 44378c2ecf20Sopenharmony_ci 44388c2ecf20Sopenharmony_ci for (program_retries = 0; program_retries < 100; program_retries++) { 44398c2ecf20Sopenharmony_ci e_dbg("Retrying Byte %2.2X at offset %u\n", byte, offset); 44408c2ecf20Sopenharmony_ci usleep_range(100, 200); 44418c2ecf20Sopenharmony_ci ret_val = e1000_write_flash_byte_ich8lan(hw, offset, byte); 44428c2ecf20Sopenharmony_ci if (!ret_val) 44438c2ecf20Sopenharmony_ci break; 44448c2ecf20Sopenharmony_ci } 44458c2ecf20Sopenharmony_ci if (program_retries == 100) 44468c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 44478c2ecf20Sopenharmony_ci 44488c2ecf20Sopenharmony_ci return 0; 44498c2ecf20Sopenharmony_ci} 44508c2ecf20Sopenharmony_ci 44518c2ecf20Sopenharmony_ci/** 44528c2ecf20Sopenharmony_ci * e1000_erase_flash_bank_ich8lan - Erase a bank (4k) from NVM 44538c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 44548c2ecf20Sopenharmony_ci * @bank: 0 for first bank, 1 for second bank, etc. 44558c2ecf20Sopenharmony_ci * 44568c2ecf20Sopenharmony_ci * Erases the bank specified. Each bank is a 4k block. Banks are 0 based. 44578c2ecf20Sopenharmony_ci * bank N is 4096 * N + flash_reg_addr. 44588c2ecf20Sopenharmony_ci **/ 44598c2ecf20Sopenharmony_cistatic s32 e1000_erase_flash_bank_ich8lan(struct e1000_hw *hw, u32 bank) 44608c2ecf20Sopenharmony_ci{ 44618c2ecf20Sopenharmony_ci struct e1000_nvm_info *nvm = &hw->nvm; 44628c2ecf20Sopenharmony_ci union ich8_hws_flash_status hsfsts; 44638c2ecf20Sopenharmony_ci union ich8_hws_flash_ctrl hsflctl; 44648c2ecf20Sopenharmony_ci u32 flash_linear_addr; 44658c2ecf20Sopenharmony_ci /* bank size is in 16bit words - adjust to bytes */ 44668c2ecf20Sopenharmony_ci u32 flash_bank_size = nvm->flash_bank_size * 2; 44678c2ecf20Sopenharmony_ci s32 ret_val; 44688c2ecf20Sopenharmony_ci s32 count = 0; 44698c2ecf20Sopenharmony_ci s32 j, iteration, sector_size; 44708c2ecf20Sopenharmony_ci 44718c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 44728c2ecf20Sopenharmony_ci 44738c2ecf20Sopenharmony_ci /* Determine HW Sector size: Read BERASE bits of hw flash status 44748c2ecf20Sopenharmony_ci * register 44758c2ecf20Sopenharmony_ci * 00: The Hw sector is 256 bytes, hence we need to erase 16 44768c2ecf20Sopenharmony_ci * consecutive sectors. The start index for the nth Hw sector 44778c2ecf20Sopenharmony_ci * can be calculated as = bank * 4096 + n * 256 44788c2ecf20Sopenharmony_ci * 01: The Hw sector is 4K bytes, hence we need to erase 1 sector. 44798c2ecf20Sopenharmony_ci * The start index for the nth Hw sector can be calculated 44808c2ecf20Sopenharmony_ci * as = bank * 4096 44818c2ecf20Sopenharmony_ci * 10: The Hw sector is 8K bytes, nth sector = bank * 8192 44828c2ecf20Sopenharmony_ci * (ich9 only, otherwise error condition) 44838c2ecf20Sopenharmony_ci * 11: The Hw sector is 64K bytes, nth sector = bank * 65536 44848c2ecf20Sopenharmony_ci */ 44858c2ecf20Sopenharmony_ci switch (hsfsts.hsf_status.berasesz) { 44868c2ecf20Sopenharmony_ci case 0: 44878c2ecf20Sopenharmony_ci /* Hw sector size 256 */ 44888c2ecf20Sopenharmony_ci sector_size = ICH_FLASH_SEG_SIZE_256; 44898c2ecf20Sopenharmony_ci iteration = flash_bank_size / ICH_FLASH_SEG_SIZE_256; 44908c2ecf20Sopenharmony_ci break; 44918c2ecf20Sopenharmony_ci case 1: 44928c2ecf20Sopenharmony_ci sector_size = ICH_FLASH_SEG_SIZE_4K; 44938c2ecf20Sopenharmony_ci iteration = 1; 44948c2ecf20Sopenharmony_ci break; 44958c2ecf20Sopenharmony_ci case 2: 44968c2ecf20Sopenharmony_ci sector_size = ICH_FLASH_SEG_SIZE_8K; 44978c2ecf20Sopenharmony_ci iteration = 1; 44988c2ecf20Sopenharmony_ci break; 44998c2ecf20Sopenharmony_ci case 3: 45008c2ecf20Sopenharmony_ci sector_size = ICH_FLASH_SEG_SIZE_64K; 45018c2ecf20Sopenharmony_ci iteration = 1; 45028c2ecf20Sopenharmony_ci break; 45038c2ecf20Sopenharmony_ci default: 45048c2ecf20Sopenharmony_ci return -E1000_ERR_NVM; 45058c2ecf20Sopenharmony_ci } 45068c2ecf20Sopenharmony_ci 45078c2ecf20Sopenharmony_ci /* Start with the base address, then add the sector offset. */ 45088c2ecf20Sopenharmony_ci flash_linear_addr = hw->nvm.flash_base_addr; 45098c2ecf20Sopenharmony_ci flash_linear_addr += (bank) ? flash_bank_size : 0; 45108c2ecf20Sopenharmony_ci 45118c2ecf20Sopenharmony_ci for (j = 0; j < iteration; j++) { 45128c2ecf20Sopenharmony_ci do { 45138c2ecf20Sopenharmony_ci u32 timeout = ICH_FLASH_ERASE_COMMAND_TIMEOUT; 45148c2ecf20Sopenharmony_ci 45158c2ecf20Sopenharmony_ci /* Steps */ 45168c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_init_ich8lan(hw); 45178c2ecf20Sopenharmony_ci if (ret_val) 45188c2ecf20Sopenharmony_ci return ret_val; 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci /* Write a value 11 (block Erase) in Flash 45218c2ecf20Sopenharmony_ci * Cycle field in hw flash control 45228c2ecf20Sopenharmony_ci */ 45238c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 45248c2ecf20Sopenharmony_ci hsflctl.regval = 45258c2ecf20Sopenharmony_ci er32flash(ICH_FLASH_HSFSTS) >> 16; 45268c2ecf20Sopenharmony_ci else 45278c2ecf20Sopenharmony_ci hsflctl.regval = er16flash(ICH_FLASH_HSFCTL); 45288c2ecf20Sopenharmony_ci 45298c2ecf20Sopenharmony_ci hsflctl.hsf_ctrl.flcycle = ICH_CYCLE_ERASE; 45308c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_spt) 45318c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_HSFSTS, 45328c2ecf20Sopenharmony_ci hsflctl.regval << 16); 45338c2ecf20Sopenharmony_ci else 45348c2ecf20Sopenharmony_ci ew16flash(ICH_FLASH_HSFCTL, hsflctl.regval); 45358c2ecf20Sopenharmony_ci 45368c2ecf20Sopenharmony_ci /* Write the last 24 bits of an index within the 45378c2ecf20Sopenharmony_ci * block into Flash Linear address field in Flash 45388c2ecf20Sopenharmony_ci * Address. 45398c2ecf20Sopenharmony_ci */ 45408c2ecf20Sopenharmony_ci flash_linear_addr += (j * sector_size); 45418c2ecf20Sopenharmony_ci ew32flash(ICH_FLASH_FADDR, flash_linear_addr); 45428c2ecf20Sopenharmony_ci 45438c2ecf20Sopenharmony_ci ret_val = e1000_flash_cycle_ich8lan(hw, timeout); 45448c2ecf20Sopenharmony_ci if (!ret_val) 45458c2ecf20Sopenharmony_ci break; 45468c2ecf20Sopenharmony_ci 45478c2ecf20Sopenharmony_ci /* Check if FCERR is set to 1. If 1, 45488c2ecf20Sopenharmony_ci * clear it and try the whole sequence 45498c2ecf20Sopenharmony_ci * a few more times else Done 45508c2ecf20Sopenharmony_ci */ 45518c2ecf20Sopenharmony_ci hsfsts.regval = er16flash(ICH_FLASH_HSFSTS); 45528c2ecf20Sopenharmony_ci if (hsfsts.hsf_status.flcerr) 45538c2ecf20Sopenharmony_ci /* repeat for some time before giving up */ 45548c2ecf20Sopenharmony_ci continue; 45558c2ecf20Sopenharmony_ci else if (!hsfsts.hsf_status.flcdone) 45568c2ecf20Sopenharmony_ci return ret_val; 45578c2ecf20Sopenharmony_ci } while (++count < ICH_FLASH_CYCLE_REPEAT_COUNT); 45588c2ecf20Sopenharmony_ci } 45598c2ecf20Sopenharmony_ci 45608c2ecf20Sopenharmony_ci return 0; 45618c2ecf20Sopenharmony_ci} 45628c2ecf20Sopenharmony_ci 45638c2ecf20Sopenharmony_ci/** 45648c2ecf20Sopenharmony_ci * e1000_valid_led_default_ich8lan - Set the default LED settings 45658c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 45668c2ecf20Sopenharmony_ci * @data: Pointer to the LED settings 45678c2ecf20Sopenharmony_ci * 45688c2ecf20Sopenharmony_ci * Reads the LED default settings from the NVM to data. If the NVM LED 45698c2ecf20Sopenharmony_ci * settings is all 0's or F's, set the LED default to a valid LED default 45708c2ecf20Sopenharmony_ci * setting. 45718c2ecf20Sopenharmony_ci **/ 45728c2ecf20Sopenharmony_cistatic s32 e1000_valid_led_default_ich8lan(struct e1000_hw *hw, u16 *data) 45738c2ecf20Sopenharmony_ci{ 45748c2ecf20Sopenharmony_ci s32 ret_val; 45758c2ecf20Sopenharmony_ci 45768c2ecf20Sopenharmony_ci ret_val = e1000_read_nvm(hw, NVM_ID_LED_SETTINGS, 1, data); 45778c2ecf20Sopenharmony_ci if (ret_val) { 45788c2ecf20Sopenharmony_ci e_dbg("NVM Read Error\n"); 45798c2ecf20Sopenharmony_ci return ret_val; 45808c2ecf20Sopenharmony_ci } 45818c2ecf20Sopenharmony_ci 45828c2ecf20Sopenharmony_ci if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF) 45838c2ecf20Sopenharmony_ci *data = ID_LED_DEFAULT_ICH8LAN; 45848c2ecf20Sopenharmony_ci 45858c2ecf20Sopenharmony_ci return 0; 45868c2ecf20Sopenharmony_ci} 45878c2ecf20Sopenharmony_ci 45888c2ecf20Sopenharmony_ci/** 45898c2ecf20Sopenharmony_ci * e1000_id_led_init_pchlan - store LED configurations 45908c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 45918c2ecf20Sopenharmony_ci * 45928c2ecf20Sopenharmony_ci * PCH does not control LEDs via the LEDCTL register, rather it uses 45938c2ecf20Sopenharmony_ci * the PHY LED configuration register. 45948c2ecf20Sopenharmony_ci * 45958c2ecf20Sopenharmony_ci * PCH also does not have an "always on" or "always off" mode which 45968c2ecf20Sopenharmony_ci * complicates the ID feature. Instead of using the "on" mode to indicate 45978c2ecf20Sopenharmony_ci * in ledctl_mode2 the LEDs to use for ID (see e1000e_id_led_init_generic()), 45988c2ecf20Sopenharmony_ci * use "link_up" mode. The LEDs will still ID on request if there is no 45998c2ecf20Sopenharmony_ci * link based on logic in e1000_led_[on|off]_pchlan(). 46008c2ecf20Sopenharmony_ci **/ 46018c2ecf20Sopenharmony_cistatic s32 e1000_id_led_init_pchlan(struct e1000_hw *hw) 46028c2ecf20Sopenharmony_ci{ 46038c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 46048c2ecf20Sopenharmony_ci s32 ret_val; 46058c2ecf20Sopenharmony_ci const u32 ledctl_on = E1000_LEDCTL_MODE_LINK_UP; 46068c2ecf20Sopenharmony_ci const u32 ledctl_off = E1000_LEDCTL_MODE_LINK_UP | E1000_PHY_LED0_IVRT; 46078c2ecf20Sopenharmony_ci u16 data, i, temp, shift; 46088c2ecf20Sopenharmony_ci 46098c2ecf20Sopenharmony_ci /* Get default ID LED modes */ 46108c2ecf20Sopenharmony_ci ret_val = hw->nvm.ops.valid_led_default(hw, &data); 46118c2ecf20Sopenharmony_ci if (ret_val) 46128c2ecf20Sopenharmony_ci return ret_val; 46138c2ecf20Sopenharmony_ci 46148c2ecf20Sopenharmony_ci mac->ledctl_default = er32(LEDCTL); 46158c2ecf20Sopenharmony_ci mac->ledctl_mode1 = mac->ledctl_default; 46168c2ecf20Sopenharmony_ci mac->ledctl_mode2 = mac->ledctl_default; 46178c2ecf20Sopenharmony_ci 46188c2ecf20Sopenharmony_ci for (i = 0; i < 4; i++) { 46198c2ecf20Sopenharmony_ci temp = (data >> (i << 2)) & E1000_LEDCTL_LED0_MODE_MASK; 46208c2ecf20Sopenharmony_ci shift = (i * 5); 46218c2ecf20Sopenharmony_ci switch (temp) { 46228c2ecf20Sopenharmony_ci case ID_LED_ON1_DEF2: 46238c2ecf20Sopenharmony_ci case ID_LED_ON1_ON2: 46248c2ecf20Sopenharmony_ci case ID_LED_ON1_OFF2: 46258c2ecf20Sopenharmony_ci mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 46268c2ecf20Sopenharmony_ci mac->ledctl_mode1 |= (ledctl_on << shift); 46278c2ecf20Sopenharmony_ci break; 46288c2ecf20Sopenharmony_ci case ID_LED_OFF1_DEF2: 46298c2ecf20Sopenharmony_ci case ID_LED_OFF1_ON2: 46308c2ecf20Sopenharmony_ci case ID_LED_OFF1_OFF2: 46318c2ecf20Sopenharmony_ci mac->ledctl_mode1 &= ~(E1000_PHY_LED0_MASK << shift); 46328c2ecf20Sopenharmony_ci mac->ledctl_mode1 |= (ledctl_off << shift); 46338c2ecf20Sopenharmony_ci break; 46348c2ecf20Sopenharmony_ci default: 46358c2ecf20Sopenharmony_ci /* Do nothing */ 46368c2ecf20Sopenharmony_ci break; 46378c2ecf20Sopenharmony_ci } 46388c2ecf20Sopenharmony_ci switch (temp) { 46398c2ecf20Sopenharmony_ci case ID_LED_DEF1_ON2: 46408c2ecf20Sopenharmony_ci case ID_LED_ON1_ON2: 46418c2ecf20Sopenharmony_ci case ID_LED_OFF1_ON2: 46428c2ecf20Sopenharmony_ci mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 46438c2ecf20Sopenharmony_ci mac->ledctl_mode2 |= (ledctl_on << shift); 46448c2ecf20Sopenharmony_ci break; 46458c2ecf20Sopenharmony_ci case ID_LED_DEF1_OFF2: 46468c2ecf20Sopenharmony_ci case ID_LED_ON1_OFF2: 46478c2ecf20Sopenharmony_ci case ID_LED_OFF1_OFF2: 46488c2ecf20Sopenharmony_ci mac->ledctl_mode2 &= ~(E1000_PHY_LED0_MASK << shift); 46498c2ecf20Sopenharmony_ci mac->ledctl_mode2 |= (ledctl_off << shift); 46508c2ecf20Sopenharmony_ci break; 46518c2ecf20Sopenharmony_ci default: 46528c2ecf20Sopenharmony_ci /* Do nothing */ 46538c2ecf20Sopenharmony_ci break; 46548c2ecf20Sopenharmony_ci } 46558c2ecf20Sopenharmony_ci } 46568c2ecf20Sopenharmony_ci 46578c2ecf20Sopenharmony_ci return 0; 46588c2ecf20Sopenharmony_ci} 46598c2ecf20Sopenharmony_ci 46608c2ecf20Sopenharmony_ci/** 46618c2ecf20Sopenharmony_ci * e1000_get_bus_info_ich8lan - Get/Set the bus type and width 46628c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 46638c2ecf20Sopenharmony_ci * 46648c2ecf20Sopenharmony_ci * ICH8 use the PCI Express bus, but does not contain a PCI Express Capability 46658c2ecf20Sopenharmony_ci * register, so the the bus width is hard coded. 46668c2ecf20Sopenharmony_ci **/ 46678c2ecf20Sopenharmony_cistatic s32 e1000_get_bus_info_ich8lan(struct e1000_hw *hw) 46688c2ecf20Sopenharmony_ci{ 46698c2ecf20Sopenharmony_ci struct e1000_bus_info *bus = &hw->bus; 46708c2ecf20Sopenharmony_ci s32 ret_val; 46718c2ecf20Sopenharmony_ci 46728c2ecf20Sopenharmony_ci ret_val = e1000e_get_bus_info_pcie(hw); 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_ci /* ICH devices are "PCI Express"-ish. They have 46758c2ecf20Sopenharmony_ci * a configuration space, but do not contain 46768c2ecf20Sopenharmony_ci * PCI Express Capability registers, so bus width 46778c2ecf20Sopenharmony_ci * must be hardcoded. 46788c2ecf20Sopenharmony_ci */ 46798c2ecf20Sopenharmony_ci if (bus->width == e1000_bus_width_unknown) 46808c2ecf20Sopenharmony_ci bus->width = e1000_bus_width_pcie_x1; 46818c2ecf20Sopenharmony_ci 46828c2ecf20Sopenharmony_ci return ret_val; 46838c2ecf20Sopenharmony_ci} 46848c2ecf20Sopenharmony_ci 46858c2ecf20Sopenharmony_ci/** 46868c2ecf20Sopenharmony_ci * e1000_reset_hw_ich8lan - Reset the hardware 46878c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 46888c2ecf20Sopenharmony_ci * 46898c2ecf20Sopenharmony_ci * Does a full reset of the hardware which includes a reset of the PHY and 46908c2ecf20Sopenharmony_ci * MAC. 46918c2ecf20Sopenharmony_ci **/ 46928c2ecf20Sopenharmony_cistatic s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) 46938c2ecf20Sopenharmony_ci{ 46948c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 46958c2ecf20Sopenharmony_ci u16 kum_cfg; 46968c2ecf20Sopenharmony_ci u32 ctrl, reg; 46978c2ecf20Sopenharmony_ci s32 ret_val; 46988c2ecf20Sopenharmony_ci 46998c2ecf20Sopenharmony_ci /* Prevent the PCI-E bus from sticking if there is no TLP connection 47008c2ecf20Sopenharmony_ci * on the last TLP read/write transaction when MAC is reset. 47018c2ecf20Sopenharmony_ci */ 47028c2ecf20Sopenharmony_ci ret_val = e1000e_disable_pcie_master(hw); 47038c2ecf20Sopenharmony_ci if (ret_val) 47048c2ecf20Sopenharmony_ci e_dbg("PCI-E Master disable polling has failed.\n"); 47058c2ecf20Sopenharmony_ci 47068c2ecf20Sopenharmony_ci e_dbg("Masking off all interrupts\n"); 47078c2ecf20Sopenharmony_ci ew32(IMC, 0xffffffff); 47088c2ecf20Sopenharmony_ci 47098c2ecf20Sopenharmony_ci /* Disable the Transmit and Receive units. Then delay to allow 47108c2ecf20Sopenharmony_ci * any pending transactions to complete before we hit the MAC 47118c2ecf20Sopenharmony_ci * with the global reset. 47128c2ecf20Sopenharmony_ci */ 47138c2ecf20Sopenharmony_ci ew32(RCTL, 0); 47148c2ecf20Sopenharmony_ci ew32(TCTL, E1000_TCTL_PSP); 47158c2ecf20Sopenharmony_ci e1e_flush(); 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ci usleep_range(10000, 11000); 47188c2ecf20Sopenharmony_ci 47198c2ecf20Sopenharmony_ci /* Workaround for ICH8 bit corruption issue in FIFO memory */ 47208c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) { 47218c2ecf20Sopenharmony_ci /* Set Tx and Rx buffer allocation to 8k apiece. */ 47228c2ecf20Sopenharmony_ci ew32(PBA, E1000_PBA_8K); 47238c2ecf20Sopenharmony_ci /* Set Packet Buffer Size to 16k. */ 47248c2ecf20Sopenharmony_ci ew32(PBS, E1000_PBS_16K); 47258c2ecf20Sopenharmony_ci } 47268c2ecf20Sopenharmony_ci 47278c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) { 47288c2ecf20Sopenharmony_ci /* Save the NVM K1 bit setting */ 47298c2ecf20Sopenharmony_ci ret_val = e1000_read_nvm(hw, E1000_NVM_K1_CONFIG, 1, &kum_cfg); 47308c2ecf20Sopenharmony_ci if (ret_val) 47318c2ecf20Sopenharmony_ci return ret_val; 47328c2ecf20Sopenharmony_ci 47338c2ecf20Sopenharmony_ci if (kum_cfg & E1000_NVM_K1_ENABLE) 47348c2ecf20Sopenharmony_ci dev_spec->nvm_k1_enabled = true; 47358c2ecf20Sopenharmony_ci else 47368c2ecf20Sopenharmony_ci dev_spec->nvm_k1_enabled = false; 47378c2ecf20Sopenharmony_ci } 47388c2ecf20Sopenharmony_ci 47398c2ecf20Sopenharmony_ci ctrl = er32(CTRL); 47408c2ecf20Sopenharmony_ci 47418c2ecf20Sopenharmony_ci if (!hw->phy.ops.check_reset_block(hw)) { 47428c2ecf20Sopenharmony_ci /* Full-chip reset requires MAC and PHY reset at the same 47438c2ecf20Sopenharmony_ci * time to make sure the interface between MAC and the 47448c2ecf20Sopenharmony_ci * external PHY is reset. 47458c2ecf20Sopenharmony_ci */ 47468c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_PHY_RST; 47478c2ecf20Sopenharmony_ci 47488c2ecf20Sopenharmony_ci /* Gate automatic PHY configuration by hardware on 47498c2ecf20Sopenharmony_ci * non-managed 82579 47508c2ecf20Sopenharmony_ci */ 47518c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_pch2lan) && 47528c2ecf20Sopenharmony_ci !(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) 47538c2ecf20Sopenharmony_ci e1000_gate_hw_phy_config_ich8lan(hw, true); 47548c2ecf20Sopenharmony_ci } 47558c2ecf20Sopenharmony_ci ret_val = e1000_acquire_swflag_ich8lan(hw); 47568c2ecf20Sopenharmony_ci e_dbg("Issuing a global reset to ich8lan\n"); 47578c2ecf20Sopenharmony_ci ew32(CTRL, (ctrl | E1000_CTRL_RST)); 47588c2ecf20Sopenharmony_ci /* cannot issue a flush here because it hangs the hardware */ 47598c2ecf20Sopenharmony_ci msleep(20); 47608c2ecf20Sopenharmony_ci 47618c2ecf20Sopenharmony_ci /* Set Phy Config Counter to 50msec */ 47628c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pch2lan) { 47638c2ecf20Sopenharmony_ci reg = er32(FEXTNVM3); 47648c2ecf20Sopenharmony_ci reg &= ~E1000_FEXTNVM3_PHY_CFG_COUNTER_MASK; 47658c2ecf20Sopenharmony_ci reg |= E1000_FEXTNVM3_PHY_CFG_COUNTER_50MSEC; 47668c2ecf20Sopenharmony_ci ew32(FEXTNVM3, reg); 47678c2ecf20Sopenharmony_ci } 47688c2ecf20Sopenharmony_ci 47698c2ecf20Sopenharmony_ci if (!ret_val) 47708c2ecf20Sopenharmony_ci clear_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state); 47718c2ecf20Sopenharmony_ci 47728c2ecf20Sopenharmony_ci if (ctrl & E1000_CTRL_PHY_RST) { 47738c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.get_cfg_done(hw); 47748c2ecf20Sopenharmony_ci if (ret_val) 47758c2ecf20Sopenharmony_ci return ret_val; 47768c2ecf20Sopenharmony_ci 47778c2ecf20Sopenharmony_ci ret_val = e1000_post_phy_reset_ich8lan(hw); 47788c2ecf20Sopenharmony_ci if (ret_val) 47798c2ecf20Sopenharmony_ci return ret_val; 47808c2ecf20Sopenharmony_ci } 47818c2ecf20Sopenharmony_ci 47828c2ecf20Sopenharmony_ci /* For PCH, this write will make sure that any noise 47838c2ecf20Sopenharmony_ci * will be detected as a CRC error and be dropped rather than show up 47848c2ecf20Sopenharmony_ci * as a bad packet to the DMA engine. 47858c2ecf20Sopenharmony_ci */ 47868c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) 47878c2ecf20Sopenharmony_ci ew32(CRC_OFFSET, 0x65656565); 47888c2ecf20Sopenharmony_ci 47898c2ecf20Sopenharmony_ci ew32(IMC, 0xffffffff); 47908c2ecf20Sopenharmony_ci er32(ICR); 47918c2ecf20Sopenharmony_ci 47928c2ecf20Sopenharmony_ci reg = er32(KABGTXD); 47938c2ecf20Sopenharmony_ci reg |= E1000_KABGTXD_BGSQLBIAS; 47948c2ecf20Sopenharmony_ci ew32(KABGTXD, reg); 47958c2ecf20Sopenharmony_ci 47968c2ecf20Sopenharmony_ci return 0; 47978c2ecf20Sopenharmony_ci} 47988c2ecf20Sopenharmony_ci 47998c2ecf20Sopenharmony_ci/** 48008c2ecf20Sopenharmony_ci * e1000_init_hw_ich8lan - Initialize the hardware 48018c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 48028c2ecf20Sopenharmony_ci * 48038c2ecf20Sopenharmony_ci * Prepares the hardware for transmit and receive by doing the following: 48048c2ecf20Sopenharmony_ci * - initialize hardware bits 48058c2ecf20Sopenharmony_ci * - initialize LED identification 48068c2ecf20Sopenharmony_ci * - setup receive address registers 48078c2ecf20Sopenharmony_ci * - setup flow control 48088c2ecf20Sopenharmony_ci * - setup transmit descriptors 48098c2ecf20Sopenharmony_ci * - clear statistics 48108c2ecf20Sopenharmony_ci **/ 48118c2ecf20Sopenharmony_cistatic s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) 48128c2ecf20Sopenharmony_ci{ 48138c2ecf20Sopenharmony_ci struct e1000_mac_info *mac = &hw->mac; 48148c2ecf20Sopenharmony_ci u32 ctrl_ext, txdctl, snoop, fflt_dbg; 48158c2ecf20Sopenharmony_ci s32 ret_val; 48168c2ecf20Sopenharmony_ci u16 i; 48178c2ecf20Sopenharmony_ci 48188c2ecf20Sopenharmony_ci e1000_initialize_hw_bits_ich8lan(hw); 48198c2ecf20Sopenharmony_ci 48208c2ecf20Sopenharmony_ci /* Initialize identification LED */ 48218c2ecf20Sopenharmony_ci ret_val = mac->ops.id_led_init(hw); 48228c2ecf20Sopenharmony_ci /* An error is not fatal and we should not stop init due to this */ 48238c2ecf20Sopenharmony_ci if (ret_val) 48248c2ecf20Sopenharmony_ci e_dbg("Error initializing identification LED\n"); 48258c2ecf20Sopenharmony_ci 48268c2ecf20Sopenharmony_ci /* Setup the receive address. */ 48278c2ecf20Sopenharmony_ci e1000e_init_rx_addrs(hw, mac->rar_entry_count); 48288c2ecf20Sopenharmony_ci 48298c2ecf20Sopenharmony_ci /* Zero out the Multicast HASH table */ 48308c2ecf20Sopenharmony_ci e_dbg("Zeroing the MTA\n"); 48318c2ecf20Sopenharmony_ci for (i = 0; i < mac->mta_reg_count; i++) 48328c2ecf20Sopenharmony_ci E1000_WRITE_REG_ARRAY(hw, E1000_MTA, i, 0); 48338c2ecf20Sopenharmony_ci 48348c2ecf20Sopenharmony_ci /* The 82578 Rx buffer will stall if wakeup is enabled in host and 48358c2ecf20Sopenharmony_ci * the ME. Disable wakeup by clearing the host wakeup bit. 48368c2ecf20Sopenharmony_ci * Reset the phy after disabling host wakeup to reset the Rx buffer. 48378c2ecf20Sopenharmony_ci */ 48388c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_82578) { 48398c2ecf20Sopenharmony_ci e1e_rphy(hw, BM_PORT_GEN_CFG, &i); 48408c2ecf20Sopenharmony_ci i &= ~BM_WUC_HOST_WU_BIT; 48418c2ecf20Sopenharmony_ci e1e_wphy(hw, BM_PORT_GEN_CFG, i); 48428c2ecf20Sopenharmony_ci ret_val = e1000_phy_hw_reset_ich8lan(hw); 48438c2ecf20Sopenharmony_ci if (ret_val) 48448c2ecf20Sopenharmony_ci return ret_val; 48458c2ecf20Sopenharmony_ci } 48468c2ecf20Sopenharmony_ci 48478c2ecf20Sopenharmony_ci /* Setup link and flow control */ 48488c2ecf20Sopenharmony_ci ret_val = mac->ops.setup_link(hw); 48498c2ecf20Sopenharmony_ci 48508c2ecf20Sopenharmony_ci /* Set the transmit descriptor write-back policy for both queues */ 48518c2ecf20Sopenharmony_ci txdctl = er32(TXDCTL(0)); 48528c2ecf20Sopenharmony_ci txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 48538c2ecf20Sopenharmony_ci E1000_TXDCTL_FULL_TX_DESC_WB); 48548c2ecf20Sopenharmony_ci txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 48558c2ecf20Sopenharmony_ci E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 48568c2ecf20Sopenharmony_ci ew32(TXDCTL(0), txdctl); 48578c2ecf20Sopenharmony_ci txdctl = er32(TXDCTL(1)); 48588c2ecf20Sopenharmony_ci txdctl = ((txdctl & ~E1000_TXDCTL_WTHRESH) | 48598c2ecf20Sopenharmony_ci E1000_TXDCTL_FULL_TX_DESC_WB); 48608c2ecf20Sopenharmony_ci txdctl = ((txdctl & ~E1000_TXDCTL_PTHRESH) | 48618c2ecf20Sopenharmony_ci E1000_TXDCTL_MAX_TX_DESC_PREFETCH); 48628c2ecf20Sopenharmony_ci ew32(TXDCTL(1), txdctl); 48638c2ecf20Sopenharmony_ci 48648c2ecf20Sopenharmony_ci /* ICH8 has opposite polarity of no_snoop bits. 48658c2ecf20Sopenharmony_ci * By default, we should use snoop behavior. 48668c2ecf20Sopenharmony_ci */ 48678c2ecf20Sopenharmony_ci if (mac->type == e1000_ich8lan) 48688c2ecf20Sopenharmony_ci snoop = PCIE_ICH8_SNOOP_ALL; 48698c2ecf20Sopenharmony_ci else 48708c2ecf20Sopenharmony_ci snoop = (u32)~(PCIE_NO_SNOOP_ALL); 48718c2ecf20Sopenharmony_ci e1000e_set_pcie_no_snoop(hw, snoop); 48728c2ecf20Sopenharmony_ci 48738c2ecf20Sopenharmony_ci /* Enable workaround for packet loss issue on TGP PCH 48748c2ecf20Sopenharmony_ci * Do not gate DMA clock from the modPHY block 48758c2ecf20Sopenharmony_ci */ 48768c2ecf20Sopenharmony_ci if (mac->type >= e1000_pch_tgp) { 48778c2ecf20Sopenharmony_ci fflt_dbg = er32(FFLT_DBG); 48788c2ecf20Sopenharmony_ci fflt_dbg |= E1000_FFLT_DBG_DONT_GATE_WAKE_DMA_CLK; 48798c2ecf20Sopenharmony_ci ew32(FFLT_DBG, fflt_dbg); 48808c2ecf20Sopenharmony_ci } 48818c2ecf20Sopenharmony_ci 48828c2ecf20Sopenharmony_ci ctrl_ext = er32(CTRL_EXT); 48838c2ecf20Sopenharmony_ci ctrl_ext |= E1000_CTRL_EXT_RO_DIS; 48848c2ecf20Sopenharmony_ci ew32(CTRL_EXT, ctrl_ext); 48858c2ecf20Sopenharmony_ci 48868c2ecf20Sopenharmony_ci /* Clear all of the statistics registers (clear on read). It is 48878c2ecf20Sopenharmony_ci * important that we do this after we have tried to establish link 48888c2ecf20Sopenharmony_ci * because the symbol error count will increment wildly if there 48898c2ecf20Sopenharmony_ci * is no link. 48908c2ecf20Sopenharmony_ci */ 48918c2ecf20Sopenharmony_ci e1000_clear_hw_cntrs_ich8lan(hw); 48928c2ecf20Sopenharmony_ci 48938c2ecf20Sopenharmony_ci return ret_val; 48948c2ecf20Sopenharmony_ci} 48958c2ecf20Sopenharmony_ci 48968c2ecf20Sopenharmony_ci/** 48978c2ecf20Sopenharmony_ci * e1000_initialize_hw_bits_ich8lan - Initialize required hardware bits 48988c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 48998c2ecf20Sopenharmony_ci * 49008c2ecf20Sopenharmony_ci * Sets/Clears required hardware bits necessary for correctly setting up the 49018c2ecf20Sopenharmony_ci * hardware for transmit and receive. 49028c2ecf20Sopenharmony_ci **/ 49038c2ecf20Sopenharmony_cistatic void e1000_initialize_hw_bits_ich8lan(struct e1000_hw *hw) 49048c2ecf20Sopenharmony_ci{ 49058c2ecf20Sopenharmony_ci u32 reg; 49068c2ecf20Sopenharmony_ci 49078c2ecf20Sopenharmony_ci /* Extended Device Control */ 49088c2ecf20Sopenharmony_ci reg = er32(CTRL_EXT); 49098c2ecf20Sopenharmony_ci reg |= BIT(22); 49108c2ecf20Sopenharmony_ci /* Enable PHY low-power state when MAC is at D3 w/o WoL */ 49118c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pchlan) 49128c2ecf20Sopenharmony_ci reg |= E1000_CTRL_EXT_PHYPDEN; 49138c2ecf20Sopenharmony_ci ew32(CTRL_EXT, reg); 49148c2ecf20Sopenharmony_ci 49158c2ecf20Sopenharmony_ci /* Transmit Descriptor Control 0 */ 49168c2ecf20Sopenharmony_ci reg = er32(TXDCTL(0)); 49178c2ecf20Sopenharmony_ci reg |= BIT(22); 49188c2ecf20Sopenharmony_ci ew32(TXDCTL(0), reg); 49198c2ecf20Sopenharmony_ci 49208c2ecf20Sopenharmony_ci /* Transmit Descriptor Control 1 */ 49218c2ecf20Sopenharmony_ci reg = er32(TXDCTL(1)); 49228c2ecf20Sopenharmony_ci reg |= BIT(22); 49238c2ecf20Sopenharmony_ci ew32(TXDCTL(1), reg); 49248c2ecf20Sopenharmony_ci 49258c2ecf20Sopenharmony_ci /* Transmit Arbitration Control 0 */ 49268c2ecf20Sopenharmony_ci reg = er32(TARC(0)); 49278c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 49288c2ecf20Sopenharmony_ci reg |= BIT(28) | BIT(29); 49298c2ecf20Sopenharmony_ci reg |= BIT(23) | BIT(24) | BIT(26) | BIT(27); 49308c2ecf20Sopenharmony_ci ew32(TARC(0), reg); 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci /* Transmit Arbitration Control 1 */ 49338c2ecf20Sopenharmony_ci reg = er32(TARC(1)); 49348c2ecf20Sopenharmony_ci if (er32(TCTL) & E1000_TCTL_MULR) 49358c2ecf20Sopenharmony_ci reg &= ~BIT(28); 49368c2ecf20Sopenharmony_ci else 49378c2ecf20Sopenharmony_ci reg |= BIT(28); 49388c2ecf20Sopenharmony_ci reg |= BIT(24) | BIT(26) | BIT(30); 49398c2ecf20Sopenharmony_ci ew32(TARC(1), reg); 49408c2ecf20Sopenharmony_ci 49418c2ecf20Sopenharmony_ci /* Device Status */ 49428c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) { 49438c2ecf20Sopenharmony_ci reg = er32(STATUS); 49448c2ecf20Sopenharmony_ci reg &= ~BIT(31); 49458c2ecf20Sopenharmony_ci ew32(STATUS, reg); 49468c2ecf20Sopenharmony_ci } 49478c2ecf20Sopenharmony_ci 49488c2ecf20Sopenharmony_ci /* work-around descriptor data corruption issue during nfs v2 udp 49498c2ecf20Sopenharmony_ci * traffic, just disable the nfs filtering capability 49508c2ecf20Sopenharmony_ci */ 49518c2ecf20Sopenharmony_ci reg = er32(RFCTL); 49528c2ecf20Sopenharmony_ci reg |= (E1000_RFCTL_NFSW_DIS | E1000_RFCTL_NFSR_DIS); 49538c2ecf20Sopenharmony_ci 49548c2ecf20Sopenharmony_ci /* Disable IPv6 extension header parsing because some malformed 49558c2ecf20Sopenharmony_ci * IPv6 headers can hang the Rx. 49568c2ecf20Sopenharmony_ci */ 49578c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 49588c2ecf20Sopenharmony_ci reg |= (E1000_RFCTL_IPV6_EX_DIS | E1000_RFCTL_NEW_IPV6_EXT_DIS); 49598c2ecf20Sopenharmony_ci ew32(RFCTL, reg); 49608c2ecf20Sopenharmony_ci 49618c2ecf20Sopenharmony_ci /* Enable ECC on Lynxpoint */ 49628c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pch_lpt) { 49638c2ecf20Sopenharmony_ci reg = er32(PBECCSTS); 49648c2ecf20Sopenharmony_ci reg |= E1000_PBECCSTS_ECC_ENABLE; 49658c2ecf20Sopenharmony_ci ew32(PBECCSTS, reg); 49668c2ecf20Sopenharmony_ci 49678c2ecf20Sopenharmony_ci reg = er32(CTRL); 49688c2ecf20Sopenharmony_ci reg |= E1000_CTRL_MEHE; 49698c2ecf20Sopenharmony_ci ew32(CTRL, reg); 49708c2ecf20Sopenharmony_ci } 49718c2ecf20Sopenharmony_ci} 49728c2ecf20Sopenharmony_ci 49738c2ecf20Sopenharmony_ci/** 49748c2ecf20Sopenharmony_ci * e1000_setup_link_ich8lan - Setup flow control and link settings 49758c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 49768c2ecf20Sopenharmony_ci * 49778c2ecf20Sopenharmony_ci * Determines which flow control settings to use, then configures flow 49788c2ecf20Sopenharmony_ci * control. Calls the appropriate media-specific link configuration 49798c2ecf20Sopenharmony_ci * function. Assuming the adapter has a valid link partner, a valid link 49808c2ecf20Sopenharmony_ci * should be established. Assumes the hardware has previously been reset 49818c2ecf20Sopenharmony_ci * and the transmitter and receiver are not enabled. 49828c2ecf20Sopenharmony_ci **/ 49838c2ecf20Sopenharmony_cistatic s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) 49848c2ecf20Sopenharmony_ci{ 49858c2ecf20Sopenharmony_ci s32 ret_val; 49868c2ecf20Sopenharmony_ci 49878c2ecf20Sopenharmony_ci if (hw->phy.ops.check_reset_block(hw)) 49888c2ecf20Sopenharmony_ci return 0; 49898c2ecf20Sopenharmony_ci 49908c2ecf20Sopenharmony_ci /* ICH parts do not have a word in the NVM to determine 49918c2ecf20Sopenharmony_ci * the default flow control setting, so we explicitly 49928c2ecf20Sopenharmony_ci * set it to full. 49938c2ecf20Sopenharmony_ci */ 49948c2ecf20Sopenharmony_ci if (hw->fc.requested_mode == e1000_fc_default) { 49958c2ecf20Sopenharmony_ci /* Workaround h/w hang when Tx flow control enabled */ 49968c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) 49978c2ecf20Sopenharmony_ci hw->fc.requested_mode = e1000_fc_rx_pause; 49988c2ecf20Sopenharmony_ci else 49998c2ecf20Sopenharmony_ci hw->fc.requested_mode = e1000_fc_full; 50008c2ecf20Sopenharmony_ci } 50018c2ecf20Sopenharmony_ci 50028c2ecf20Sopenharmony_ci /* Save off the requested flow control mode for use later. Depending 50038c2ecf20Sopenharmony_ci * on the link partner's capabilities, we may or may not use this mode. 50048c2ecf20Sopenharmony_ci */ 50058c2ecf20Sopenharmony_ci hw->fc.current_mode = hw->fc.requested_mode; 50068c2ecf20Sopenharmony_ci 50078c2ecf20Sopenharmony_ci e_dbg("After fix-ups FlowControl is now = %x\n", hw->fc.current_mode); 50088c2ecf20Sopenharmony_ci 50098c2ecf20Sopenharmony_ci /* Continue to configure the copper link. */ 50108c2ecf20Sopenharmony_ci ret_val = hw->mac.ops.setup_physical_interface(hw); 50118c2ecf20Sopenharmony_ci if (ret_val) 50128c2ecf20Sopenharmony_ci return ret_val; 50138c2ecf20Sopenharmony_ci 50148c2ecf20Sopenharmony_ci ew32(FCTTV, hw->fc.pause_time); 50158c2ecf20Sopenharmony_ci if ((hw->phy.type == e1000_phy_82578) || 50168c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_82579) || 50178c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_i217) || 50188c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_82577)) { 50198c2ecf20Sopenharmony_ci ew32(FCRTV_PCH, hw->fc.refresh_time); 50208c2ecf20Sopenharmony_ci 50218c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, PHY_REG(BM_PORT_CTRL_PAGE, 27), 50228c2ecf20Sopenharmony_ci hw->fc.pause_time); 50238c2ecf20Sopenharmony_ci if (ret_val) 50248c2ecf20Sopenharmony_ci return ret_val; 50258c2ecf20Sopenharmony_ci } 50268c2ecf20Sopenharmony_ci 50278c2ecf20Sopenharmony_ci return e1000e_set_fc_watermarks(hw); 50288c2ecf20Sopenharmony_ci} 50298c2ecf20Sopenharmony_ci 50308c2ecf20Sopenharmony_ci/** 50318c2ecf20Sopenharmony_ci * e1000_setup_copper_link_ich8lan - Configure MAC/PHY interface 50328c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 50338c2ecf20Sopenharmony_ci * 50348c2ecf20Sopenharmony_ci * Configures the kumeran interface to the PHY to wait the appropriate time 50358c2ecf20Sopenharmony_ci * when polling the PHY, then call the generic setup_copper_link to finish 50368c2ecf20Sopenharmony_ci * configuring the copper link. 50378c2ecf20Sopenharmony_ci **/ 50388c2ecf20Sopenharmony_cistatic s32 e1000_setup_copper_link_ich8lan(struct e1000_hw *hw) 50398c2ecf20Sopenharmony_ci{ 50408c2ecf20Sopenharmony_ci u32 ctrl; 50418c2ecf20Sopenharmony_ci s32 ret_val; 50428c2ecf20Sopenharmony_ci u16 reg_data; 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci ctrl = er32(CTRL); 50458c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_SLU; 50468c2ecf20Sopenharmony_ci ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 50478c2ecf20Sopenharmony_ci ew32(CTRL, ctrl); 50488c2ecf20Sopenharmony_ci 50498c2ecf20Sopenharmony_ci /* Set the mac to wait the maximum time between each iteration 50508c2ecf20Sopenharmony_ci * and increase the max iterations when polling the phy; 50518c2ecf20Sopenharmony_ci * this fixes erroneous timeouts at 10Mbps. 50528c2ecf20Sopenharmony_ci */ 50538c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_TIMEOUTS, 0xFFFF); 50548c2ecf20Sopenharmony_ci if (ret_val) 50558c2ecf20Sopenharmony_ci return ret_val; 50568c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM, 50578c2ecf20Sopenharmony_ci ®_data); 50588c2ecf20Sopenharmony_ci if (ret_val) 50598c2ecf20Sopenharmony_ci return ret_val; 50608c2ecf20Sopenharmony_ci reg_data |= 0x3F; 50618c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_INBAND_PARAM, 50628c2ecf20Sopenharmony_ci reg_data); 50638c2ecf20Sopenharmony_ci if (ret_val) 50648c2ecf20Sopenharmony_ci return ret_val; 50658c2ecf20Sopenharmony_ci 50668c2ecf20Sopenharmony_ci switch (hw->phy.type) { 50678c2ecf20Sopenharmony_ci case e1000_phy_igp_3: 50688c2ecf20Sopenharmony_ci ret_val = e1000e_copper_link_setup_igp(hw); 50698c2ecf20Sopenharmony_ci if (ret_val) 50708c2ecf20Sopenharmony_ci return ret_val; 50718c2ecf20Sopenharmony_ci break; 50728c2ecf20Sopenharmony_ci case e1000_phy_bm: 50738c2ecf20Sopenharmony_ci case e1000_phy_82578: 50748c2ecf20Sopenharmony_ci ret_val = e1000e_copper_link_setup_m88(hw); 50758c2ecf20Sopenharmony_ci if (ret_val) 50768c2ecf20Sopenharmony_ci return ret_val; 50778c2ecf20Sopenharmony_ci break; 50788c2ecf20Sopenharmony_ci case e1000_phy_82577: 50798c2ecf20Sopenharmony_ci case e1000_phy_82579: 50808c2ecf20Sopenharmony_ci ret_val = e1000_copper_link_setup_82577(hw); 50818c2ecf20Sopenharmony_ci if (ret_val) 50828c2ecf20Sopenharmony_ci return ret_val; 50838c2ecf20Sopenharmony_ci break; 50848c2ecf20Sopenharmony_ci case e1000_phy_ife: 50858c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IFE_PHY_MDIX_CONTROL, ®_data); 50868c2ecf20Sopenharmony_ci if (ret_val) 50878c2ecf20Sopenharmony_ci return ret_val; 50888c2ecf20Sopenharmony_ci 50898c2ecf20Sopenharmony_ci reg_data &= ~IFE_PMC_AUTO_MDIX; 50908c2ecf20Sopenharmony_ci 50918c2ecf20Sopenharmony_ci switch (hw->phy.mdix) { 50928c2ecf20Sopenharmony_ci case 1: 50938c2ecf20Sopenharmony_ci reg_data &= ~IFE_PMC_FORCE_MDIX; 50948c2ecf20Sopenharmony_ci break; 50958c2ecf20Sopenharmony_ci case 2: 50968c2ecf20Sopenharmony_ci reg_data |= IFE_PMC_FORCE_MDIX; 50978c2ecf20Sopenharmony_ci break; 50988c2ecf20Sopenharmony_ci case 0: 50998c2ecf20Sopenharmony_ci default: 51008c2ecf20Sopenharmony_ci reg_data |= IFE_PMC_AUTO_MDIX; 51018c2ecf20Sopenharmony_ci break; 51028c2ecf20Sopenharmony_ci } 51038c2ecf20Sopenharmony_ci ret_val = e1e_wphy(hw, IFE_PHY_MDIX_CONTROL, reg_data); 51048c2ecf20Sopenharmony_ci if (ret_val) 51058c2ecf20Sopenharmony_ci return ret_val; 51068c2ecf20Sopenharmony_ci break; 51078c2ecf20Sopenharmony_ci default: 51088c2ecf20Sopenharmony_ci break; 51098c2ecf20Sopenharmony_ci } 51108c2ecf20Sopenharmony_ci 51118c2ecf20Sopenharmony_ci return e1000e_setup_copper_link(hw); 51128c2ecf20Sopenharmony_ci} 51138c2ecf20Sopenharmony_ci 51148c2ecf20Sopenharmony_ci/** 51158c2ecf20Sopenharmony_ci * e1000_setup_copper_link_pch_lpt - Configure MAC/PHY interface 51168c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 51178c2ecf20Sopenharmony_ci * 51188c2ecf20Sopenharmony_ci * Calls the PHY specific link setup function and then calls the 51198c2ecf20Sopenharmony_ci * generic setup_copper_link to finish configuring the link for 51208c2ecf20Sopenharmony_ci * Lynxpoint PCH devices 51218c2ecf20Sopenharmony_ci **/ 51228c2ecf20Sopenharmony_cistatic s32 e1000_setup_copper_link_pch_lpt(struct e1000_hw *hw) 51238c2ecf20Sopenharmony_ci{ 51248c2ecf20Sopenharmony_ci u32 ctrl; 51258c2ecf20Sopenharmony_ci s32 ret_val; 51268c2ecf20Sopenharmony_ci 51278c2ecf20Sopenharmony_ci ctrl = er32(CTRL); 51288c2ecf20Sopenharmony_ci ctrl |= E1000_CTRL_SLU; 51298c2ecf20Sopenharmony_ci ctrl &= ~(E1000_CTRL_FRCSPD | E1000_CTRL_FRCDPX); 51308c2ecf20Sopenharmony_ci ew32(CTRL, ctrl); 51318c2ecf20Sopenharmony_ci 51328c2ecf20Sopenharmony_ci ret_val = e1000_copper_link_setup_82577(hw); 51338c2ecf20Sopenharmony_ci if (ret_val) 51348c2ecf20Sopenharmony_ci return ret_val; 51358c2ecf20Sopenharmony_ci 51368c2ecf20Sopenharmony_ci return e1000e_setup_copper_link(hw); 51378c2ecf20Sopenharmony_ci} 51388c2ecf20Sopenharmony_ci 51398c2ecf20Sopenharmony_ci/** 51408c2ecf20Sopenharmony_ci * e1000_get_link_up_info_ich8lan - Get current link speed and duplex 51418c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 51428c2ecf20Sopenharmony_ci * @speed: pointer to store current link speed 51438c2ecf20Sopenharmony_ci * @duplex: pointer to store the current link duplex 51448c2ecf20Sopenharmony_ci * 51458c2ecf20Sopenharmony_ci * Calls the generic get_speed_and_duplex to retrieve the current link 51468c2ecf20Sopenharmony_ci * information and then calls the Kumeran lock loss workaround for links at 51478c2ecf20Sopenharmony_ci * gigabit speeds. 51488c2ecf20Sopenharmony_ci **/ 51498c2ecf20Sopenharmony_cistatic s32 e1000_get_link_up_info_ich8lan(struct e1000_hw *hw, u16 *speed, 51508c2ecf20Sopenharmony_ci u16 *duplex) 51518c2ecf20Sopenharmony_ci{ 51528c2ecf20Sopenharmony_ci s32 ret_val; 51538c2ecf20Sopenharmony_ci 51548c2ecf20Sopenharmony_ci ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); 51558c2ecf20Sopenharmony_ci if (ret_val) 51568c2ecf20Sopenharmony_ci return ret_val; 51578c2ecf20Sopenharmony_ci 51588c2ecf20Sopenharmony_ci if ((hw->mac.type == e1000_ich8lan) && 51598c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_igp_3) && (*speed == SPEED_1000)) { 51608c2ecf20Sopenharmony_ci ret_val = e1000_kmrn_lock_loss_workaround_ich8lan(hw); 51618c2ecf20Sopenharmony_ci } 51628c2ecf20Sopenharmony_ci 51638c2ecf20Sopenharmony_ci return ret_val; 51648c2ecf20Sopenharmony_ci} 51658c2ecf20Sopenharmony_ci 51668c2ecf20Sopenharmony_ci/** 51678c2ecf20Sopenharmony_ci * e1000_kmrn_lock_loss_workaround_ich8lan - Kumeran workaround 51688c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 51698c2ecf20Sopenharmony_ci * 51708c2ecf20Sopenharmony_ci * Work-around for 82566 Kumeran PCS lock loss: 51718c2ecf20Sopenharmony_ci * On link status change (i.e. PCI reset, speed change) and link is up and 51728c2ecf20Sopenharmony_ci * speed is gigabit- 51738c2ecf20Sopenharmony_ci * 0) if workaround is optionally disabled do nothing 51748c2ecf20Sopenharmony_ci * 1) wait 1ms for Kumeran link to come up 51758c2ecf20Sopenharmony_ci * 2) check Kumeran Diagnostic register PCS lock loss bit 51768c2ecf20Sopenharmony_ci * 3) if not set the link is locked (all is good), otherwise... 51778c2ecf20Sopenharmony_ci * 4) reset the PHY 51788c2ecf20Sopenharmony_ci * 5) repeat up to 10 times 51798c2ecf20Sopenharmony_ci * Note: this is only called for IGP3 copper when speed is 1gb. 51808c2ecf20Sopenharmony_ci **/ 51818c2ecf20Sopenharmony_cistatic s32 e1000_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw) 51828c2ecf20Sopenharmony_ci{ 51838c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 51848c2ecf20Sopenharmony_ci u32 phy_ctrl; 51858c2ecf20Sopenharmony_ci s32 ret_val; 51868c2ecf20Sopenharmony_ci u16 i, data; 51878c2ecf20Sopenharmony_ci bool link; 51888c2ecf20Sopenharmony_ci 51898c2ecf20Sopenharmony_ci if (!dev_spec->kmrn_lock_loss_workaround_enabled) 51908c2ecf20Sopenharmony_ci return 0; 51918c2ecf20Sopenharmony_ci 51928c2ecf20Sopenharmony_ci /* Make sure link is up before proceeding. If not just return. 51938c2ecf20Sopenharmony_ci * Attempting this while link is negotiating fouled up link 51948c2ecf20Sopenharmony_ci * stability 51958c2ecf20Sopenharmony_ci */ 51968c2ecf20Sopenharmony_ci ret_val = e1000e_phy_has_link_generic(hw, 1, 0, &link); 51978c2ecf20Sopenharmony_ci if (!link) 51988c2ecf20Sopenharmony_ci return 0; 51998c2ecf20Sopenharmony_ci 52008c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 52018c2ecf20Sopenharmony_ci /* read once to clear */ 52028c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); 52038c2ecf20Sopenharmony_ci if (ret_val) 52048c2ecf20Sopenharmony_ci return ret_val; 52058c2ecf20Sopenharmony_ci /* and again to get new status */ 52068c2ecf20Sopenharmony_ci ret_val = e1e_rphy(hw, IGP3_KMRN_DIAG, &data); 52078c2ecf20Sopenharmony_ci if (ret_val) 52088c2ecf20Sopenharmony_ci return ret_val; 52098c2ecf20Sopenharmony_ci 52108c2ecf20Sopenharmony_ci /* check for PCS lock */ 52118c2ecf20Sopenharmony_ci if (!(data & IGP3_KMRN_DIAG_PCS_LOCK_LOSS)) 52128c2ecf20Sopenharmony_ci return 0; 52138c2ecf20Sopenharmony_ci 52148c2ecf20Sopenharmony_ci /* Issue PHY reset */ 52158c2ecf20Sopenharmony_ci e1000_phy_hw_reset(hw); 52168c2ecf20Sopenharmony_ci mdelay(5); 52178c2ecf20Sopenharmony_ci } 52188c2ecf20Sopenharmony_ci /* Disable GigE link negotiation */ 52198c2ecf20Sopenharmony_ci phy_ctrl = er32(PHY_CTRL); 52208c2ecf20Sopenharmony_ci phy_ctrl |= (E1000_PHY_CTRL_GBE_DISABLE | 52218c2ecf20Sopenharmony_ci E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 52228c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 52238c2ecf20Sopenharmony_ci 52248c2ecf20Sopenharmony_ci /* Call gig speed drop workaround on Gig disable before accessing 52258c2ecf20Sopenharmony_ci * any PHY registers 52268c2ecf20Sopenharmony_ci */ 52278c2ecf20Sopenharmony_ci e1000e_gig_downshift_workaround_ich8lan(hw); 52288c2ecf20Sopenharmony_ci 52298c2ecf20Sopenharmony_ci /* unable to acquire PCS lock */ 52308c2ecf20Sopenharmony_ci return -E1000_ERR_PHY; 52318c2ecf20Sopenharmony_ci} 52328c2ecf20Sopenharmony_ci 52338c2ecf20Sopenharmony_ci/** 52348c2ecf20Sopenharmony_ci * e1000e_set_kmrn_lock_loss_workaround_ich8lan - Set Kumeran workaround state 52358c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 52368c2ecf20Sopenharmony_ci * @state: boolean value used to set the current Kumeran workaround state 52378c2ecf20Sopenharmony_ci * 52388c2ecf20Sopenharmony_ci * If ICH8, set the current Kumeran workaround state (enabled - true 52398c2ecf20Sopenharmony_ci * /disabled - false). 52408c2ecf20Sopenharmony_ci **/ 52418c2ecf20Sopenharmony_civoid e1000e_set_kmrn_lock_loss_workaround_ich8lan(struct e1000_hw *hw, 52428c2ecf20Sopenharmony_ci bool state) 52438c2ecf20Sopenharmony_ci{ 52448c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 52458c2ecf20Sopenharmony_ci 52468c2ecf20Sopenharmony_ci if (hw->mac.type != e1000_ich8lan) { 52478c2ecf20Sopenharmony_ci e_dbg("Workaround applies to ICH8 only.\n"); 52488c2ecf20Sopenharmony_ci return; 52498c2ecf20Sopenharmony_ci } 52508c2ecf20Sopenharmony_ci 52518c2ecf20Sopenharmony_ci dev_spec->kmrn_lock_loss_workaround_enabled = state; 52528c2ecf20Sopenharmony_ci} 52538c2ecf20Sopenharmony_ci 52548c2ecf20Sopenharmony_ci/** 52558c2ecf20Sopenharmony_ci * e1000_ipg3_phy_powerdown_workaround_ich8lan - Power down workaround on D3 52568c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 52578c2ecf20Sopenharmony_ci * 52588c2ecf20Sopenharmony_ci * Workaround for 82566 power-down on D3 entry: 52598c2ecf20Sopenharmony_ci * 1) disable gigabit link 52608c2ecf20Sopenharmony_ci * 2) write VR power-down enable 52618c2ecf20Sopenharmony_ci * 3) read it back 52628c2ecf20Sopenharmony_ci * Continue if successful, else issue LCD reset and repeat 52638c2ecf20Sopenharmony_ci **/ 52648c2ecf20Sopenharmony_civoid e1000e_igp3_phy_powerdown_workaround_ich8lan(struct e1000_hw *hw) 52658c2ecf20Sopenharmony_ci{ 52668c2ecf20Sopenharmony_ci u32 reg; 52678c2ecf20Sopenharmony_ci u16 data; 52688c2ecf20Sopenharmony_ci u8 retry = 0; 52698c2ecf20Sopenharmony_ci 52708c2ecf20Sopenharmony_ci if (hw->phy.type != e1000_phy_igp_3) 52718c2ecf20Sopenharmony_ci return; 52728c2ecf20Sopenharmony_ci 52738c2ecf20Sopenharmony_ci /* Try the workaround twice (if needed) */ 52748c2ecf20Sopenharmony_ci do { 52758c2ecf20Sopenharmony_ci /* Disable link */ 52768c2ecf20Sopenharmony_ci reg = er32(PHY_CTRL); 52778c2ecf20Sopenharmony_ci reg |= (E1000_PHY_CTRL_GBE_DISABLE | 52788c2ecf20Sopenharmony_ci E1000_PHY_CTRL_NOND0A_GBE_DISABLE); 52798c2ecf20Sopenharmony_ci ew32(PHY_CTRL, reg); 52808c2ecf20Sopenharmony_ci 52818c2ecf20Sopenharmony_ci /* Call gig speed drop workaround on Gig disable before 52828c2ecf20Sopenharmony_ci * accessing any PHY registers 52838c2ecf20Sopenharmony_ci */ 52848c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 52858c2ecf20Sopenharmony_ci e1000e_gig_downshift_workaround_ich8lan(hw); 52868c2ecf20Sopenharmony_ci 52878c2ecf20Sopenharmony_ci /* Write VR power-down enable */ 52888c2ecf20Sopenharmony_ci e1e_rphy(hw, IGP3_VR_CTRL, &data); 52898c2ecf20Sopenharmony_ci data &= ~IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 52908c2ecf20Sopenharmony_ci e1e_wphy(hw, IGP3_VR_CTRL, data | IGP3_VR_CTRL_MODE_SHUTDOWN); 52918c2ecf20Sopenharmony_ci 52928c2ecf20Sopenharmony_ci /* Read it back and test */ 52938c2ecf20Sopenharmony_ci e1e_rphy(hw, IGP3_VR_CTRL, &data); 52948c2ecf20Sopenharmony_ci data &= IGP3_VR_CTRL_DEV_POWERDOWN_MODE_MASK; 52958c2ecf20Sopenharmony_ci if ((data == IGP3_VR_CTRL_MODE_SHUTDOWN) || retry) 52968c2ecf20Sopenharmony_ci break; 52978c2ecf20Sopenharmony_ci 52988c2ecf20Sopenharmony_ci /* Issue PHY reset and repeat at most one more time */ 52998c2ecf20Sopenharmony_ci reg = er32(CTRL); 53008c2ecf20Sopenharmony_ci ew32(CTRL, reg | E1000_CTRL_PHY_RST); 53018c2ecf20Sopenharmony_ci retry++; 53028c2ecf20Sopenharmony_ci } while (retry); 53038c2ecf20Sopenharmony_ci} 53048c2ecf20Sopenharmony_ci 53058c2ecf20Sopenharmony_ci/** 53068c2ecf20Sopenharmony_ci * e1000e_gig_downshift_workaround_ich8lan - WoL from S5 stops working 53078c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 53088c2ecf20Sopenharmony_ci * 53098c2ecf20Sopenharmony_ci * Steps to take when dropping from 1Gb/s (eg. link cable removal (LSC), 53108c2ecf20Sopenharmony_ci * LPLU, Gig disable, MDIC PHY reset): 53118c2ecf20Sopenharmony_ci * 1) Set Kumeran Near-end loopback 53128c2ecf20Sopenharmony_ci * 2) Clear Kumeran Near-end loopback 53138c2ecf20Sopenharmony_ci * Should only be called for ICH8[m] devices with any 1G Phy. 53148c2ecf20Sopenharmony_ci **/ 53158c2ecf20Sopenharmony_civoid e1000e_gig_downshift_workaround_ich8lan(struct e1000_hw *hw) 53168c2ecf20Sopenharmony_ci{ 53178c2ecf20Sopenharmony_ci s32 ret_val; 53188c2ecf20Sopenharmony_ci u16 reg_data; 53198c2ecf20Sopenharmony_ci 53208c2ecf20Sopenharmony_ci if ((hw->mac.type != e1000_ich8lan) || (hw->phy.type == e1000_phy_ife)) 53218c2ecf20Sopenharmony_ci return; 53228c2ecf20Sopenharmony_ci 53238c2ecf20Sopenharmony_ci ret_val = e1000e_read_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 53248c2ecf20Sopenharmony_ci ®_data); 53258c2ecf20Sopenharmony_ci if (ret_val) 53268c2ecf20Sopenharmony_ci return; 53278c2ecf20Sopenharmony_ci reg_data |= E1000_KMRNCTRLSTA_DIAG_NELPBK; 53288c2ecf20Sopenharmony_ci ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, 53298c2ecf20Sopenharmony_ci reg_data); 53308c2ecf20Sopenharmony_ci if (ret_val) 53318c2ecf20Sopenharmony_ci return; 53328c2ecf20Sopenharmony_ci reg_data &= ~E1000_KMRNCTRLSTA_DIAG_NELPBK; 53338c2ecf20Sopenharmony_ci e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_DIAG_OFFSET, reg_data); 53348c2ecf20Sopenharmony_ci} 53358c2ecf20Sopenharmony_ci 53368c2ecf20Sopenharmony_ci/** 53378c2ecf20Sopenharmony_ci * e1000_suspend_workarounds_ich8lan - workarounds needed during S0->Sx 53388c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 53398c2ecf20Sopenharmony_ci * 53408c2ecf20Sopenharmony_ci * During S0 to Sx transition, it is possible the link remains at gig 53418c2ecf20Sopenharmony_ci * instead of negotiating to a lower speed. Before going to Sx, set 53428c2ecf20Sopenharmony_ci * 'Gig Disable' to force link speed negotiation to a lower speed based on 53438c2ecf20Sopenharmony_ci * the LPLU setting in the NVM or custom setting. For PCH and newer parts, 53448c2ecf20Sopenharmony_ci * the OEM bits PHY register (LED, GbE disable and LPLU configurations) also 53458c2ecf20Sopenharmony_ci * needs to be written. 53468c2ecf20Sopenharmony_ci * Parts that support (and are linked to a partner which support) EEE in 53478c2ecf20Sopenharmony_ci * 100Mbps should disable LPLU since 100Mbps w/ EEE requires less power 53488c2ecf20Sopenharmony_ci * than 10Mbps w/o EEE. 53498c2ecf20Sopenharmony_ci **/ 53508c2ecf20Sopenharmony_civoid e1000_suspend_workarounds_ich8lan(struct e1000_hw *hw) 53518c2ecf20Sopenharmony_ci{ 53528c2ecf20Sopenharmony_ci struct e1000_dev_spec_ich8lan *dev_spec = &hw->dev_spec.ich8lan; 53538c2ecf20Sopenharmony_ci u32 phy_ctrl; 53548c2ecf20Sopenharmony_ci s32 ret_val; 53558c2ecf20Sopenharmony_ci 53568c2ecf20Sopenharmony_ci phy_ctrl = er32(PHY_CTRL); 53578c2ecf20Sopenharmony_ci phy_ctrl |= E1000_PHY_CTRL_GBE_DISABLE; 53588c2ecf20Sopenharmony_ci 53598c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_i217) { 53608c2ecf20Sopenharmony_ci u16 phy_reg, device_id = hw->adapter->pdev->device; 53618c2ecf20Sopenharmony_ci 53628c2ecf20Sopenharmony_ci if ((device_id == E1000_DEV_ID_PCH_LPTLP_I218_LM) || 53638c2ecf20Sopenharmony_ci (device_id == E1000_DEV_ID_PCH_LPTLP_I218_V) || 53648c2ecf20Sopenharmony_ci (device_id == E1000_DEV_ID_PCH_I218_LM3) || 53658c2ecf20Sopenharmony_ci (device_id == E1000_DEV_ID_PCH_I218_V3) || 53668c2ecf20Sopenharmony_ci (hw->mac.type >= e1000_pch_spt)) { 53678c2ecf20Sopenharmony_ci u32 fextnvm6 = er32(FEXTNVM6); 53688c2ecf20Sopenharmony_ci 53698c2ecf20Sopenharmony_ci ew32(FEXTNVM6, fextnvm6 & ~E1000_FEXTNVM6_REQ_PLL_CLK); 53708c2ecf20Sopenharmony_ci } 53718c2ecf20Sopenharmony_ci 53728c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 53738c2ecf20Sopenharmony_ci if (ret_val) 53748c2ecf20Sopenharmony_ci goto out; 53758c2ecf20Sopenharmony_ci 53768c2ecf20Sopenharmony_ci if (!dev_spec->eee_disable) { 53778c2ecf20Sopenharmony_ci u16 eee_advert; 53788c2ecf20Sopenharmony_ci 53798c2ecf20Sopenharmony_ci ret_val = 53808c2ecf20Sopenharmony_ci e1000_read_emi_reg_locked(hw, 53818c2ecf20Sopenharmony_ci I217_EEE_ADVERTISEMENT, 53828c2ecf20Sopenharmony_ci &eee_advert); 53838c2ecf20Sopenharmony_ci if (ret_val) 53848c2ecf20Sopenharmony_ci goto release; 53858c2ecf20Sopenharmony_ci 53868c2ecf20Sopenharmony_ci /* Disable LPLU if both link partners support 100BaseT 53878c2ecf20Sopenharmony_ci * EEE and 100Full is advertised on both ends of the 53888c2ecf20Sopenharmony_ci * link, and enable Auto Enable LPI since there will 53898c2ecf20Sopenharmony_ci * be no driver to enable LPI while in Sx. 53908c2ecf20Sopenharmony_ci */ 53918c2ecf20Sopenharmony_ci if ((eee_advert & I82579_EEE_100_SUPPORTED) && 53928c2ecf20Sopenharmony_ci (dev_spec->eee_lp_ability & 53938c2ecf20Sopenharmony_ci I82579_EEE_100_SUPPORTED) && 53948c2ecf20Sopenharmony_ci (hw->phy.autoneg_advertised & ADVERTISE_100_FULL)) { 53958c2ecf20Sopenharmony_ci phy_ctrl &= ~(E1000_PHY_CTRL_D0A_LPLU | 53968c2ecf20Sopenharmony_ci E1000_PHY_CTRL_NOND0A_LPLU); 53978c2ecf20Sopenharmony_ci 53988c2ecf20Sopenharmony_ci /* Set Auto Enable LPI after link up */ 53998c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, 54008c2ecf20Sopenharmony_ci I217_LPI_GPIO_CTRL, &phy_reg); 54018c2ecf20Sopenharmony_ci phy_reg |= I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 54028c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, 54038c2ecf20Sopenharmony_ci I217_LPI_GPIO_CTRL, phy_reg); 54048c2ecf20Sopenharmony_ci } 54058c2ecf20Sopenharmony_ci } 54068c2ecf20Sopenharmony_ci 54078c2ecf20Sopenharmony_ci /* For i217 Intel Rapid Start Technology support, 54088c2ecf20Sopenharmony_ci * when the system is going into Sx and no manageability engine 54098c2ecf20Sopenharmony_ci * is present, the driver must configure proxy to reset only on 54108c2ecf20Sopenharmony_ci * power good. LPI (Low Power Idle) state must also reset only 54118c2ecf20Sopenharmony_ci * on power good, as well as the MTA (Multicast table array). 54128c2ecf20Sopenharmony_ci * The SMBus release must also be disabled on LCD reset. 54138c2ecf20Sopenharmony_ci */ 54148c2ecf20Sopenharmony_ci if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { 54158c2ecf20Sopenharmony_ci /* Enable proxy to reset only on power good. */ 54168c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_PROXY_CTRL, &phy_reg); 54178c2ecf20Sopenharmony_ci phy_reg |= I217_PROXY_CTRL_AUTO_DISABLE; 54188c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_PROXY_CTRL, phy_reg); 54198c2ecf20Sopenharmony_ci 54208c2ecf20Sopenharmony_ci /* Set bit enable LPI (EEE) to reset only on 54218c2ecf20Sopenharmony_ci * power good. 54228c2ecf20Sopenharmony_ci */ 54238c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_SxCTRL, &phy_reg); 54248c2ecf20Sopenharmony_ci phy_reg |= I217_SxCTRL_ENABLE_LPI_RESET; 54258c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_SxCTRL, phy_reg); 54268c2ecf20Sopenharmony_ci 54278c2ecf20Sopenharmony_ci /* Disable the SMB release on LCD reset. */ 54288c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg); 54298c2ecf20Sopenharmony_ci phy_reg &= ~I217_MEMPWR_DISABLE_SMB_RELEASE; 54308c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_MEMPWR, phy_reg); 54318c2ecf20Sopenharmony_ci } 54328c2ecf20Sopenharmony_ci 54338c2ecf20Sopenharmony_ci /* Enable MTA to reset for Intel Rapid Start Technology 54348c2ecf20Sopenharmony_ci * Support 54358c2ecf20Sopenharmony_ci */ 54368c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_CGFREG, &phy_reg); 54378c2ecf20Sopenharmony_ci phy_reg |= I217_CGFREG_ENABLE_MTA_RESET; 54388c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_CGFREG, phy_reg); 54398c2ecf20Sopenharmony_ci 54408c2ecf20Sopenharmony_cirelease: 54418c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 54428c2ecf20Sopenharmony_ci } 54438c2ecf20Sopenharmony_ciout: 54448c2ecf20Sopenharmony_ci ew32(PHY_CTRL, phy_ctrl); 54458c2ecf20Sopenharmony_ci 54468c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_ich8lan) 54478c2ecf20Sopenharmony_ci e1000e_gig_downshift_workaround_ich8lan(hw); 54488c2ecf20Sopenharmony_ci 54498c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_pchlan) { 54508c2ecf20Sopenharmony_ci e1000_oem_bits_config_ich8lan(hw, false); 54518c2ecf20Sopenharmony_ci 54528c2ecf20Sopenharmony_ci /* Reset PHY to activate OEM bits on 82577/8 */ 54538c2ecf20Sopenharmony_ci if (hw->mac.type == e1000_pchlan) 54548c2ecf20Sopenharmony_ci e1000e_phy_hw_reset_generic(hw); 54558c2ecf20Sopenharmony_ci 54568c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 54578c2ecf20Sopenharmony_ci if (ret_val) 54588c2ecf20Sopenharmony_ci return; 54598c2ecf20Sopenharmony_ci e1000_write_smbus_addr(hw); 54608c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 54618c2ecf20Sopenharmony_ci } 54628c2ecf20Sopenharmony_ci} 54638c2ecf20Sopenharmony_ci 54648c2ecf20Sopenharmony_ci/** 54658c2ecf20Sopenharmony_ci * e1000_resume_workarounds_pchlan - workarounds needed during Sx->S0 54668c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 54678c2ecf20Sopenharmony_ci * 54688c2ecf20Sopenharmony_ci * During Sx to S0 transitions on non-managed devices or managed devices 54698c2ecf20Sopenharmony_ci * on which PHY resets are not blocked, if the PHY registers cannot be 54708c2ecf20Sopenharmony_ci * accessed properly by the s/w toggle the LANPHYPC value to power cycle 54718c2ecf20Sopenharmony_ci * the PHY. 54728c2ecf20Sopenharmony_ci * On i217, setup Intel Rapid Start Technology. 54738c2ecf20Sopenharmony_ci **/ 54748c2ecf20Sopenharmony_civoid e1000_resume_workarounds_pchlan(struct e1000_hw *hw) 54758c2ecf20Sopenharmony_ci{ 54768c2ecf20Sopenharmony_ci s32 ret_val; 54778c2ecf20Sopenharmony_ci 54788c2ecf20Sopenharmony_ci if (hw->mac.type < e1000_pch2lan) 54798c2ecf20Sopenharmony_ci return; 54808c2ecf20Sopenharmony_ci 54818c2ecf20Sopenharmony_ci ret_val = e1000_init_phy_workarounds_pchlan(hw); 54828c2ecf20Sopenharmony_ci if (ret_val) { 54838c2ecf20Sopenharmony_ci e_dbg("Failed to init PHY flow ret_val=%d\n", ret_val); 54848c2ecf20Sopenharmony_ci return; 54858c2ecf20Sopenharmony_ci } 54868c2ecf20Sopenharmony_ci 54878c2ecf20Sopenharmony_ci /* For i217 Intel Rapid Start Technology support when the system 54888c2ecf20Sopenharmony_ci * is transitioning from Sx and no manageability engine is present 54898c2ecf20Sopenharmony_ci * configure SMBus to restore on reset, disable proxy, and enable 54908c2ecf20Sopenharmony_ci * the reset on MTA (Multicast table array). 54918c2ecf20Sopenharmony_ci */ 54928c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_i217) { 54938c2ecf20Sopenharmony_ci u16 phy_reg; 54948c2ecf20Sopenharmony_ci 54958c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 54968c2ecf20Sopenharmony_ci if (ret_val) { 54978c2ecf20Sopenharmony_ci e_dbg("Failed to setup iRST\n"); 54988c2ecf20Sopenharmony_ci return; 54998c2ecf20Sopenharmony_ci } 55008c2ecf20Sopenharmony_ci 55018c2ecf20Sopenharmony_ci /* Clear Auto Enable LPI after link up */ 55028c2ecf20Sopenharmony_ci e1e_rphy_locked(hw, I217_LPI_GPIO_CTRL, &phy_reg); 55038c2ecf20Sopenharmony_ci phy_reg &= ~I217_LPI_GPIO_CTRL_AUTO_EN_LPI; 55048c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_LPI_GPIO_CTRL, phy_reg); 55058c2ecf20Sopenharmony_ci 55068c2ecf20Sopenharmony_ci if (!(er32(FWSM) & E1000_ICH_FWSM_FW_VALID)) { 55078c2ecf20Sopenharmony_ci /* Restore clear on SMB if no manageability engine 55088c2ecf20Sopenharmony_ci * is present 55098c2ecf20Sopenharmony_ci */ 55108c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, I217_MEMPWR, &phy_reg); 55118c2ecf20Sopenharmony_ci if (ret_val) 55128c2ecf20Sopenharmony_ci goto release; 55138c2ecf20Sopenharmony_ci phy_reg |= I217_MEMPWR_DISABLE_SMB_RELEASE; 55148c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_MEMPWR, phy_reg); 55158c2ecf20Sopenharmony_ci 55168c2ecf20Sopenharmony_ci /* Disable Proxy */ 55178c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_PROXY_CTRL, 0); 55188c2ecf20Sopenharmony_ci } 55198c2ecf20Sopenharmony_ci /* Enable reset on MTA */ 55208c2ecf20Sopenharmony_ci ret_val = e1e_rphy_locked(hw, I217_CGFREG, &phy_reg); 55218c2ecf20Sopenharmony_ci if (ret_val) 55228c2ecf20Sopenharmony_ci goto release; 55238c2ecf20Sopenharmony_ci phy_reg &= ~I217_CGFREG_ENABLE_MTA_RESET; 55248c2ecf20Sopenharmony_ci e1e_wphy_locked(hw, I217_CGFREG, phy_reg); 55258c2ecf20Sopenharmony_cirelease: 55268c2ecf20Sopenharmony_ci if (ret_val) 55278c2ecf20Sopenharmony_ci e_dbg("Error %d in resume workarounds\n", ret_val); 55288c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 55298c2ecf20Sopenharmony_ci } 55308c2ecf20Sopenharmony_ci} 55318c2ecf20Sopenharmony_ci 55328c2ecf20Sopenharmony_ci/** 55338c2ecf20Sopenharmony_ci * e1000_cleanup_led_ich8lan - Restore the default LED operation 55348c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 55358c2ecf20Sopenharmony_ci * 55368c2ecf20Sopenharmony_ci * Return the LED back to the default configuration. 55378c2ecf20Sopenharmony_ci **/ 55388c2ecf20Sopenharmony_cistatic s32 e1000_cleanup_led_ich8lan(struct e1000_hw *hw) 55398c2ecf20Sopenharmony_ci{ 55408c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_ife) 55418c2ecf20Sopenharmony_ci return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 0); 55428c2ecf20Sopenharmony_ci 55438c2ecf20Sopenharmony_ci ew32(LEDCTL, hw->mac.ledctl_default); 55448c2ecf20Sopenharmony_ci return 0; 55458c2ecf20Sopenharmony_ci} 55468c2ecf20Sopenharmony_ci 55478c2ecf20Sopenharmony_ci/** 55488c2ecf20Sopenharmony_ci * e1000_led_on_ich8lan - Turn LEDs on 55498c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 55508c2ecf20Sopenharmony_ci * 55518c2ecf20Sopenharmony_ci * Turn on the LEDs. 55528c2ecf20Sopenharmony_ci **/ 55538c2ecf20Sopenharmony_cistatic s32 e1000_led_on_ich8lan(struct e1000_hw *hw) 55548c2ecf20Sopenharmony_ci{ 55558c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_ife) 55568c2ecf20Sopenharmony_ci return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 55578c2ecf20Sopenharmony_ci (IFE_PSCL_PROBE_MODE | IFE_PSCL_PROBE_LEDS_ON)); 55588c2ecf20Sopenharmony_ci 55598c2ecf20Sopenharmony_ci ew32(LEDCTL, hw->mac.ledctl_mode2); 55608c2ecf20Sopenharmony_ci return 0; 55618c2ecf20Sopenharmony_ci} 55628c2ecf20Sopenharmony_ci 55638c2ecf20Sopenharmony_ci/** 55648c2ecf20Sopenharmony_ci * e1000_led_off_ich8lan - Turn LEDs off 55658c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 55668c2ecf20Sopenharmony_ci * 55678c2ecf20Sopenharmony_ci * Turn off the LEDs. 55688c2ecf20Sopenharmony_ci **/ 55698c2ecf20Sopenharmony_cistatic s32 e1000_led_off_ich8lan(struct e1000_hw *hw) 55708c2ecf20Sopenharmony_ci{ 55718c2ecf20Sopenharmony_ci if (hw->phy.type == e1000_phy_ife) 55728c2ecf20Sopenharmony_ci return e1e_wphy(hw, IFE_PHY_SPECIAL_CONTROL_LED, 55738c2ecf20Sopenharmony_ci (IFE_PSCL_PROBE_MODE | 55748c2ecf20Sopenharmony_ci IFE_PSCL_PROBE_LEDS_OFF)); 55758c2ecf20Sopenharmony_ci 55768c2ecf20Sopenharmony_ci ew32(LEDCTL, hw->mac.ledctl_mode1); 55778c2ecf20Sopenharmony_ci return 0; 55788c2ecf20Sopenharmony_ci} 55798c2ecf20Sopenharmony_ci 55808c2ecf20Sopenharmony_ci/** 55818c2ecf20Sopenharmony_ci * e1000_setup_led_pchlan - Configures SW controllable LED 55828c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 55838c2ecf20Sopenharmony_ci * 55848c2ecf20Sopenharmony_ci * This prepares the SW controllable LED for use. 55858c2ecf20Sopenharmony_ci **/ 55868c2ecf20Sopenharmony_cistatic s32 e1000_setup_led_pchlan(struct e1000_hw *hw) 55878c2ecf20Sopenharmony_ci{ 55888c2ecf20Sopenharmony_ci return e1e_wphy(hw, HV_LED_CONFIG, (u16)hw->mac.ledctl_mode1); 55898c2ecf20Sopenharmony_ci} 55908c2ecf20Sopenharmony_ci 55918c2ecf20Sopenharmony_ci/** 55928c2ecf20Sopenharmony_ci * e1000_cleanup_led_pchlan - Restore the default LED operation 55938c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 55948c2ecf20Sopenharmony_ci * 55958c2ecf20Sopenharmony_ci * Return the LED back to the default configuration. 55968c2ecf20Sopenharmony_ci **/ 55978c2ecf20Sopenharmony_cistatic s32 e1000_cleanup_led_pchlan(struct e1000_hw *hw) 55988c2ecf20Sopenharmony_ci{ 55998c2ecf20Sopenharmony_ci return e1e_wphy(hw, HV_LED_CONFIG, (u16)hw->mac.ledctl_default); 56008c2ecf20Sopenharmony_ci} 56018c2ecf20Sopenharmony_ci 56028c2ecf20Sopenharmony_ci/** 56038c2ecf20Sopenharmony_ci * e1000_led_on_pchlan - Turn LEDs on 56048c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 56058c2ecf20Sopenharmony_ci * 56068c2ecf20Sopenharmony_ci * Turn on the LEDs. 56078c2ecf20Sopenharmony_ci **/ 56088c2ecf20Sopenharmony_cistatic s32 e1000_led_on_pchlan(struct e1000_hw *hw) 56098c2ecf20Sopenharmony_ci{ 56108c2ecf20Sopenharmony_ci u16 data = (u16)hw->mac.ledctl_mode2; 56118c2ecf20Sopenharmony_ci u32 i, led; 56128c2ecf20Sopenharmony_ci 56138c2ecf20Sopenharmony_ci /* If no link, then turn LED on by setting the invert bit 56148c2ecf20Sopenharmony_ci * for each LED that's mode is "link_up" in ledctl_mode2. 56158c2ecf20Sopenharmony_ci */ 56168c2ecf20Sopenharmony_ci if (!(er32(STATUS) & E1000_STATUS_LU)) { 56178c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 56188c2ecf20Sopenharmony_ci led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 56198c2ecf20Sopenharmony_ci if ((led & E1000_PHY_LED0_MODE_MASK) != 56208c2ecf20Sopenharmony_ci E1000_LEDCTL_MODE_LINK_UP) 56218c2ecf20Sopenharmony_ci continue; 56228c2ecf20Sopenharmony_ci if (led & E1000_PHY_LED0_IVRT) 56238c2ecf20Sopenharmony_ci data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 56248c2ecf20Sopenharmony_ci else 56258c2ecf20Sopenharmony_ci data |= (E1000_PHY_LED0_IVRT << (i * 5)); 56268c2ecf20Sopenharmony_ci } 56278c2ecf20Sopenharmony_ci } 56288c2ecf20Sopenharmony_ci 56298c2ecf20Sopenharmony_ci return e1e_wphy(hw, HV_LED_CONFIG, data); 56308c2ecf20Sopenharmony_ci} 56318c2ecf20Sopenharmony_ci 56328c2ecf20Sopenharmony_ci/** 56338c2ecf20Sopenharmony_ci * e1000_led_off_pchlan - Turn LEDs off 56348c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 56358c2ecf20Sopenharmony_ci * 56368c2ecf20Sopenharmony_ci * Turn off the LEDs. 56378c2ecf20Sopenharmony_ci **/ 56388c2ecf20Sopenharmony_cistatic s32 e1000_led_off_pchlan(struct e1000_hw *hw) 56398c2ecf20Sopenharmony_ci{ 56408c2ecf20Sopenharmony_ci u16 data = (u16)hw->mac.ledctl_mode1; 56418c2ecf20Sopenharmony_ci u32 i, led; 56428c2ecf20Sopenharmony_ci 56438c2ecf20Sopenharmony_ci /* If no link, then turn LED off by clearing the invert bit 56448c2ecf20Sopenharmony_ci * for each LED that's mode is "link_up" in ledctl_mode1. 56458c2ecf20Sopenharmony_ci */ 56468c2ecf20Sopenharmony_ci if (!(er32(STATUS) & E1000_STATUS_LU)) { 56478c2ecf20Sopenharmony_ci for (i = 0; i < 3; i++) { 56488c2ecf20Sopenharmony_ci led = (data >> (i * 5)) & E1000_PHY_LED0_MASK; 56498c2ecf20Sopenharmony_ci if ((led & E1000_PHY_LED0_MODE_MASK) != 56508c2ecf20Sopenharmony_ci E1000_LEDCTL_MODE_LINK_UP) 56518c2ecf20Sopenharmony_ci continue; 56528c2ecf20Sopenharmony_ci if (led & E1000_PHY_LED0_IVRT) 56538c2ecf20Sopenharmony_ci data &= ~(E1000_PHY_LED0_IVRT << (i * 5)); 56548c2ecf20Sopenharmony_ci else 56558c2ecf20Sopenharmony_ci data |= (E1000_PHY_LED0_IVRT << (i * 5)); 56568c2ecf20Sopenharmony_ci } 56578c2ecf20Sopenharmony_ci } 56588c2ecf20Sopenharmony_ci 56598c2ecf20Sopenharmony_ci return e1e_wphy(hw, HV_LED_CONFIG, data); 56608c2ecf20Sopenharmony_ci} 56618c2ecf20Sopenharmony_ci 56628c2ecf20Sopenharmony_ci/** 56638c2ecf20Sopenharmony_ci * e1000_get_cfg_done_ich8lan - Read config done bit after Full or PHY reset 56648c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 56658c2ecf20Sopenharmony_ci * 56668c2ecf20Sopenharmony_ci * Read appropriate register for the config done bit for completion status 56678c2ecf20Sopenharmony_ci * and configure the PHY through s/w for EEPROM-less parts. 56688c2ecf20Sopenharmony_ci * 56698c2ecf20Sopenharmony_ci * NOTE: some silicon which is EEPROM-less will fail trying to read the 56708c2ecf20Sopenharmony_ci * config done bit, so only an error is logged and continues. If we were 56718c2ecf20Sopenharmony_ci * to return with error, EEPROM-less silicon would not be able to be reset 56728c2ecf20Sopenharmony_ci * or change link. 56738c2ecf20Sopenharmony_ci **/ 56748c2ecf20Sopenharmony_cistatic s32 e1000_get_cfg_done_ich8lan(struct e1000_hw *hw) 56758c2ecf20Sopenharmony_ci{ 56768c2ecf20Sopenharmony_ci s32 ret_val = 0; 56778c2ecf20Sopenharmony_ci u32 bank = 0; 56788c2ecf20Sopenharmony_ci u32 status; 56798c2ecf20Sopenharmony_ci 56808c2ecf20Sopenharmony_ci e1000e_get_cfg_done_generic(hw); 56818c2ecf20Sopenharmony_ci 56828c2ecf20Sopenharmony_ci /* Wait for indication from h/w that it has completed basic config */ 56838c2ecf20Sopenharmony_ci if (hw->mac.type >= e1000_ich10lan) { 56848c2ecf20Sopenharmony_ci e1000_lan_init_done_ich8lan(hw); 56858c2ecf20Sopenharmony_ci } else { 56868c2ecf20Sopenharmony_ci ret_val = e1000e_get_auto_rd_done(hw); 56878c2ecf20Sopenharmony_ci if (ret_val) { 56888c2ecf20Sopenharmony_ci /* When auto config read does not complete, do not 56898c2ecf20Sopenharmony_ci * return with an error. This can happen in situations 56908c2ecf20Sopenharmony_ci * where there is no eeprom and prevents getting link. 56918c2ecf20Sopenharmony_ci */ 56928c2ecf20Sopenharmony_ci e_dbg("Auto Read Done did not complete\n"); 56938c2ecf20Sopenharmony_ci ret_val = 0; 56948c2ecf20Sopenharmony_ci } 56958c2ecf20Sopenharmony_ci } 56968c2ecf20Sopenharmony_ci 56978c2ecf20Sopenharmony_ci /* Clear PHY Reset Asserted bit */ 56988c2ecf20Sopenharmony_ci status = er32(STATUS); 56998c2ecf20Sopenharmony_ci if (status & E1000_STATUS_PHYRA) 57008c2ecf20Sopenharmony_ci ew32(STATUS, status & ~E1000_STATUS_PHYRA); 57018c2ecf20Sopenharmony_ci else 57028c2ecf20Sopenharmony_ci e_dbg("PHY Reset Asserted not set - needs delay\n"); 57038c2ecf20Sopenharmony_ci 57048c2ecf20Sopenharmony_ci /* If EEPROM is not marked present, init the IGP 3 PHY manually */ 57058c2ecf20Sopenharmony_ci if (hw->mac.type <= e1000_ich9lan) { 57068c2ecf20Sopenharmony_ci if (!(er32(EECD) & E1000_EECD_PRES) && 57078c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_igp_3)) { 57088c2ecf20Sopenharmony_ci e1000e_phy_init_script_igp3(hw); 57098c2ecf20Sopenharmony_ci } 57108c2ecf20Sopenharmony_ci } else { 57118c2ecf20Sopenharmony_ci if (e1000_valid_nvm_bank_detect_ich8lan(hw, &bank)) { 57128c2ecf20Sopenharmony_ci /* Maybe we should do a basic PHY config */ 57138c2ecf20Sopenharmony_ci e_dbg("EEPROM not present\n"); 57148c2ecf20Sopenharmony_ci ret_val = -E1000_ERR_CONFIG; 57158c2ecf20Sopenharmony_ci } 57168c2ecf20Sopenharmony_ci } 57178c2ecf20Sopenharmony_ci 57188c2ecf20Sopenharmony_ci return ret_val; 57198c2ecf20Sopenharmony_ci} 57208c2ecf20Sopenharmony_ci 57218c2ecf20Sopenharmony_ci/** 57228c2ecf20Sopenharmony_ci * e1000_power_down_phy_copper_ich8lan - Remove link during PHY power down 57238c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 57248c2ecf20Sopenharmony_ci * 57258c2ecf20Sopenharmony_ci * In the case of a PHY power down to save power, or to turn off link during a 57268c2ecf20Sopenharmony_ci * driver unload, or wake on lan is not enabled, remove the link. 57278c2ecf20Sopenharmony_ci **/ 57288c2ecf20Sopenharmony_cistatic void e1000_power_down_phy_copper_ich8lan(struct e1000_hw *hw) 57298c2ecf20Sopenharmony_ci{ 57308c2ecf20Sopenharmony_ci /* If the management interface is not enabled, then power down */ 57318c2ecf20Sopenharmony_ci if (!(hw->mac.ops.check_mng_mode(hw) || 57328c2ecf20Sopenharmony_ci hw->phy.ops.check_reset_block(hw))) 57338c2ecf20Sopenharmony_ci e1000_power_down_phy_copper(hw); 57348c2ecf20Sopenharmony_ci} 57358c2ecf20Sopenharmony_ci 57368c2ecf20Sopenharmony_ci/** 57378c2ecf20Sopenharmony_ci * e1000_clear_hw_cntrs_ich8lan - Clear statistical counters 57388c2ecf20Sopenharmony_ci * @hw: pointer to the HW structure 57398c2ecf20Sopenharmony_ci * 57408c2ecf20Sopenharmony_ci * Clears hardware counters specific to the silicon family and calls 57418c2ecf20Sopenharmony_ci * clear_hw_cntrs_generic to clear all general purpose counters. 57428c2ecf20Sopenharmony_ci **/ 57438c2ecf20Sopenharmony_cistatic void e1000_clear_hw_cntrs_ich8lan(struct e1000_hw *hw) 57448c2ecf20Sopenharmony_ci{ 57458c2ecf20Sopenharmony_ci u16 phy_data; 57468c2ecf20Sopenharmony_ci s32 ret_val; 57478c2ecf20Sopenharmony_ci 57488c2ecf20Sopenharmony_ci e1000e_clear_hw_cntrs_base(hw); 57498c2ecf20Sopenharmony_ci 57508c2ecf20Sopenharmony_ci er32(ALGNERRC); 57518c2ecf20Sopenharmony_ci er32(RXERRC); 57528c2ecf20Sopenharmony_ci er32(TNCRS); 57538c2ecf20Sopenharmony_ci er32(CEXTERR); 57548c2ecf20Sopenharmony_ci er32(TSCTC); 57558c2ecf20Sopenharmony_ci er32(TSCTFC); 57568c2ecf20Sopenharmony_ci 57578c2ecf20Sopenharmony_ci er32(MGTPRC); 57588c2ecf20Sopenharmony_ci er32(MGTPDC); 57598c2ecf20Sopenharmony_ci er32(MGTPTC); 57608c2ecf20Sopenharmony_ci 57618c2ecf20Sopenharmony_ci er32(IAC); 57628c2ecf20Sopenharmony_ci er32(ICRXOC); 57638c2ecf20Sopenharmony_ci 57648c2ecf20Sopenharmony_ci /* Clear PHY statistics registers */ 57658c2ecf20Sopenharmony_ci if ((hw->phy.type == e1000_phy_82578) || 57668c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_82579) || 57678c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_i217) || 57688c2ecf20Sopenharmony_ci (hw->phy.type == e1000_phy_82577)) { 57698c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.acquire(hw); 57708c2ecf20Sopenharmony_ci if (ret_val) 57718c2ecf20Sopenharmony_ci return; 57728c2ecf20Sopenharmony_ci ret_val = hw->phy.ops.set_page(hw, 57738c2ecf20Sopenharmony_ci HV_STATS_PAGE << IGP_PAGE_SHIFT); 57748c2ecf20Sopenharmony_ci if (ret_val) 57758c2ecf20Sopenharmony_ci goto release; 57768c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_SCC_UPPER, &phy_data); 57778c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_SCC_LOWER, &phy_data); 57788c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_ECOL_UPPER, &phy_data); 57798c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_ECOL_LOWER, &phy_data); 57808c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_MCC_UPPER, &phy_data); 57818c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_MCC_LOWER, &phy_data); 57828c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_LATECOL_UPPER, &phy_data); 57838c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_LATECOL_LOWER, &phy_data); 57848c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_COLC_UPPER, &phy_data); 57858c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_COLC_LOWER, &phy_data); 57868c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_DC_UPPER, &phy_data); 57878c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_DC_LOWER, &phy_data); 57888c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_TNCRS_UPPER, &phy_data); 57898c2ecf20Sopenharmony_ci hw->phy.ops.read_reg_page(hw, HV_TNCRS_LOWER, &phy_data); 57908c2ecf20Sopenharmony_cirelease: 57918c2ecf20Sopenharmony_ci hw->phy.ops.release(hw); 57928c2ecf20Sopenharmony_ci } 57938c2ecf20Sopenharmony_ci} 57948c2ecf20Sopenharmony_ci 57958c2ecf20Sopenharmony_cistatic const struct e1000_mac_operations ich8_mac_ops = { 57968c2ecf20Sopenharmony_ci /* check_mng_mode dependent on mac type */ 57978c2ecf20Sopenharmony_ci .check_for_link = e1000_check_for_copper_link_ich8lan, 57988c2ecf20Sopenharmony_ci /* cleanup_led dependent on mac type */ 57998c2ecf20Sopenharmony_ci .clear_hw_cntrs = e1000_clear_hw_cntrs_ich8lan, 58008c2ecf20Sopenharmony_ci .get_bus_info = e1000_get_bus_info_ich8lan, 58018c2ecf20Sopenharmony_ci .set_lan_id = e1000_set_lan_id_single_port, 58028c2ecf20Sopenharmony_ci .get_link_up_info = e1000_get_link_up_info_ich8lan, 58038c2ecf20Sopenharmony_ci /* led_on dependent on mac type */ 58048c2ecf20Sopenharmony_ci /* led_off dependent on mac type */ 58058c2ecf20Sopenharmony_ci .update_mc_addr_list = e1000e_update_mc_addr_list_generic, 58068c2ecf20Sopenharmony_ci .reset_hw = e1000_reset_hw_ich8lan, 58078c2ecf20Sopenharmony_ci .init_hw = e1000_init_hw_ich8lan, 58088c2ecf20Sopenharmony_ci .setup_link = e1000_setup_link_ich8lan, 58098c2ecf20Sopenharmony_ci .setup_physical_interface = e1000_setup_copper_link_ich8lan, 58108c2ecf20Sopenharmony_ci /* id_led_init dependent on mac type */ 58118c2ecf20Sopenharmony_ci .config_collision_dist = e1000e_config_collision_dist_generic, 58128c2ecf20Sopenharmony_ci .rar_set = e1000e_rar_set_generic, 58138c2ecf20Sopenharmony_ci .rar_get_count = e1000e_rar_get_count_generic, 58148c2ecf20Sopenharmony_ci}; 58158c2ecf20Sopenharmony_ci 58168c2ecf20Sopenharmony_cistatic const struct e1000_phy_operations ich8_phy_ops = { 58178c2ecf20Sopenharmony_ci .acquire = e1000_acquire_swflag_ich8lan, 58188c2ecf20Sopenharmony_ci .check_reset_block = e1000_check_reset_block_ich8lan, 58198c2ecf20Sopenharmony_ci .commit = NULL, 58208c2ecf20Sopenharmony_ci .get_cfg_done = e1000_get_cfg_done_ich8lan, 58218c2ecf20Sopenharmony_ci .get_cable_length = e1000e_get_cable_length_igp_2, 58228c2ecf20Sopenharmony_ci .read_reg = e1000e_read_phy_reg_igp, 58238c2ecf20Sopenharmony_ci .release = e1000_release_swflag_ich8lan, 58248c2ecf20Sopenharmony_ci .reset = e1000_phy_hw_reset_ich8lan, 58258c2ecf20Sopenharmony_ci .set_d0_lplu_state = e1000_set_d0_lplu_state_ich8lan, 58268c2ecf20Sopenharmony_ci .set_d3_lplu_state = e1000_set_d3_lplu_state_ich8lan, 58278c2ecf20Sopenharmony_ci .write_reg = e1000e_write_phy_reg_igp, 58288c2ecf20Sopenharmony_ci}; 58298c2ecf20Sopenharmony_ci 58308c2ecf20Sopenharmony_cistatic const struct e1000_nvm_operations ich8_nvm_ops = { 58318c2ecf20Sopenharmony_ci .acquire = e1000_acquire_nvm_ich8lan, 58328c2ecf20Sopenharmony_ci .read = e1000_read_nvm_ich8lan, 58338c2ecf20Sopenharmony_ci .release = e1000_release_nvm_ich8lan, 58348c2ecf20Sopenharmony_ci .reload = e1000e_reload_nvm_generic, 58358c2ecf20Sopenharmony_ci .update = e1000_update_nvm_checksum_ich8lan, 58368c2ecf20Sopenharmony_ci .valid_led_default = e1000_valid_led_default_ich8lan, 58378c2ecf20Sopenharmony_ci .validate = e1000_validate_nvm_checksum_ich8lan, 58388c2ecf20Sopenharmony_ci .write = e1000_write_nvm_ich8lan, 58398c2ecf20Sopenharmony_ci}; 58408c2ecf20Sopenharmony_ci 58418c2ecf20Sopenharmony_cistatic const struct e1000_nvm_operations spt_nvm_ops = { 58428c2ecf20Sopenharmony_ci .acquire = e1000_acquire_nvm_ich8lan, 58438c2ecf20Sopenharmony_ci .release = e1000_release_nvm_ich8lan, 58448c2ecf20Sopenharmony_ci .read = e1000_read_nvm_spt, 58458c2ecf20Sopenharmony_ci .update = e1000_update_nvm_checksum_spt, 58468c2ecf20Sopenharmony_ci .reload = e1000e_reload_nvm_generic, 58478c2ecf20Sopenharmony_ci .valid_led_default = e1000_valid_led_default_ich8lan, 58488c2ecf20Sopenharmony_ci .validate = e1000_validate_nvm_checksum_ich8lan, 58498c2ecf20Sopenharmony_ci .write = e1000_write_nvm_ich8lan, 58508c2ecf20Sopenharmony_ci}; 58518c2ecf20Sopenharmony_ci 58528c2ecf20Sopenharmony_ciconst struct e1000_info e1000_ich8_info = { 58538c2ecf20Sopenharmony_ci .mac = e1000_ich8lan, 58548c2ecf20Sopenharmony_ci .flags = FLAG_HAS_WOL 58558c2ecf20Sopenharmony_ci | FLAG_IS_ICH 58568c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 58578c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 58588c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 58598c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 58608c2ecf20Sopenharmony_ci .pba = 8, 58618c2ecf20Sopenharmony_ci .max_hw_frame_size = VLAN_ETH_FRAME_LEN + ETH_FCS_LEN, 58628c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 58638c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 58648c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 58658c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 58668c2ecf20Sopenharmony_ci}; 58678c2ecf20Sopenharmony_ci 58688c2ecf20Sopenharmony_ciconst struct e1000_info e1000_ich9_info = { 58698c2ecf20Sopenharmony_ci .mac = e1000_ich9lan, 58708c2ecf20Sopenharmony_ci .flags = FLAG_HAS_JUMBO_FRAMES 58718c2ecf20Sopenharmony_ci | FLAG_IS_ICH 58728c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 58738c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 58748c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 58758c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 58768c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 58778c2ecf20Sopenharmony_ci .pba = 18, 58788c2ecf20Sopenharmony_ci .max_hw_frame_size = DEFAULT_JUMBO, 58798c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 58808c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 58818c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 58828c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 58838c2ecf20Sopenharmony_ci}; 58848c2ecf20Sopenharmony_ci 58858c2ecf20Sopenharmony_ciconst struct e1000_info e1000_ich10_info = { 58868c2ecf20Sopenharmony_ci .mac = e1000_ich10lan, 58878c2ecf20Sopenharmony_ci .flags = FLAG_HAS_JUMBO_FRAMES 58888c2ecf20Sopenharmony_ci | FLAG_IS_ICH 58898c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 58908c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 58918c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 58928c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 58938c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 58948c2ecf20Sopenharmony_ci .pba = 18, 58958c2ecf20Sopenharmony_ci .max_hw_frame_size = DEFAULT_JUMBO, 58968c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 58978c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 58988c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 58998c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 59008c2ecf20Sopenharmony_ci}; 59018c2ecf20Sopenharmony_ci 59028c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch_info = { 59038c2ecf20Sopenharmony_ci .mac = e1000_pchlan, 59048c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 59058c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 59068c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 59078c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 59088c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 59098c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 59108c2ecf20Sopenharmony_ci | FLAG_DISABLE_FC_PAUSE_TIME /* errata */ 59118c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 59128c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS, 59138c2ecf20Sopenharmony_ci .pba = 26, 59148c2ecf20Sopenharmony_ci .max_hw_frame_size = 4096, 59158c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 59168c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 59178c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 59188c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 59198c2ecf20Sopenharmony_ci}; 59208c2ecf20Sopenharmony_ci 59218c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch2_info = { 59228c2ecf20Sopenharmony_ci .mac = e1000_pch2lan, 59238c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 59248c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 59258c2ecf20Sopenharmony_ci | FLAG_HAS_HW_TIMESTAMP 59268c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 59278c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 59288c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 59298c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 59308c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 59318c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS 59328c2ecf20Sopenharmony_ci | FLAG2_HAS_EEE 59338c2ecf20Sopenharmony_ci | FLAG2_CHECK_SYSTIM_OVERFLOW, 59348c2ecf20Sopenharmony_ci .pba = 26, 59358c2ecf20Sopenharmony_ci .max_hw_frame_size = 9022, 59368c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 59378c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 59388c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 59398c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 59408c2ecf20Sopenharmony_ci}; 59418c2ecf20Sopenharmony_ci 59428c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch_lpt_info = { 59438c2ecf20Sopenharmony_ci .mac = e1000_pch_lpt, 59448c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 59458c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 59468c2ecf20Sopenharmony_ci | FLAG_HAS_HW_TIMESTAMP 59478c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 59488c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 59498c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 59508c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 59518c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 59528c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS 59538c2ecf20Sopenharmony_ci | FLAG2_HAS_EEE 59548c2ecf20Sopenharmony_ci | FLAG2_CHECK_SYSTIM_OVERFLOW, 59558c2ecf20Sopenharmony_ci .pba = 26, 59568c2ecf20Sopenharmony_ci .max_hw_frame_size = 9022, 59578c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 59588c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 59598c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 59608c2ecf20Sopenharmony_ci .nvm_ops = &ich8_nvm_ops, 59618c2ecf20Sopenharmony_ci}; 59628c2ecf20Sopenharmony_ci 59638c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch_spt_info = { 59648c2ecf20Sopenharmony_ci .mac = e1000_pch_spt, 59658c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 59668c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 59678c2ecf20Sopenharmony_ci | FLAG_HAS_HW_TIMESTAMP 59688c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 59698c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 59708c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 59718c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 59728c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 59738c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS 59748c2ecf20Sopenharmony_ci | FLAG2_HAS_EEE, 59758c2ecf20Sopenharmony_ci .pba = 26, 59768c2ecf20Sopenharmony_ci .max_hw_frame_size = 9022, 59778c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 59788c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 59798c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 59808c2ecf20Sopenharmony_ci .nvm_ops = &spt_nvm_ops, 59818c2ecf20Sopenharmony_ci}; 59828c2ecf20Sopenharmony_ci 59838c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch_cnp_info = { 59848c2ecf20Sopenharmony_ci .mac = e1000_pch_cnp, 59858c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 59868c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 59878c2ecf20Sopenharmony_ci | FLAG_HAS_HW_TIMESTAMP 59888c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 59898c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 59908c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 59918c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 59928c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 59938c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS 59948c2ecf20Sopenharmony_ci | FLAG2_HAS_EEE, 59958c2ecf20Sopenharmony_ci .pba = 26, 59968c2ecf20Sopenharmony_ci .max_hw_frame_size = 9022, 59978c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 59988c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 59998c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 60008c2ecf20Sopenharmony_ci .nvm_ops = &spt_nvm_ops, 60018c2ecf20Sopenharmony_ci}; 60028c2ecf20Sopenharmony_ci 60038c2ecf20Sopenharmony_ciconst struct e1000_info e1000_pch_tgp_info = { 60048c2ecf20Sopenharmony_ci .mac = e1000_pch_tgp, 60058c2ecf20Sopenharmony_ci .flags = FLAG_IS_ICH 60068c2ecf20Sopenharmony_ci | FLAG_HAS_WOL 60078c2ecf20Sopenharmony_ci | FLAG_HAS_HW_TIMESTAMP 60088c2ecf20Sopenharmony_ci | FLAG_HAS_CTRLEXT_ON_LOAD 60098c2ecf20Sopenharmony_ci | FLAG_HAS_AMT 60108c2ecf20Sopenharmony_ci | FLAG_HAS_FLASH 60118c2ecf20Sopenharmony_ci | FLAG_HAS_JUMBO_FRAMES 60128c2ecf20Sopenharmony_ci | FLAG_APME_IN_WUC, 60138c2ecf20Sopenharmony_ci .flags2 = FLAG2_HAS_PHY_STATS 60148c2ecf20Sopenharmony_ci | FLAG2_HAS_EEE, 60158c2ecf20Sopenharmony_ci .pba = 26, 60168c2ecf20Sopenharmony_ci .max_hw_frame_size = 9022, 60178c2ecf20Sopenharmony_ci .get_variants = e1000_get_variants_ich8lan, 60188c2ecf20Sopenharmony_ci .mac_ops = &ich8_mac_ops, 60198c2ecf20Sopenharmony_ci .phy_ops = &ich8_phy_ops, 60208c2ecf20Sopenharmony_ci .nvm_ops = &spt_nvm_ops, 60218c2ecf20Sopenharmony_ci}; 6022