162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2013 Johannes Berg <johannes@sipsolutions.net> 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This file is free software: you may copy, redistribute and/or modify it 562306a36Sopenharmony_ci * under the terms of the GNU General Public License as published by the 662306a36Sopenharmony_ci * Free Software Foundation, either version 2 of the License, or (at your 762306a36Sopenharmony_ci * option) any later version. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * This file is distributed in the hope that it will be useful, but 1062306a36Sopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of 1162306a36Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1262306a36Sopenharmony_ci * General Public License for more details. 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * You should have received a copy of the GNU General Public License 1562306a36Sopenharmony_ci * along with this program. If not, see <http://www.gnu.org/licenses/>. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci * This file incorporates work covered by the following copyright and 1862306a36Sopenharmony_ci * permission notice: 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Copyright (c) 2012 Qualcomm Atheros, Inc. 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * Permission to use, copy, modify, and/or distribute this software for any 2362306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 2462306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 2562306a36Sopenharmony_ci * 2662306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 2762306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 2862306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 2962306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 3062306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 3162306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 3262306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci#include <linux/etherdevice.h> 3562306a36Sopenharmony_ci#include <linux/delay.h> 3662306a36Sopenharmony_ci#include <linux/pci.h> 3762306a36Sopenharmony_ci#include <linux/mdio.h> 3862306a36Sopenharmony_ci#include "reg.h" 3962306a36Sopenharmony_ci#include "hw.h" 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic inline bool alx_is_rev_a(u8 rev) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci return rev == ALX_REV_A0 || rev == ALX_REV_A1; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic int alx_wait_mdio_idle(struct alx_hw *hw) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci u32 val; 4962306a36Sopenharmony_ci int i; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci for (i = 0; i < ALX_MDIO_MAX_AC_TO; i++) { 5262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MDIO); 5362306a36Sopenharmony_ci if (!(val & ALX_MDIO_BUSY)) 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci udelay(10); 5662306a36Sopenharmony_ci } 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci return -ETIMEDOUT; 5962306a36Sopenharmony_ci} 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_cistatic int alx_read_phy_core(struct alx_hw *hw, bool ext, u8 dev, 6262306a36Sopenharmony_ci u16 reg, u16 *phy_data) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci u32 val, clk_sel; 6562306a36Sopenharmony_ci int err; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci *phy_data = 0; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci /* use slow clock when it's in hibernation status */ 7062306a36Sopenharmony_ci clk_sel = hw->link_speed != SPEED_UNKNOWN ? 7162306a36Sopenharmony_ci ALX_MDIO_CLK_SEL_25MD4 : 7262306a36Sopenharmony_ci ALX_MDIO_CLK_SEL_25MD128; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (ext) { 7562306a36Sopenharmony_ci val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT | 7662306a36Sopenharmony_ci reg << ALX_MDIO_EXTN_REG_SHIFT; 7762306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MDIO_EXTN, val); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci val = ALX_MDIO_SPRES_PRMBL | ALX_MDIO_START | 8062306a36Sopenharmony_ci ALX_MDIO_MODE_EXT | ALX_MDIO_OP_READ | 8162306a36Sopenharmony_ci clk_sel << ALX_MDIO_CLK_SEL_SHIFT; 8262306a36Sopenharmony_ci } else { 8362306a36Sopenharmony_ci val = ALX_MDIO_SPRES_PRMBL | 8462306a36Sopenharmony_ci clk_sel << ALX_MDIO_CLK_SEL_SHIFT | 8562306a36Sopenharmony_ci reg << ALX_MDIO_REG_SHIFT | 8662306a36Sopenharmony_ci ALX_MDIO_START | ALX_MDIO_OP_READ; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MDIO, val); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci err = alx_wait_mdio_idle(hw); 9162306a36Sopenharmony_ci if (err) 9262306a36Sopenharmony_ci return err; 9362306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MDIO); 9462306a36Sopenharmony_ci *phy_data = ALX_GET_FIELD(val, ALX_MDIO_DATA); 9562306a36Sopenharmony_ci return 0; 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic int alx_write_phy_core(struct alx_hw *hw, bool ext, u8 dev, 9962306a36Sopenharmony_ci u16 reg, u16 phy_data) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci u32 val, clk_sel; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* use slow clock when it's in hibernation status */ 10462306a36Sopenharmony_ci clk_sel = hw->link_speed != SPEED_UNKNOWN ? 10562306a36Sopenharmony_ci ALX_MDIO_CLK_SEL_25MD4 : 10662306a36Sopenharmony_ci ALX_MDIO_CLK_SEL_25MD128; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (ext) { 10962306a36Sopenharmony_ci val = dev << ALX_MDIO_EXTN_DEVAD_SHIFT | 11062306a36Sopenharmony_ci reg << ALX_MDIO_EXTN_REG_SHIFT; 11162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MDIO_EXTN, val); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci val = ALX_MDIO_SPRES_PRMBL | 11462306a36Sopenharmony_ci clk_sel << ALX_MDIO_CLK_SEL_SHIFT | 11562306a36Sopenharmony_ci phy_data << ALX_MDIO_DATA_SHIFT | 11662306a36Sopenharmony_ci ALX_MDIO_START | ALX_MDIO_MODE_EXT; 11762306a36Sopenharmony_ci } else { 11862306a36Sopenharmony_ci val = ALX_MDIO_SPRES_PRMBL | 11962306a36Sopenharmony_ci clk_sel << ALX_MDIO_CLK_SEL_SHIFT | 12062306a36Sopenharmony_ci reg << ALX_MDIO_REG_SHIFT | 12162306a36Sopenharmony_ci phy_data << ALX_MDIO_DATA_SHIFT | 12262306a36Sopenharmony_ci ALX_MDIO_START; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MDIO, val); 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return alx_wait_mdio_idle(hw); 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_cistatic int __alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci return alx_read_phy_core(hw, false, 0, reg, phy_data); 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_cistatic int __alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data) 13562306a36Sopenharmony_ci{ 13662306a36Sopenharmony_ci return alx_write_phy_core(hw, false, 0, reg, phy_data); 13762306a36Sopenharmony_ci} 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_cistatic int __alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci return alx_read_phy_core(hw, true, dev, reg, pdata); 14262306a36Sopenharmony_ci} 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_cistatic int __alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data) 14562306a36Sopenharmony_ci{ 14662306a36Sopenharmony_ci return alx_write_phy_core(hw, true, dev, reg, data); 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_cistatic int __alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci int err; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg); 15462306a36Sopenharmony_ci if (err) 15562306a36Sopenharmony_ci return err; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci return __alx_read_phy_reg(hw, ALX_MII_DBG_DATA, pdata); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic int __alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci int err; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci err = __alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, reg); 16562306a36Sopenharmony_ci if (err) 16662306a36Sopenharmony_ci return err; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci return __alx_write_phy_reg(hw, ALX_MII_DBG_DATA, data); 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ciint alx_read_phy_reg(struct alx_hw *hw, u16 reg, u16 *phy_data) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci int err; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 17662306a36Sopenharmony_ci err = __alx_read_phy_reg(hw, reg, phy_data); 17762306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return err; 18062306a36Sopenharmony_ci} 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ciint alx_write_phy_reg(struct alx_hw *hw, u16 reg, u16 phy_data) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci int err; 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 18762306a36Sopenharmony_ci err = __alx_write_phy_reg(hw, reg, phy_data); 18862306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return err; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ciint alx_read_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 *pdata) 19462306a36Sopenharmony_ci{ 19562306a36Sopenharmony_ci int err; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 19862306a36Sopenharmony_ci err = __alx_read_phy_ext(hw, dev, reg, pdata); 19962306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return err; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ciint alx_write_phy_ext(struct alx_hw *hw, u8 dev, u16 reg, u16 data) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci int err; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 20962306a36Sopenharmony_ci err = __alx_write_phy_ext(hw, dev, reg, data); 21062306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci return err; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int alx_read_phy_dbg(struct alx_hw *hw, u16 reg, u16 *pdata) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci int err; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 22062306a36Sopenharmony_ci err = __alx_read_phy_dbg(hw, reg, pdata); 22162306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci return err; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int alx_write_phy_dbg(struct alx_hw *hw, u16 reg, u16 data) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int err; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci spin_lock(&hw->mdio_lock); 23162306a36Sopenharmony_ci err = __alx_write_phy_dbg(hw, reg, data); 23262306a36Sopenharmony_ci spin_unlock(&hw->mdio_lock); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci return err; 23562306a36Sopenharmony_ci} 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cistatic u16 alx_get_phy_config(struct alx_hw *hw) 23862306a36Sopenharmony_ci{ 23962306a36Sopenharmony_ci u32 val; 24062306a36Sopenharmony_ci u16 phy_val; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_PHY_CTRL); 24362306a36Sopenharmony_ci /* phy in reset */ 24462306a36Sopenharmony_ci if ((val & ALX_PHY_CTRL_DSPRST_OUT) == 0) 24562306a36Sopenharmony_ci return ALX_DRV_PHY_UNKNOWN; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_DRV); 24862306a36Sopenharmony_ci val = ALX_GET_FIELD(val, ALX_DRV_PHY); 24962306a36Sopenharmony_ci if (ALX_DRV_PHY_UNKNOWN == val) 25062306a36Sopenharmony_ci return ALX_DRV_PHY_UNKNOWN; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci alx_read_phy_reg(hw, ALX_MII_DBG_ADDR, &phy_val); 25362306a36Sopenharmony_ci if (ALX_PHY_INITED == phy_val) 25462306a36Sopenharmony_ci return val; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return ALX_DRV_PHY_UNKNOWN; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic bool alx_wait_reg(struct alx_hw *hw, u32 reg, u32 wait, u32 *val) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci u32 read; 26262306a36Sopenharmony_ci int i; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci for (i = 0; i < ALX_SLD_MAX_TO; i++) { 26562306a36Sopenharmony_ci read = alx_read_mem32(hw, reg); 26662306a36Sopenharmony_ci if ((read & wait) == 0) { 26762306a36Sopenharmony_ci if (val) 26862306a36Sopenharmony_ci *val = read; 26962306a36Sopenharmony_ci return true; 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci mdelay(1); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci return false; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistatic bool alx_read_macaddr(struct alx_hw *hw, u8 *addr) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci u32 mac0, mac1; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mac0 = alx_read_mem32(hw, ALX_STAD0); 28262306a36Sopenharmony_ci mac1 = alx_read_mem32(hw, ALX_STAD1); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci /* addr should be big-endian */ 28562306a36Sopenharmony_ci put_unaligned(cpu_to_be32(mac0), (__be32 *)(addr + 2)); 28662306a36Sopenharmony_ci put_unaligned(cpu_to_be16(mac1), (__be16 *)addr); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return is_valid_ether_addr(addr); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ciint alx_get_perm_macaddr(struct alx_hw *hw, u8 *addr) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci u32 val; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* try to get it from register first */ 29662306a36Sopenharmony_ci if (alx_read_macaddr(hw, addr)) 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci /* try to load from efuse */ 30062306a36Sopenharmony_ci if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_STAT | ALX_SLD_START, &val)) 30162306a36Sopenharmony_ci return -EIO; 30262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_SLD, val | ALX_SLD_START); 30362306a36Sopenharmony_ci if (!alx_wait_reg(hw, ALX_SLD, ALX_SLD_START, NULL)) 30462306a36Sopenharmony_ci return -EIO; 30562306a36Sopenharmony_ci if (alx_read_macaddr(hw, addr)) 30662306a36Sopenharmony_ci return 0; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci /* try to load from flash/eeprom (if present) */ 30962306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_EFLD); 31062306a36Sopenharmony_ci if (val & (ALX_EFLD_F_EXIST | ALX_EFLD_E_EXIST)) { 31162306a36Sopenharmony_ci if (!alx_wait_reg(hw, ALX_EFLD, 31262306a36Sopenharmony_ci ALX_EFLD_STAT | ALX_EFLD_START, &val)) 31362306a36Sopenharmony_ci return -EIO; 31462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_EFLD, val | ALX_EFLD_START); 31562306a36Sopenharmony_ci if (!alx_wait_reg(hw, ALX_EFLD, ALX_EFLD_START, NULL)) 31662306a36Sopenharmony_ci return -EIO; 31762306a36Sopenharmony_ci if (alx_read_macaddr(hw, addr)) 31862306a36Sopenharmony_ci return 0; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return -EIO; 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_civoid alx_set_macaddr(struct alx_hw *hw, const u8 *addr) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci u32 val; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* for example: 00-0B-6A-F6-00-DC * STAD0=6AF600DC, STAD1=000B */ 32962306a36Sopenharmony_ci val = be32_to_cpu(get_unaligned((__be32 *)(addr + 2))); 33062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_STAD0, val); 33162306a36Sopenharmony_ci val = be16_to_cpu(get_unaligned((__be16 *)addr)); 33262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_STAD1, val); 33362306a36Sopenharmony_ci} 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_cistatic void alx_reset_osc(struct alx_hw *hw, u8 rev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci u32 val, val2; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* clear Internal OSC settings, switching OSC by hw itself */ 34062306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MISC3); 34162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC3, 34262306a36Sopenharmony_ci (val & ~ALX_MISC3_25M_BY_SW) | 34362306a36Sopenharmony_ci ALX_MISC3_25M_NOTO_INTNL); 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci /* 25M clk from chipset may be unstable 1s after de-assert of 34662306a36Sopenharmony_ci * PERST, driver need re-calibrate before enter Sleep for WoL 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MISC); 34962306a36Sopenharmony_ci if (rev >= ALX_REV_B0) { 35062306a36Sopenharmony_ci /* restore over current protection def-val, 35162306a36Sopenharmony_ci * this val could be reset by MAC-RST 35262306a36Sopenharmony_ci */ 35362306a36Sopenharmony_ci ALX_SET_FIELD(val, ALX_MISC_PSW_OCP, ALX_MISC_PSW_OCP_DEF); 35462306a36Sopenharmony_ci /* a 0->1 change will update the internal val of osc */ 35562306a36Sopenharmony_ci val &= ~ALX_MISC_INTNLOSC_OPEN; 35662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC, val); 35762306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN); 35862306a36Sopenharmony_ci /* hw will automatically dis OSC after cab. */ 35962306a36Sopenharmony_ci val2 = alx_read_mem32(hw, ALX_MSIC2); 36062306a36Sopenharmony_ci val2 &= ~ALX_MSIC2_CALB_START; 36162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MSIC2, val2); 36262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MSIC2, val2 | ALX_MSIC2_CALB_START); 36362306a36Sopenharmony_ci } else { 36462306a36Sopenharmony_ci val &= ~ALX_MISC_INTNLOSC_OPEN; 36562306a36Sopenharmony_ci /* disable isolate for rev A devices */ 36662306a36Sopenharmony_ci if (alx_is_rev_a(rev)) 36762306a36Sopenharmony_ci val &= ~ALX_MISC_ISO_EN; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC, val | ALX_MISC_INTNLOSC_OPEN); 37062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC, val); 37162306a36Sopenharmony_ci } 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci udelay(20); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic int alx_stop_mac(struct alx_hw *hw) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci u32 rxq, txq, val; 37962306a36Sopenharmony_ci u16 i; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci rxq = alx_read_mem32(hw, ALX_RXQ0); 38262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RXQ0, rxq & ~ALX_RXQ0_EN); 38362306a36Sopenharmony_ci txq = alx_read_mem32(hw, ALX_TXQ0); 38462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TXQ0, txq & ~ALX_TXQ0_EN); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci udelay(40); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci hw->rx_ctrl &= ~(ALX_MAC_CTRL_RX_EN | ALX_MAC_CTRL_TX_EN); 38962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) { 39262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MAC_STS); 39362306a36Sopenharmony_ci if (!(val & ALX_MAC_STS_IDLE)) 39462306a36Sopenharmony_ci return 0; 39562306a36Sopenharmony_ci udelay(10); 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return -ETIMEDOUT; 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ciint alx_reset_mac(struct alx_hw *hw) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci u32 val, pmctrl; 40462306a36Sopenharmony_ci int i, ret; 40562306a36Sopenharmony_ci u8 rev; 40662306a36Sopenharmony_ci bool a_cr; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci pmctrl = 0; 40962306a36Sopenharmony_ci rev = alx_hw_revision(hw); 41062306a36Sopenharmony_ci a_cr = alx_is_rev_a(rev) && alx_hw_with_cr(hw); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* disable all interrupts, RXQ/TXQ */ 41362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MSIX_MASK, 0xFFFFFFFF); 41462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_IMR, 0); 41562306a36Sopenharmony_ci alx_write_mem32(hw, ALX_ISR, ALX_ISR_DIS); 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci ret = alx_stop_mac(hw); 41862306a36Sopenharmony_ci if (ret) 41962306a36Sopenharmony_ci return ret; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* mac reset workaroud */ 42262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RFD_PIDX, 1); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci /* dis l0s/l1 before mac reset */ 42562306a36Sopenharmony_ci if (a_cr) { 42662306a36Sopenharmony_ci pmctrl = alx_read_mem32(hw, ALX_PMCTRL); 42762306a36Sopenharmony_ci if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN)) 42862306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PMCTRL, 42962306a36Sopenharmony_ci pmctrl & ~(ALX_PMCTRL_L1_EN | 43062306a36Sopenharmony_ci ALX_PMCTRL_L0S_EN)); 43162306a36Sopenharmony_ci } 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci /* reset whole mac safely */ 43462306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MASTER); 43562306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MASTER, 43662306a36Sopenharmony_ci val | ALX_MASTER_DMA_MAC_RST | ALX_MASTER_OOB_DIS); 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci /* make sure it's real idle */ 43962306a36Sopenharmony_ci udelay(10); 44062306a36Sopenharmony_ci for (i = 0; i < ALX_DMA_MAC_RST_TO; i++) { 44162306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_RFD_PIDX); 44262306a36Sopenharmony_ci if (val == 0) 44362306a36Sopenharmony_ci break; 44462306a36Sopenharmony_ci udelay(10); 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci for (; i < ALX_DMA_MAC_RST_TO; i++) { 44762306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MASTER); 44862306a36Sopenharmony_ci if ((val & ALX_MASTER_DMA_MAC_RST) == 0) 44962306a36Sopenharmony_ci break; 45062306a36Sopenharmony_ci udelay(10); 45162306a36Sopenharmony_ci } 45262306a36Sopenharmony_ci if (i == ALX_DMA_MAC_RST_TO) 45362306a36Sopenharmony_ci return -EIO; 45462306a36Sopenharmony_ci udelay(10); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci if (a_cr) { 45762306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MASTER, val | ALX_MASTER_PCLKSEL_SRDS); 45862306a36Sopenharmony_ci /* restore l0s / l1 */ 45962306a36Sopenharmony_ci if (pmctrl & (ALX_PMCTRL_L1_EN | ALX_PMCTRL_L0S_EN)) 46062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PMCTRL, pmctrl); 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci alx_reset_osc(hw, rev); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci /* clear Internal OSC settings, switching OSC by hw itself, 46662306a36Sopenharmony_ci * disable isolate for rev A devices 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MISC3); 46962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC3, 47062306a36Sopenharmony_ci (val & ~ALX_MISC3_25M_BY_SW) | 47162306a36Sopenharmony_ci ALX_MISC3_25M_NOTO_INTNL); 47262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MISC); 47362306a36Sopenharmony_ci val &= ~ALX_MISC_INTNLOSC_OPEN; 47462306a36Sopenharmony_ci if (alx_is_rev_a(rev)) 47562306a36Sopenharmony_ci val &= ~ALX_MISC_ISO_EN; 47662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MISC, val); 47762306a36Sopenharmony_ci udelay(20); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci /* driver control speed/duplex, hash-alg */ 48062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_SERDES); 48362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_SERDES, 48462306a36Sopenharmony_ci val | ALX_SERDES_MACCLK_SLWDWN | 48562306a36Sopenharmony_ci ALX_SERDES_PHYCLK_SLWDWN); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci return 0; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_civoid alx_reset_phy(struct alx_hw *hw) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci int i; 49362306a36Sopenharmony_ci u32 val; 49462306a36Sopenharmony_ci u16 phy_val; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* (DSP)reset PHY core */ 49762306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_PHY_CTRL); 49862306a36Sopenharmony_ci val &= ~(ALX_PHY_CTRL_DSPRST_OUT | ALX_PHY_CTRL_IDDQ | 49962306a36Sopenharmony_ci ALX_PHY_CTRL_GATE_25M | ALX_PHY_CTRL_POWER_DOWN | 50062306a36Sopenharmony_ci ALX_PHY_CTRL_CLS); 50162306a36Sopenharmony_ci val |= ALX_PHY_CTRL_RST_ANALOG; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci val |= (ALX_PHY_CTRL_HIB_PULSE | ALX_PHY_CTRL_HIB_EN); 50462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PHY_CTRL, val); 50562306a36Sopenharmony_ci udelay(10); 50662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PHY_CTRL, val | ALX_PHY_CTRL_DSPRST_OUT); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci for (i = 0; i < ALX_PHY_CTRL_DSPRST_TO; i++) 50962306a36Sopenharmony_ci udelay(10); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* phy power saving & hib */ 51262306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_LEGCYPS, ALX_LEGCYPS_DEF); 51362306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_SYSMODCTRL, 51462306a36Sopenharmony_ci ALX_SYSMODCTRL_IECHOADJ_DEF); 51562306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_VDRVBIAS, 51662306a36Sopenharmony_ci ALX_VDRVBIAS_DEF); 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci /* EEE advertisement */ 51962306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_LPI_CTRL); 52062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_LPI_CTRL, val & ~ALX_LPI_CTRL_EN); 52162306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_LOCAL_EEEADV, 0); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci /* phy power saving */ 52462306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_TST10BTCFG, ALX_TST10BTCFG_DEF); 52562306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_SRDSYSMOD, ALX_SRDSYSMOD_DEF); 52662306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_TST100BTCFG, ALX_TST100BTCFG_DEF); 52762306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_ANACTRL, ALX_ANACTRL_DEF); 52862306a36Sopenharmony_ci alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val); 52962306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, 53062306a36Sopenharmony_ci phy_val & ~ALX_GREENCFG2_GATE_DFSE_EN); 53162306a36Sopenharmony_ci /* rtl8139c, 120m issue */ 53262306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_NLP78, 53362306a36Sopenharmony_ci ALX_MIIEXT_NLP78_120M_DEF); 53462306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_S3DIG10, 53562306a36Sopenharmony_ci ALX_MIIEXT_S3DIG10_DEF); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci if (hw->lnk_patch) { 53862306a36Sopenharmony_ci /* Turn off half amplitude */ 53962306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3, 54062306a36Sopenharmony_ci &phy_val); 54162306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL3, 54262306a36Sopenharmony_ci phy_val | ALX_CLDCTRL3_BP_CABLE1TH_DET_GT); 54362306a36Sopenharmony_ci /* Turn off Green feature */ 54462306a36Sopenharmony_ci alx_read_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, &phy_val); 54562306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_GREENCFG2, 54662306a36Sopenharmony_ci phy_val | ALX_GREENCFG2_BP_GREEN); 54762306a36Sopenharmony_ci /* Turn off half Bias */ 54862306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5, 54962306a36Sopenharmony_ci &phy_val); 55062306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL5, 55162306a36Sopenharmony_ci phy_val | ALX_CLDCTRL5_BP_VD_HLFBIAS); 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci /* set phy interrupt mask */ 55562306a36Sopenharmony_ci alx_write_phy_reg(hw, ALX_MII_IER, ALX_IER_LINK_UP | ALX_IER_LINK_DOWN); 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci#define ALX_PCI_CMD (PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO) 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_civoid alx_reset_pcie(struct alx_hw *hw) 56162306a36Sopenharmony_ci{ 56262306a36Sopenharmony_ci u8 rev = alx_hw_revision(hw); 56362306a36Sopenharmony_ci u32 val; 56462306a36Sopenharmony_ci u16 val16; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ 56762306a36Sopenharmony_ci pci_read_config_word(hw->pdev, PCI_COMMAND, &val16); 56862306a36Sopenharmony_ci if (!(val16 & ALX_PCI_CMD) || (val16 & PCI_COMMAND_INTX_DISABLE)) { 56962306a36Sopenharmony_ci val16 = (val16 | ALX_PCI_CMD) & ~PCI_COMMAND_INTX_DISABLE; 57062306a36Sopenharmony_ci pci_write_config_word(hw->pdev, PCI_COMMAND, val16); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci /* clear WoL setting/status */ 57462306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_WOL0); 57562306a36Sopenharmony_ci alx_write_mem32(hw, ALX_WOL0, 0); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_PDLL_TRNS1); 57862306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PDLL_TRNS1, val & ~ALX_PDLL_TRNS1_D3PLLOFF_EN); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci /* mask some pcie error bits */ 58162306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_UE_SVRT); 58262306a36Sopenharmony_ci val &= ~(ALX_UE_SVRT_DLPROTERR | ALX_UE_SVRT_FCPROTERR); 58362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_UE_SVRT, val); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* wol 25M & pclk */ 58662306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MASTER); 58762306a36Sopenharmony_ci if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) { 58862306a36Sopenharmony_ci if ((val & ALX_MASTER_WAKEN_25M) == 0 || 58962306a36Sopenharmony_ci (val & ALX_MASTER_PCLKSEL_SRDS) == 0) 59062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MASTER, 59162306a36Sopenharmony_ci val | ALX_MASTER_PCLKSEL_SRDS | 59262306a36Sopenharmony_ci ALX_MASTER_WAKEN_25M); 59362306a36Sopenharmony_ci } else { 59462306a36Sopenharmony_ci if ((val & ALX_MASTER_WAKEN_25M) == 0 || 59562306a36Sopenharmony_ci (val & ALX_MASTER_PCLKSEL_SRDS) != 0) 59662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MASTER, 59762306a36Sopenharmony_ci (val & ~ALX_MASTER_PCLKSEL_SRDS) | 59862306a36Sopenharmony_ci ALX_MASTER_WAKEN_25M); 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* ASPM setting */ 60262306a36Sopenharmony_ci alx_enable_aspm(hw, true, true); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci udelay(10); 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_civoid alx_start_mac(struct alx_hw *hw) 60862306a36Sopenharmony_ci{ 60962306a36Sopenharmony_ci u32 mac, txq, rxq; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci rxq = alx_read_mem32(hw, ALX_RXQ0); 61262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RXQ0, rxq | ALX_RXQ0_EN); 61362306a36Sopenharmony_ci txq = alx_read_mem32(hw, ALX_TXQ0); 61462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TXQ0, txq | ALX_TXQ0_EN); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci mac = hw->rx_ctrl; 61762306a36Sopenharmony_ci if (hw->duplex == DUPLEX_FULL) 61862306a36Sopenharmony_ci mac |= ALX_MAC_CTRL_FULLD; 61962306a36Sopenharmony_ci else 62062306a36Sopenharmony_ci mac &= ~ALX_MAC_CTRL_FULLD; 62162306a36Sopenharmony_ci ALX_SET_FIELD(mac, ALX_MAC_CTRL_SPEED, 62262306a36Sopenharmony_ci hw->link_speed == SPEED_1000 ? ALX_MAC_CTRL_SPEED_1000 : 62362306a36Sopenharmony_ci ALX_MAC_CTRL_SPEED_10_100); 62462306a36Sopenharmony_ci mac |= ALX_MAC_CTRL_TX_EN | ALX_MAC_CTRL_RX_EN; 62562306a36Sopenharmony_ci hw->rx_ctrl = mac; 62662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MAC_CTRL, mac); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_civoid alx_cfg_mac_flowcontrol(struct alx_hw *hw, u8 fc) 63062306a36Sopenharmony_ci{ 63162306a36Sopenharmony_ci if (fc & ALX_FC_RX) 63262306a36Sopenharmony_ci hw->rx_ctrl |= ALX_MAC_CTRL_RXFC_EN; 63362306a36Sopenharmony_ci else 63462306a36Sopenharmony_ci hw->rx_ctrl &= ~ALX_MAC_CTRL_RXFC_EN; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (fc & ALX_FC_TX) 63762306a36Sopenharmony_ci hw->rx_ctrl |= ALX_MAC_CTRL_TXFC_EN; 63862306a36Sopenharmony_ci else 63962306a36Sopenharmony_ci hw->rx_ctrl &= ~ALX_MAC_CTRL_TXFC_EN; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MAC_CTRL, hw->rx_ctrl); 64262306a36Sopenharmony_ci} 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_civoid alx_enable_aspm(struct alx_hw *hw, bool l0s_en, bool l1_en) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci u32 pmctrl; 64762306a36Sopenharmony_ci u8 rev = alx_hw_revision(hw); 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci pmctrl = alx_read_mem32(hw, ALX_PMCTRL); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci ALX_SET_FIELD(pmctrl, ALX_PMCTRL_LCKDET_TIMER, 65262306a36Sopenharmony_ci ALX_PMCTRL_LCKDET_TIMER_DEF); 65362306a36Sopenharmony_ci pmctrl |= ALX_PMCTRL_RCVR_WT_1US | 65462306a36Sopenharmony_ci ALX_PMCTRL_L1_CLKSW_EN | 65562306a36Sopenharmony_ci ALX_PMCTRL_L1_SRDSRX_PWD; 65662306a36Sopenharmony_ci ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1REQ_TO, ALX_PMCTRL_L1REG_TO_DEF); 65762306a36Sopenharmony_ci ALX_SET_FIELD(pmctrl, ALX_PMCTRL_L1_TIMER, ALX_PMCTRL_L1_TIMER_16US); 65862306a36Sopenharmony_ci pmctrl &= ~(ALX_PMCTRL_L1_SRDS_EN | 65962306a36Sopenharmony_ci ALX_PMCTRL_L1_SRDSPLL_EN | 66062306a36Sopenharmony_ci ALX_PMCTRL_L1_BUFSRX_EN | 66162306a36Sopenharmony_ci ALX_PMCTRL_SADLY_EN | 66262306a36Sopenharmony_ci ALX_PMCTRL_HOTRST_WTEN| 66362306a36Sopenharmony_ci ALX_PMCTRL_L0S_EN | 66462306a36Sopenharmony_ci ALX_PMCTRL_L1_EN | 66562306a36Sopenharmony_ci ALX_PMCTRL_ASPM_FCEN | 66662306a36Sopenharmony_ci ALX_PMCTRL_TXL1_AFTER_L0S | 66762306a36Sopenharmony_ci ALX_PMCTRL_RXL1_AFTER_L0S); 66862306a36Sopenharmony_ci if (alx_is_rev_a(rev) && alx_hw_with_cr(hw)) 66962306a36Sopenharmony_ci pmctrl |= ALX_PMCTRL_L1_SRDS_EN | ALX_PMCTRL_L1_SRDSPLL_EN; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci if (l0s_en) 67262306a36Sopenharmony_ci pmctrl |= (ALX_PMCTRL_L0S_EN | ALX_PMCTRL_ASPM_FCEN); 67362306a36Sopenharmony_ci if (l1_en) 67462306a36Sopenharmony_ci pmctrl |= (ALX_PMCTRL_L1_EN | ALX_PMCTRL_ASPM_FCEN); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_PMCTRL, pmctrl); 67762306a36Sopenharmony_ci} 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_cistatic u32 ethadv_to_hw_cfg(struct alx_hw *hw, u32 ethadv_cfg) 68162306a36Sopenharmony_ci{ 68262306a36Sopenharmony_ci u32 cfg = 0; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_Autoneg) { 68562306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_AUTO; 68662306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_10baseT_Half) 68762306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_10; 68862306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_10baseT_Full) 68962306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX; 69062306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_100baseT_Half) 69162306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_100; 69262306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_100baseT_Full) 69362306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; 69462306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_1000baseT_Half) 69562306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_1000; 69662306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_1000baseT_Full) 69762306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; 69862306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_Pause) 69962306a36Sopenharmony_ci cfg |= ADVERTISE_PAUSE_CAP; 70062306a36Sopenharmony_ci if (ethadv_cfg & ADVERTISED_Asym_Pause) 70162306a36Sopenharmony_ci cfg |= ADVERTISE_PAUSE_ASYM; 70262306a36Sopenharmony_ci } else { 70362306a36Sopenharmony_ci switch (ethadv_cfg) { 70462306a36Sopenharmony_ci case ADVERTISED_10baseT_Half: 70562306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_10; 70662306a36Sopenharmony_ci break; 70762306a36Sopenharmony_ci case ADVERTISED_100baseT_Half: 70862306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_100; 70962306a36Sopenharmony_ci break; 71062306a36Sopenharmony_ci case ADVERTISED_10baseT_Full: 71162306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_10 | ALX_DRV_PHY_DUPLEX; 71262306a36Sopenharmony_ci break; 71362306a36Sopenharmony_ci case ADVERTISED_100baseT_Full: 71462306a36Sopenharmony_ci cfg |= ALX_DRV_PHY_100 | ALX_DRV_PHY_DUPLEX; 71562306a36Sopenharmony_ci break; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci return cfg; 72062306a36Sopenharmony_ci} 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ciint alx_setup_speed_duplex(struct alx_hw *hw, u32 ethadv, u8 flowctrl) 72362306a36Sopenharmony_ci{ 72462306a36Sopenharmony_ci u16 adv, giga, cr; 72562306a36Sopenharmony_ci u32 val; 72662306a36Sopenharmony_ci int err = 0; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, 0); 72962306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_DRV); 73062306a36Sopenharmony_ci ALX_SET_FIELD(val, ALX_DRV_PHY, 0); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci if (ethadv & ADVERTISED_Autoneg) { 73362306a36Sopenharmony_ci adv = ADVERTISE_CSMA; 73462306a36Sopenharmony_ci adv |= ethtool_adv_to_mii_adv_t(ethadv); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (flowctrl & ALX_FC_ANEG) { 73762306a36Sopenharmony_ci if (flowctrl & ALX_FC_RX) { 73862306a36Sopenharmony_ci adv |= ADVERTISED_Pause; 73962306a36Sopenharmony_ci if (!(flowctrl & ALX_FC_TX)) 74062306a36Sopenharmony_ci adv |= ADVERTISED_Asym_Pause; 74162306a36Sopenharmony_ci } else if (flowctrl & ALX_FC_TX) { 74262306a36Sopenharmony_ci adv |= ADVERTISED_Asym_Pause; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci giga = 0; 74662306a36Sopenharmony_ci if (alx_hw_giga(hw)) 74762306a36Sopenharmony_ci giga = ethtool_adv_to_mii_ctrl1000_t(ethadv); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci cr = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci if (alx_write_phy_reg(hw, MII_ADVERTISE, adv) || 75262306a36Sopenharmony_ci alx_write_phy_reg(hw, MII_CTRL1000, giga) || 75362306a36Sopenharmony_ci alx_write_phy_reg(hw, MII_BMCR, cr)) 75462306a36Sopenharmony_ci err = -EBUSY; 75562306a36Sopenharmony_ci } else { 75662306a36Sopenharmony_ci cr = BMCR_RESET; 75762306a36Sopenharmony_ci if (ethadv == ADVERTISED_100baseT_Half || 75862306a36Sopenharmony_ci ethadv == ADVERTISED_100baseT_Full) 75962306a36Sopenharmony_ci cr |= BMCR_SPEED100; 76062306a36Sopenharmony_ci if (ethadv == ADVERTISED_10baseT_Full || 76162306a36Sopenharmony_ci ethadv == ADVERTISED_100baseT_Full) 76262306a36Sopenharmony_ci cr |= BMCR_FULLDPLX; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci err = alx_write_phy_reg(hw, MII_BMCR, cr); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci if (!err) { 76862306a36Sopenharmony_ci alx_write_phy_reg(hw, ALX_MII_DBG_ADDR, ALX_PHY_INITED); 76962306a36Sopenharmony_ci val |= ethadv_to_hw_cfg(hw, ethadv); 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_DRV, val); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci return err; 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_civoid alx_post_phy_link(struct alx_hw *hw) 77962306a36Sopenharmony_ci{ 78062306a36Sopenharmony_ci u16 phy_val, len, agc; 78162306a36Sopenharmony_ci u8 revid = alx_hw_revision(hw); 78262306a36Sopenharmony_ci bool adj_th = revid == ALX_REV_B0; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (revid != ALX_REV_B0 && !alx_is_rev_a(revid)) 78562306a36Sopenharmony_ci return; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci /* 1000BT/AZ, wrong cable length */ 78862306a36Sopenharmony_ci if (hw->link_speed != SPEED_UNKNOWN) { 78962306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_PCS, ALX_MIIEXT_CLDCTRL6, 79062306a36Sopenharmony_ci &phy_val); 79162306a36Sopenharmony_ci len = ALX_GET_FIELD(phy_val, ALX_CLDCTRL6_CAB_LEN); 79262306a36Sopenharmony_ci alx_read_phy_dbg(hw, ALX_MIIDBG_AGC, &phy_val); 79362306a36Sopenharmony_ci agc = ALX_GET_FIELD(phy_val, ALX_AGC_2_VGA); 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci if ((hw->link_speed == SPEED_1000 && 79662306a36Sopenharmony_ci (len > ALX_CLDCTRL6_CAB_LEN_SHORT1G || 79762306a36Sopenharmony_ci (len == 0 && agc > ALX_AGC_LONG1G_LIMT))) || 79862306a36Sopenharmony_ci (hw->link_speed == SPEED_100 && 79962306a36Sopenharmony_ci (len > ALX_CLDCTRL6_CAB_LEN_SHORT100M || 80062306a36Sopenharmony_ci (len == 0 && agc > ALX_AGC_LONG100M_LIMT)))) { 80162306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT, 80262306a36Sopenharmony_ci ALX_AZ_ANADECT_LONG); 80362306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, 80462306a36Sopenharmony_ci &phy_val); 80562306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, 80662306a36Sopenharmony_ci phy_val | ALX_AFE_10BT_100M_TH); 80762306a36Sopenharmony_ci } else { 80862306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_AZ_ANADECT, 80962306a36Sopenharmony_ci ALX_AZ_ANADECT_DEF); 81062306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, 81162306a36Sopenharmony_ci ALX_MIIEXT_AFE, &phy_val); 81262306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, 81362306a36Sopenharmony_ci phy_val & ~ALX_AFE_10BT_100M_TH); 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci /* threshold adjust */ 81762306a36Sopenharmony_ci if (adj_th && hw->lnk_patch) { 81862306a36Sopenharmony_ci if (hw->link_speed == SPEED_100) { 81962306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB, 82062306a36Sopenharmony_ci ALX_MSE16DB_UP); 82162306a36Sopenharmony_ci } else if (hw->link_speed == SPEED_1000) { 82262306a36Sopenharmony_ci /* 82362306a36Sopenharmony_ci * Giga link threshold, raise the tolerance of 82462306a36Sopenharmony_ci * noise 50% 82562306a36Sopenharmony_ci */ 82662306a36Sopenharmony_ci alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, 82762306a36Sopenharmony_ci &phy_val); 82862306a36Sopenharmony_ci ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH, 82962306a36Sopenharmony_ci ALX_MSE20DB_TH_HI); 83062306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, 83162306a36Sopenharmony_ci phy_val); 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci } else { 83562306a36Sopenharmony_ci alx_read_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, 83662306a36Sopenharmony_ci &phy_val); 83762306a36Sopenharmony_ci alx_write_phy_ext(hw, ALX_MIIEXT_ANEG, ALX_MIIEXT_AFE, 83862306a36Sopenharmony_ci phy_val & ~ALX_AFE_10BT_100M_TH); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci if (adj_th && hw->lnk_patch) { 84162306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_MSE16DB, 84262306a36Sopenharmony_ci ALX_MSE16DB_DOWN); 84362306a36Sopenharmony_ci alx_read_phy_dbg(hw, ALX_MIIDBG_MSE20DB, &phy_val); 84462306a36Sopenharmony_ci ALX_SET_FIELD(phy_val, ALX_MSE20DB_TH, 84562306a36Sopenharmony_ci ALX_MSE20DB_TH_DEF); 84662306a36Sopenharmony_ci alx_write_phy_dbg(hw, ALX_MIIDBG_MSE20DB, phy_val); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci } 84962306a36Sopenharmony_ci} 85062306a36Sopenharmony_ci 85162306a36Sopenharmony_cibool alx_phy_configured(struct alx_hw *hw) 85262306a36Sopenharmony_ci{ 85362306a36Sopenharmony_ci u32 cfg, hw_cfg; 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci cfg = ethadv_to_hw_cfg(hw, hw->adv_cfg); 85662306a36Sopenharmony_ci cfg = ALX_GET_FIELD(cfg, ALX_DRV_PHY); 85762306a36Sopenharmony_ci hw_cfg = alx_get_phy_config(hw); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci if (hw_cfg == ALX_DRV_PHY_UNKNOWN) 86062306a36Sopenharmony_ci return false; 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return cfg == hw_cfg; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ciint alx_read_phy_link(struct alx_hw *hw) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci struct pci_dev *pdev = hw->pdev; 86862306a36Sopenharmony_ci u16 bmsr, giga; 86962306a36Sopenharmony_ci int err; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci err = alx_read_phy_reg(hw, MII_BMSR, &bmsr); 87262306a36Sopenharmony_ci if (err) 87362306a36Sopenharmony_ci return err; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci err = alx_read_phy_reg(hw, MII_BMSR, &bmsr); 87662306a36Sopenharmony_ci if (err) 87762306a36Sopenharmony_ci return err; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (!(bmsr & BMSR_LSTATUS)) { 88062306a36Sopenharmony_ci hw->link_speed = SPEED_UNKNOWN; 88162306a36Sopenharmony_ci hw->duplex = DUPLEX_UNKNOWN; 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci } 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* speed/duplex result is saved in PHY Specific Status Register */ 88662306a36Sopenharmony_ci err = alx_read_phy_reg(hw, ALX_MII_GIGA_PSSR, &giga); 88762306a36Sopenharmony_ci if (err) 88862306a36Sopenharmony_ci return err; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci if (!(giga & ALX_GIGA_PSSR_SPD_DPLX_RESOLVED)) 89162306a36Sopenharmony_ci goto wrong_speed; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci switch (giga & ALX_GIGA_PSSR_SPEED) { 89462306a36Sopenharmony_ci case ALX_GIGA_PSSR_1000MBS: 89562306a36Sopenharmony_ci hw->link_speed = SPEED_1000; 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case ALX_GIGA_PSSR_100MBS: 89862306a36Sopenharmony_ci hw->link_speed = SPEED_100; 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci case ALX_GIGA_PSSR_10MBS: 90162306a36Sopenharmony_ci hw->link_speed = SPEED_10; 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci default: 90462306a36Sopenharmony_ci goto wrong_speed; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci hw->duplex = (giga & ALX_GIGA_PSSR_DPLX) ? DUPLEX_FULL : DUPLEX_HALF; 90862306a36Sopenharmony_ci return 0; 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ciwrong_speed: 91162306a36Sopenharmony_ci dev_err(&pdev->dev, "invalid PHY speed/duplex: 0x%x\n", giga); 91262306a36Sopenharmony_ci return -EINVAL; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ciint alx_clear_phy_intr(struct alx_hw *hw) 91662306a36Sopenharmony_ci{ 91762306a36Sopenharmony_ci u16 isr; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* clear interrupt status by reading it */ 92062306a36Sopenharmony_ci return alx_read_phy_reg(hw, ALX_MII_ISR, &isr); 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_civoid alx_disable_rss(struct alx_hw *hw) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci u32 ctrl = alx_read_mem32(hw, ALX_RXQ0); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci ctrl &= ~ALX_RXQ0_RSS_HASH_EN; 92862306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RXQ0, ctrl); 92962306a36Sopenharmony_ci} 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_civoid alx_configure_basic(struct alx_hw *hw) 93262306a36Sopenharmony_ci{ 93362306a36Sopenharmony_ci u32 val, raw_mtu, max_payload; 93462306a36Sopenharmony_ci u16 val16; 93562306a36Sopenharmony_ci u8 chip_rev = alx_hw_revision(hw); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci alx_set_macaddr(hw, hw->mac_addr); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_CLK_GATE, ALX_CLK_GATE_ALL); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci /* idle timeout to switch clk_125M */ 94262306a36Sopenharmony_ci if (chip_rev >= ALX_REV_B0) 94362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_IDLE_DECISN_TIMER, 94462306a36Sopenharmony_ci ALX_IDLE_DECISN_TIMER_DEF); 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_SMB_TIMER, hw->smb_timer * 500UL); 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_MASTER); 94962306a36Sopenharmony_ci val |= ALX_MASTER_IRQMOD2_EN | 95062306a36Sopenharmony_ci ALX_MASTER_IRQMOD1_EN | 95162306a36Sopenharmony_ci ALX_MASTER_SYSALVTIMER_EN; 95262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MASTER, val); 95362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_IRQ_MODU_TIMER, 95462306a36Sopenharmony_ci (hw->imt >> 1) << ALX_IRQ_MODU_TIMER1_SHIFT); 95562306a36Sopenharmony_ci /* intr re-trig timeout */ 95662306a36Sopenharmony_ci alx_write_mem32(hw, ALX_INT_RETRIG, ALX_INT_RETRIG_TO); 95762306a36Sopenharmony_ci /* tpd threshold to trig int */ 95862306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TINT_TPD_THRSHLD, hw->ith_tpd); 95962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TINT_TIMER, hw->imt); 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci raw_mtu = ALX_RAW_MTU(hw->mtu); 96262306a36Sopenharmony_ci alx_write_mem32(hw, ALX_MTU, raw_mtu); 96362306a36Sopenharmony_ci if (raw_mtu > (ALX_MTU_JUMBO_TH + ETH_FCS_LEN + VLAN_HLEN)) 96462306a36Sopenharmony_ci hw->rx_ctrl &= ~ALX_MAC_CTRL_FAST_PAUSE; 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci if (raw_mtu < ALX_TXQ1_JUMBO_TSO_TH) 96762306a36Sopenharmony_ci val = (raw_mtu + 7) >> 3; 96862306a36Sopenharmony_ci else 96962306a36Sopenharmony_ci val = ALX_TXQ1_JUMBO_TSO_TH >> 3; 97062306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TXQ1, val | ALX_TXQ1_ERRLGPKT_DROP_EN); 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_ci max_payload = pcie_get_readrq(hw->pdev) >> 8; 97362306a36Sopenharmony_ci /* 97462306a36Sopenharmony_ci * if BIOS had changed the default dma read max length, 97562306a36Sopenharmony_ci * restore it to default value 97662306a36Sopenharmony_ci */ 97762306a36Sopenharmony_ci if (max_payload < ALX_DEV_CTRL_MAXRRS_MIN) 97862306a36Sopenharmony_ci pcie_set_readrq(hw->pdev, 128 << ALX_DEV_CTRL_MAXRRS_MIN); 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_TXQ0_TPD_BURSTPREF_SHIFT | 98162306a36Sopenharmony_ci ALX_TXQ0_MODE_ENHANCE | ALX_TXQ0_LSO_8023_EN | 98262306a36Sopenharmony_ci ALX_TXQ0_SUPT_IPOPT | 98362306a36Sopenharmony_ci ALX_TXQ_TXF_BURST_PREF_DEF << ALX_TXQ0_TXF_BURST_PREF_SHIFT; 98462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_TXQ0, val); 98562306a36Sopenharmony_ci val = ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q1_NUMPREF_SHIFT | 98662306a36Sopenharmony_ci ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q2_NUMPREF_SHIFT | 98762306a36Sopenharmony_ci ALX_TXQ_TPD_BURSTPREF_DEF << ALX_HQTPD_Q3_NUMPREF_SHIFT | 98862306a36Sopenharmony_ci ALX_HQTPD_BURST_EN; 98962306a36Sopenharmony_ci alx_write_mem32(hw, ALX_HQTPD, val); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci /* rxq, flow control */ 99262306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_SRAM5); 99362306a36Sopenharmony_ci val = ALX_GET_FIELD(val, ALX_SRAM_RXF_LEN) << 3; 99462306a36Sopenharmony_ci if (val > ALX_SRAM_RXF_LEN_8K) { 99562306a36Sopenharmony_ci val16 = ALX_MTU_STD_ALGN >> 3; 99662306a36Sopenharmony_ci val = (val - ALX_RXQ2_RXF_FLOW_CTRL_RSVD) >> 3; 99762306a36Sopenharmony_ci } else { 99862306a36Sopenharmony_ci val16 = ALX_MTU_STD_ALGN >> 3; 99962306a36Sopenharmony_ci val = (val - ALX_MTU_STD_ALGN) >> 3; 100062306a36Sopenharmony_ci } 100162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RXQ2, 100262306a36Sopenharmony_ci val16 << ALX_RXQ2_RXF_XOFF_THRESH_SHIFT | 100362306a36Sopenharmony_ci val << ALX_RXQ2_RXF_XON_THRESH_SHIFT); 100462306a36Sopenharmony_ci val = ALX_RXQ0_NUM_RFD_PREF_DEF << ALX_RXQ0_NUM_RFD_PREF_SHIFT | 100562306a36Sopenharmony_ci ALX_RXQ0_RSS_MODE_DIS << ALX_RXQ0_RSS_MODE_SHIFT | 100662306a36Sopenharmony_ci ALX_RXQ0_IDT_TBL_SIZE_DEF << ALX_RXQ0_IDT_TBL_SIZE_SHIFT | 100762306a36Sopenharmony_ci ALX_RXQ0_RSS_HSTYP_ALL | ALX_RXQ0_RSS_HASH_EN | 100862306a36Sopenharmony_ci ALX_RXQ0_IPV6_PARSE_EN; 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci if (alx_hw_giga(hw)) 101162306a36Sopenharmony_ci ALX_SET_FIELD(val, ALX_RXQ0_ASPM_THRESH, 101262306a36Sopenharmony_ci ALX_RXQ0_ASPM_THRESH_100M); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci alx_write_mem32(hw, ALX_RXQ0, val); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci val = alx_read_mem32(hw, ALX_DMA); 101762306a36Sopenharmony_ci val = ALX_DMA_RORDER_MODE_OUT << ALX_DMA_RORDER_MODE_SHIFT | 101862306a36Sopenharmony_ci ALX_DMA_RREQ_PRI_DATA | 101962306a36Sopenharmony_ci max_payload << ALX_DMA_RREQ_BLEN_SHIFT | 102062306a36Sopenharmony_ci ALX_DMA_WDLY_CNT_DEF << ALX_DMA_WDLY_CNT_SHIFT | 102162306a36Sopenharmony_ci ALX_DMA_RDLY_CNT_DEF << ALX_DMA_RDLY_CNT_SHIFT | 102262306a36Sopenharmony_ci (hw->dma_chnl - 1) << ALX_DMA_RCHNL_SEL_SHIFT; 102362306a36Sopenharmony_ci alx_write_mem32(hw, ALX_DMA, val); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* default multi-tx-q weights */ 102662306a36Sopenharmony_ci val = ALX_WRR_PRI_RESTRICT_NONE << ALX_WRR_PRI_SHIFT | 102762306a36Sopenharmony_ci 4 << ALX_WRR_PRI0_SHIFT | 102862306a36Sopenharmony_ci 4 << ALX_WRR_PRI1_SHIFT | 102962306a36Sopenharmony_ci 4 << ALX_WRR_PRI2_SHIFT | 103062306a36Sopenharmony_ci 4 << ALX_WRR_PRI3_SHIFT; 103162306a36Sopenharmony_ci alx_write_mem32(hw, ALX_WRR, val); 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_civoid alx_mask_msix(struct alx_hw *hw, int index, bool mask) 103562306a36Sopenharmony_ci{ 103662306a36Sopenharmony_ci u32 reg, val; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci reg = ALX_MSIX_ENTRY_BASE + index * PCI_MSIX_ENTRY_SIZE + 103962306a36Sopenharmony_ci PCI_MSIX_ENTRY_VECTOR_CTRL; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci val = mask ? PCI_MSIX_ENTRY_CTRL_MASKBIT : 0; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci alx_write_mem32(hw, reg, val); 104462306a36Sopenharmony_ci alx_post_write(hw); 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_cibool alx_get_phy_info(struct alx_hw *hw) 104962306a36Sopenharmony_ci{ 105062306a36Sopenharmony_ci u16 devs1, devs2; 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (alx_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id[0]) || 105362306a36Sopenharmony_ci alx_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id[1])) 105462306a36Sopenharmony_ci return false; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci /* since we haven't PMA/PMD status2 register, we can't 105762306a36Sopenharmony_ci * use mdio45_probe function for prtad and mmds. 105862306a36Sopenharmony_ci * use fixed MMD3 to get mmds. 105962306a36Sopenharmony_ci */ 106062306a36Sopenharmony_ci if (alx_read_phy_ext(hw, 3, MDIO_DEVS1, &devs1) || 106162306a36Sopenharmony_ci alx_read_phy_ext(hw, 3, MDIO_DEVS2, &devs2)) 106262306a36Sopenharmony_ci return false; 106362306a36Sopenharmony_ci hw->mdio.mmds = devs1 | devs2 << 16; 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_ci return true; 106662306a36Sopenharmony_ci} 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_civoid alx_update_hw_stats(struct alx_hw *hw) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci /* RX stats */ 107162306a36Sopenharmony_ci hw->stats.rx_ok += alx_read_mem32(hw, ALX_MIB_RX_OK); 107262306a36Sopenharmony_ci hw->stats.rx_bcast += alx_read_mem32(hw, ALX_MIB_RX_BCAST); 107362306a36Sopenharmony_ci hw->stats.rx_mcast += alx_read_mem32(hw, ALX_MIB_RX_MCAST); 107462306a36Sopenharmony_ci hw->stats.rx_pause += alx_read_mem32(hw, ALX_MIB_RX_PAUSE); 107562306a36Sopenharmony_ci hw->stats.rx_ctrl += alx_read_mem32(hw, ALX_MIB_RX_CTRL); 107662306a36Sopenharmony_ci hw->stats.rx_fcs_err += alx_read_mem32(hw, ALX_MIB_RX_FCS_ERR); 107762306a36Sopenharmony_ci hw->stats.rx_len_err += alx_read_mem32(hw, ALX_MIB_RX_LEN_ERR); 107862306a36Sopenharmony_ci hw->stats.rx_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BYTE_CNT); 107962306a36Sopenharmony_ci hw->stats.rx_runt += alx_read_mem32(hw, ALX_MIB_RX_RUNT); 108062306a36Sopenharmony_ci hw->stats.rx_frag += alx_read_mem32(hw, ALX_MIB_RX_FRAG); 108162306a36Sopenharmony_ci hw->stats.rx_sz_64B += alx_read_mem32(hw, ALX_MIB_RX_SZ_64B); 108262306a36Sopenharmony_ci hw->stats.rx_sz_127B += alx_read_mem32(hw, ALX_MIB_RX_SZ_127B); 108362306a36Sopenharmony_ci hw->stats.rx_sz_255B += alx_read_mem32(hw, ALX_MIB_RX_SZ_255B); 108462306a36Sopenharmony_ci hw->stats.rx_sz_511B += alx_read_mem32(hw, ALX_MIB_RX_SZ_511B); 108562306a36Sopenharmony_ci hw->stats.rx_sz_1023B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1023B); 108662306a36Sopenharmony_ci hw->stats.rx_sz_1518B += alx_read_mem32(hw, ALX_MIB_RX_SZ_1518B); 108762306a36Sopenharmony_ci hw->stats.rx_sz_max += alx_read_mem32(hw, ALX_MIB_RX_SZ_MAX); 108862306a36Sopenharmony_ci hw->stats.rx_ov_sz += alx_read_mem32(hw, ALX_MIB_RX_OV_SZ); 108962306a36Sopenharmony_ci hw->stats.rx_ov_rxf += alx_read_mem32(hw, ALX_MIB_RX_OV_RXF); 109062306a36Sopenharmony_ci hw->stats.rx_ov_rrd += alx_read_mem32(hw, ALX_MIB_RX_OV_RRD); 109162306a36Sopenharmony_ci hw->stats.rx_align_err += alx_read_mem32(hw, ALX_MIB_RX_ALIGN_ERR); 109262306a36Sopenharmony_ci hw->stats.rx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_BCCNT); 109362306a36Sopenharmony_ci hw->stats.rx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_RX_MCCNT); 109462306a36Sopenharmony_ci hw->stats.rx_err_addr += alx_read_mem32(hw, ALX_MIB_RX_ERRADDR); 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci /* TX stats */ 109762306a36Sopenharmony_ci hw->stats.tx_ok += alx_read_mem32(hw, ALX_MIB_TX_OK); 109862306a36Sopenharmony_ci hw->stats.tx_bcast += alx_read_mem32(hw, ALX_MIB_TX_BCAST); 109962306a36Sopenharmony_ci hw->stats.tx_mcast += alx_read_mem32(hw, ALX_MIB_TX_MCAST); 110062306a36Sopenharmony_ci hw->stats.tx_pause += alx_read_mem32(hw, ALX_MIB_TX_PAUSE); 110162306a36Sopenharmony_ci hw->stats.tx_exc_defer += alx_read_mem32(hw, ALX_MIB_TX_EXC_DEFER); 110262306a36Sopenharmony_ci hw->stats.tx_ctrl += alx_read_mem32(hw, ALX_MIB_TX_CTRL); 110362306a36Sopenharmony_ci hw->stats.tx_defer += alx_read_mem32(hw, ALX_MIB_TX_DEFER); 110462306a36Sopenharmony_ci hw->stats.tx_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BYTE_CNT); 110562306a36Sopenharmony_ci hw->stats.tx_sz_64B += alx_read_mem32(hw, ALX_MIB_TX_SZ_64B); 110662306a36Sopenharmony_ci hw->stats.tx_sz_127B += alx_read_mem32(hw, ALX_MIB_TX_SZ_127B); 110762306a36Sopenharmony_ci hw->stats.tx_sz_255B += alx_read_mem32(hw, ALX_MIB_TX_SZ_255B); 110862306a36Sopenharmony_ci hw->stats.tx_sz_511B += alx_read_mem32(hw, ALX_MIB_TX_SZ_511B); 110962306a36Sopenharmony_ci hw->stats.tx_sz_1023B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1023B); 111062306a36Sopenharmony_ci hw->stats.tx_sz_1518B += alx_read_mem32(hw, ALX_MIB_TX_SZ_1518B); 111162306a36Sopenharmony_ci hw->stats.tx_sz_max += alx_read_mem32(hw, ALX_MIB_TX_SZ_MAX); 111262306a36Sopenharmony_ci hw->stats.tx_single_col += alx_read_mem32(hw, ALX_MIB_TX_SINGLE_COL); 111362306a36Sopenharmony_ci hw->stats.tx_multi_col += alx_read_mem32(hw, ALX_MIB_TX_MULTI_COL); 111462306a36Sopenharmony_ci hw->stats.tx_late_col += alx_read_mem32(hw, ALX_MIB_TX_LATE_COL); 111562306a36Sopenharmony_ci hw->stats.tx_abort_col += alx_read_mem32(hw, ALX_MIB_TX_ABORT_COL); 111662306a36Sopenharmony_ci hw->stats.tx_underrun += alx_read_mem32(hw, ALX_MIB_TX_UNDERRUN); 111762306a36Sopenharmony_ci hw->stats.tx_trd_eop += alx_read_mem32(hw, ALX_MIB_TX_TRD_EOP); 111862306a36Sopenharmony_ci hw->stats.tx_len_err += alx_read_mem32(hw, ALX_MIB_TX_LEN_ERR); 111962306a36Sopenharmony_ci hw->stats.tx_trunc += alx_read_mem32(hw, ALX_MIB_TX_TRUNC); 112062306a36Sopenharmony_ci hw->stats.tx_bc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_BCCNT); 112162306a36Sopenharmony_ci hw->stats.tx_mc_byte_cnt += alx_read_mem32(hw, ALX_MIB_TX_MCCNT); 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci hw->stats.update += alx_read_mem32(hw, ALX_MIB_UPDATE); 112462306a36Sopenharmony_ci} 1125