11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
22b133ad6SJeff Kirsher /*
32b133ad6SJeff Kirsher * Copyright(c) 2007 Atheros Corporation. All rights reserved.
42b133ad6SJeff Kirsher *
52b133ad6SJeff Kirsher * Derived from Intel e1000 driver
62b133ad6SJeff Kirsher * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
72b133ad6SJeff Kirsher */
82b133ad6SJeff Kirsher #include <linux/pci.h>
92b133ad6SJeff Kirsher #include <linux/delay.h>
102b133ad6SJeff Kirsher #include <linux/mii.h>
112b133ad6SJeff Kirsher #include <linux/crc32.h>
122b133ad6SJeff Kirsher
132b133ad6SJeff Kirsher #include "atl1c.h"
142b133ad6SJeff Kirsher
152b133ad6SJeff Kirsher /*
162b133ad6SJeff Kirsher * check_eeprom_exist
172b133ad6SJeff Kirsher * return 1 if eeprom exist
182b133ad6SJeff Kirsher */
atl1c_check_eeprom_exist(struct atl1c_hw * hw)192b133ad6SJeff Kirsher int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
202b133ad6SJeff Kirsher {
212b133ad6SJeff Kirsher u32 data;
222b133ad6SJeff Kirsher
232b133ad6SJeff Kirsher AT_READ_REG(hw, REG_TWSI_DEBUG, &data);
242b133ad6SJeff Kirsher if (data & TWSI_DEBUG_DEV_EXIST)
252b133ad6SJeff Kirsher return 1;
262b133ad6SJeff Kirsher
272b133ad6SJeff Kirsher AT_READ_REG(hw, REG_MASTER_CTRL, &data);
282b133ad6SJeff Kirsher if (data & MASTER_CTRL_OTP_SEL)
292b133ad6SJeff Kirsher return 1;
302b133ad6SJeff Kirsher return 0;
312b133ad6SJeff Kirsher }
322b133ad6SJeff Kirsher
atl1c_hw_set_mac_addr(struct atl1c_hw * hw,u8 * mac_addr)33229e6b6eSHuang, Xiong void atl1c_hw_set_mac_addr(struct atl1c_hw *hw, u8 *mac_addr)
342b133ad6SJeff Kirsher {
352b133ad6SJeff Kirsher u32 value;
362b133ad6SJeff Kirsher /*
372b133ad6SJeff Kirsher * 00-0B-6A-F6-00-DC
382b133ad6SJeff Kirsher * 0: 6AF600DC 1: 000B
392b133ad6SJeff Kirsher * low dword
402b133ad6SJeff Kirsher */
41229e6b6eSHuang, Xiong value = mac_addr[2] << 24 |
42229e6b6eSHuang, Xiong mac_addr[3] << 16 |
43229e6b6eSHuang, Xiong mac_addr[4] << 8 |
44229e6b6eSHuang, Xiong mac_addr[5];
452b133ad6SJeff Kirsher AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
462b133ad6SJeff Kirsher /* hight dword */
47229e6b6eSHuang, Xiong value = mac_addr[0] << 8 |
48229e6b6eSHuang, Xiong mac_addr[1];
492b133ad6SJeff Kirsher AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
502b133ad6SJeff Kirsher }
512b133ad6SJeff Kirsher
52229e6b6eSHuang, Xiong /* read mac address from hardware register */
atl1c_read_current_addr(struct atl1c_hw * hw,u8 * eth_addr)53229e6b6eSHuang, Xiong static bool atl1c_read_current_addr(struct atl1c_hw *hw, u8 *eth_addr)
54229e6b6eSHuang, Xiong {
55229e6b6eSHuang, Xiong u32 addr[2];
56229e6b6eSHuang, Xiong
57229e6b6eSHuang, Xiong AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
58229e6b6eSHuang, Xiong AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]);
59229e6b6eSHuang, Xiong
60229e6b6eSHuang, Xiong *(u32 *) ð_addr[2] = htonl(addr[0]);
61229e6b6eSHuang, Xiong *(u16 *) ð_addr[0] = htons((u16)addr[1]);
62229e6b6eSHuang, Xiong
63229e6b6eSHuang, Xiong return is_valid_ether_addr(eth_addr);
64229e6b6eSHuang, Xiong }
65229e6b6eSHuang, Xiong
662b133ad6SJeff Kirsher /*
672b133ad6SJeff Kirsher * atl1c_get_permanent_address
682b133ad6SJeff Kirsher * return 0 if get valid mac address,
692b133ad6SJeff Kirsher */
atl1c_get_permanent_address(struct atl1c_hw * hw)702b133ad6SJeff Kirsher static int atl1c_get_permanent_address(struct atl1c_hw *hw)
712b133ad6SJeff Kirsher {
722b133ad6SJeff Kirsher u32 i;
732b133ad6SJeff Kirsher u32 otp_ctrl_data;
742b133ad6SJeff Kirsher u32 twsi_ctrl_data;
752b133ad6SJeff Kirsher u16 phy_data;
762b133ad6SJeff Kirsher bool raise_vol = false;
772b133ad6SJeff Kirsher
78229e6b6eSHuang, Xiong /* MAC-address from BIOS is the 1st priority */
79229e6b6eSHuang, Xiong if (atl1c_read_current_addr(hw, hw->perm_mac_addr))
80229e6b6eSHuang, Xiong return 0;
81229e6b6eSHuang, Xiong
822b133ad6SJeff Kirsher /* init */
832b133ad6SJeff Kirsher AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
842b133ad6SJeff Kirsher if (atl1c_check_eeprom_exist(hw)) {
852b133ad6SJeff Kirsher if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
862b133ad6SJeff Kirsher /* Enable OTP CLK */
872b133ad6SJeff Kirsher if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
882b133ad6SJeff Kirsher otp_ctrl_data |= OTP_CTRL_CLK_EN;
892b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
902b133ad6SJeff Kirsher AT_WRITE_FLUSH(hw);
912b133ad6SJeff Kirsher msleep(1);
922b133ad6SJeff Kirsher }
932b133ad6SJeff Kirsher }
94229e6b6eSHuang, Xiong /* raise voltage temporally for l2cb */
95229e6b6eSHuang, Xiong if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) {
96229e6b6eSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
97229e6b6eSHuang, Xiong phy_data &= ~ANACTRL_HB_EN;
98229e6b6eSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
99229e6b6eSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
100229e6b6eSHuang, Xiong phy_data |= VOLT_CTRL_SWLOWEST;
101229e6b6eSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
1022b133ad6SJeff Kirsher udelay(20);
1032b133ad6SJeff Kirsher raise_vol = true;
1042b133ad6SJeff Kirsher }
1052b133ad6SJeff Kirsher
1062b133ad6SJeff Kirsher AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
1072b133ad6SJeff Kirsher twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
1082b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
1092b133ad6SJeff Kirsher for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
1102b133ad6SJeff Kirsher msleep(10);
1112b133ad6SJeff Kirsher AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
1122b133ad6SJeff Kirsher if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
1132b133ad6SJeff Kirsher break;
1142b133ad6SJeff Kirsher }
1152b133ad6SJeff Kirsher if (i >= AT_TWSI_EEPROM_TIMEOUT)
1162b133ad6SJeff Kirsher return -1;
1172b133ad6SJeff Kirsher }
1182b133ad6SJeff Kirsher /* Disable OTP_CLK */
1192b133ad6SJeff Kirsher if ((hw->nic_type == athr_l1c || hw->nic_type == athr_l2c)) {
1202b133ad6SJeff Kirsher otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
1212b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
1222b133ad6SJeff Kirsher msleep(1);
1232b133ad6SJeff Kirsher }
1242b133ad6SJeff Kirsher if (raise_vol) {
125229e6b6eSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_ANACTRL, &phy_data);
126229e6b6eSHuang, Xiong phy_data |= ANACTRL_HB_EN;
127229e6b6eSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, phy_data);
128229e6b6eSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
129229e6b6eSHuang, Xiong phy_data &= ~VOLT_CTRL_SWLOWEST;
130229e6b6eSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
1312b133ad6SJeff Kirsher udelay(20);
1322b133ad6SJeff Kirsher }
1332b133ad6SJeff Kirsher
134229e6b6eSHuang, Xiong if (atl1c_read_current_addr(hw, hw->perm_mac_addr))
1352b133ad6SJeff Kirsher return 0;
1362b133ad6SJeff Kirsher
1372b133ad6SJeff Kirsher return -1;
1382b133ad6SJeff Kirsher }
1392b133ad6SJeff Kirsher
atl1c_read_eeprom(struct atl1c_hw * hw,u32 offset,u32 * p_value)1402b133ad6SJeff Kirsher bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
1412b133ad6SJeff Kirsher {
1422b133ad6SJeff Kirsher int i;
14355705639SPeter Senna Tschudin bool ret = false;
1442b133ad6SJeff Kirsher u32 otp_ctrl_data;
1452b133ad6SJeff Kirsher u32 control;
1462b133ad6SJeff Kirsher u32 data;
1472b133ad6SJeff Kirsher
1482b133ad6SJeff Kirsher if (offset & 3)
1492b133ad6SJeff Kirsher return ret; /* address do not align */
1502b133ad6SJeff Kirsher
1512b133ad6SJeff Kirsher AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
1522b133ad6SJeff Kirsher if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
1532b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_OTP_CTRL,
1542b133ad6SJeff Kirsher (otp_ctrl_data | OTP_CTRL_CLK_EN));
1552b133ad6SJeff Kirsher
1562b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
1572b133ad6SJeff Kirsher control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
1582b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);
1592b133ad6SJeff Kirsher
1602b133ad6SJeff Kirsher for (i = 0; i < 10; i++) {
1612b133ad6SJeff Kirsher udelay(100);
1622b133ad6SJeff Kirsher AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
1632b133ad6SJeff Kirsher if (control & EEPROM_CTRL_RW)
1642b133ad6SJeff Kirsher break;
1652b133ad6SJeff Kirsher }
1662b133ad6SJeff Kirsher if (control & EEPROM_CTRL_RW) {
1672b133ad6SJeff Kirsher AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
1682b133ad6SJeff Kirsher AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
1692b133ad6SJeff Kirsher data = data & 0xFFFF;
1702b133ad6SJeff Kirsher *p_value = swab32((data << 16) | (*p_value >> 16));
1712b133ad6SJeff Kirsher ret = true;
1722b133ad6SJeff Kirsher }
1732b133ad6SJeff Kirsher if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
1742b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
1752b133ad6SJeff Kirsher
1762b133ad6SJeff Kirsher return ret;
1772b133ad6SJeff Kirsher }
1782b133ad6SJeff Kirsher /*
1792b133ad6SJeff Kirsher * Reads the adapter's MAC address from the EEPROM
1802b133ad6SJeff Kirsher *
1812b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
1822b133ad6SJeff Kirsher */
atl1c_read_mac_addr(struct atl1c_hw * hw)1832b133ad6SJeff Kirsher int atl1c_read_mac_addr(struct atl1c_hw *hw)
1842b133ad6SJeff Kirsher {
1852b133ad6SJeff Kirsher int err = 0;
1862b133ad6SJeff Kirsher
1872b133ad6SJeff Kirsher err = atl1c_get_permanent_address(hw);
1882b133ad6SJeff Kirsher if (err)
1897efd26d0SJoe Perches eth_random_addr(hw->perm_mac_addr);
1902b133ad6SJeff Kirsher
1912b133ad6SJeff Kirsher memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
1926a214fd4SDanny Kukawka return err;
1932b133ad6SJeff Kirsher }
1942b133ad6SJeff Kirsher
1952b133ad6SJeff Kirsher /*
1962b133ad6SJeff Kirsher * atl1c_hash_mc_addr
1972b133ad6SJeff Kirsher * purpose
1982b133ad6SJeff Kirsher * set hash value for a multicast address
1992b133ad6SJeff Kirsher * hash calcu processing :
2002b133ad6SJeff Kirsher * 1. calcu 32bit CRC for multicast address
2012b133ad6SJeff Kirsher * 2. reverse crc with MSB to LSB
2022b133ad6SJeff Kirsher */
atl1c_hash_mc_addr(struct atl1c_hw * hw,u8 * mc_addr)2032b133ad6SJeff Kirsher u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr)
2042b133ad6SJeff Kirsher {
2052b133ad6SJeff Kirsher u32 crc32;
2062b133ad6SJeff Kirsher u32 value = 0;
2072b133ad6SJeff Kirsher int i;
2082b133ad6SJeff Kirsher
2092b133ad6SJeff Kirsher crc32 = ether_crc_le(6, mc_addr);
2102b133ad6SJeff Kirsher for (i = 0; i < 32; i++)
2112b133ad6SJeff Kirsher value |= (((crc32 >> i) & 1) << (31 - i));
2122b133ad6SJeff Kirsher
2132b133ad6SJeff Kirsher return value;
2142b133ad6SJeff Kirsher }
2152b133ad6SJeff Kirsher
2162b133ad6SJeff Kirsher /*
2172b133ad6SJeff Kirsher * Sets the bit in the multicast table corresponding to the hash value.
2182b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
2192b133ad6SJeff Kirsher * hash_value - Multicast address hash value
2202b133ad6SJeff Kirsher */
atl1c_hash_set(struct atl1c_hw * hw,u32 hash_value)2212b133ad6SJeff Kirsher void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value)
2222b133ad6SJeff Kirsher {
2232b133ad6SJeff Kirsher u32 hash_bit, hash_reg;
2242b133ad6SJeff Kirsher u32 mta;
2252b133ad6SJeff Kirsher
2262b133ad6SJeff Kirsher /*
2272b133ad6SJeff Kirsher * The HASH Table is a register array of 2 32-bit registers.
2282b133ad6SJeff Kirsher * It is treated like an array of 64 bits. We want to set
2292b133ad6SJeff Kirsher * bit BitArray[hash_value]. So we figure out what register
2302b133ad6SJeff Kirsher * the bit is in, read it, OR in the new bit, then write
2312b133ad6SJeff Kirsher * back the new value. The register is determined by the
2322b133ad6SJeff Kirsher * upper bit of the hash value and the bit within that
2332b133ad6SJeff Kirsher * register are determined by the lower 5 bits of the value.
2342b133ad6SJeff Kirsher */
2352b133ad6SJeff Kirsher hash_reg = (hash_value >> 31) & 0x1;
2362b133ad6SJeff Kirsher hash_bit = (hash_value >> 26) & 0x1F;
2372b133ad6SJeff Kirsher
2382b133ad6SJeff Kirsher mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
2392b133ad6SJeff Kirsher
2402b133ad6SJeff Kirsher mta |= (1 << hash_bit);
2412b133ad6SJeff Kirsher
2422b133ad6SJeff Kirsher AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
2432b133ad6SJeff Kirsher }
2442b133ad6SJeff Kirsher
2452b133ad6SJeff Kirsher /*
246929a5e93SHuang, Xiong * wait mdio module be idle
247929a5e93SHuang, Xiong * return true: idle
248929a5e93SHuang, Xiong * false: still busy
249929a5e93SHuang, Xiong */
atl1c_wait_mdio_idle(struct atl1c_hw * hw)250929a5e93SHuang, Xiong bool atl1c_wait_mdio_idle(struct atl1c_hw *hw)
251929a5e93SHuang, Xiong {
252929a5e93SHuang, Xiong u32 val;
253929a5e93SHuang, Xiong int i;
254929a5e93SHuang, Xiong
255929a5e93SHuang, Xiong for (i = 0; i < MDIO_MAX_AC_TO; i++) {
256929a5e93SHuang, Xiong AT_READ_REG(hw, REG_MDIO_CTRL, &val);
257929a5e93SHuang, Xiong if (!(val & (MDIO_CTRL_BUSY | MDIO_CTRL_START)))
258929a5e93SHuang, Xiong break;
259929a5e93SHuang, Xiong udelay(10);
260929a5e93SHuang, Xiong }
261929a5e93SHuang, Xiong
262929a5e93SHuang, Xiong return i != MDIO_MAX_AC_TO;
263929a5e93SHuang, Xiong }
264929a5e93SHuang, Xiong
atl1c_stop_phy_polling(struct atl1c_hw * hw)265929a5e93SHuang, Xiong void atl1c_stop_phy_polling(struct atl1c_hw *hw)
266929a5e93SHuang, Xiong {
267929a5e93SHuang, Xiong if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION))
268929a5e93SHuang, Xiong return;
269929a5e93SHuang, Xiong
270929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_CTRL, 0);
271929a5e93SHuang, Xiong atl1c_wait_mdio_idle(hw);
272929a5e93SHuang, Xiong }
273929a5e93SHuang, Xiong
atl1c_start_phy_polling(struct atl1c_hw * hw,u16 clk_sel)274929a5e93SHuang, Xiong void atl1c_start_phy_polling(struct atl1c_hw *hw, u16 clk_sel)
275929a5e93SHuang, Xiong {
276929a5e93SHuang, Xiong u32 val;
277929a5e93SHuang, Xiong
278929a5e93SHuang, Xiong if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION))
279929a5e93SHuang, Xiong return;
280929a5e93SHuang, Xiong
281929a5e93SHuang, Xiong val = MDIO_CTRL_SPRES_PRMBL |
282929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) |
283929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_REG, 1) |
284929a5e93SHuang, Xiong MDIO_CTRL_START |
285929a5e93SHuang, Xiong MDIO_CTRL_OP_READ;
286929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
287929a5e93SHuang, Xiong atl1c_wait_mdio_idle(hw);
288929a5e93SHuang, Xiong val |= MDIO_CTRL_AP_EN;
289929a5e93SHuang, Xiong val &= ~MDIO_CTRL_START;
290929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
291929a5e93SHuang, Xiong udelay(30);
292929a5e93SHuang, Xiong }
293929a5e93SHuang, Xiong
294929a5e93SHuang, Xiong
295929a5e93SHuang, Xiong /*
296929a5e93SHuang, Xiong * atl1c_read_phy_core
297ad61dd30SStephen Boyd * core function to read register in PHY via MDIO control register.
298929a5e93SHuang, Xiong * ext: extension register (see IEEE 802.3)
299929a5e93SHuang, Xiong * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0)
300929a5e93SHuang, Xiong * reg: reg to read
301929a5e93SHuang, Xiong */
atl1c_read_phy_core(struct atl1c_hw * hw,bool ext,u8 dev,u16 reg,u16 * phy_data)302929a5e93SHuang, Xiong int atl1c_read_phy_core(struct atl1c_hw *hw, bool ext, u8 dev,
303929a5e93SHuang, Xiong u16 reg, u16 *phy_data)
304929a5e93SHuang, Xiong {
305929a5e93SHuang, Xiong u32 val;
306929a5e93SHuang, Xiong u16 clk_sel = MDIO_CTRL_CLK_25_4;
307929a5e93SHuang, Xiong
308929a5e93SHuang, Xiong atl1c_stop_phy_polling(hw);
309929a5e93SHuang, Xiong
310929a5e93SHuang, Xiong *phy_data = 0;
311929a5e93SHuang, Xiong
312929a5e93SHuang, Xiong /* only l2c_b2 & l1d_2 could use slow clock */
313929a5e93SHuang, Xiong if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) &&
314929a5e93SHuang, Xiong hw->hibernate)
315929a5e93SHuang, Xiong clk_sel = MDIO_CTRL_CLK_25_128;
316929a5e93SHuang, Xiong if (ext) {
317929a5e93SHuang, Xiong val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg);
318929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_EXTN, val);
319929a5e93SHuang, Xiong val = MDIO_CTRL_SPRES_PRMBL |
320929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) |
321929a5e93SHuang, Xiong MDIO_CTRL_START |
322929a5e93SHuang, Xiong MDIO_CTRL_MODE_EXT |
323929a5e93SHuang, Xiong MDIO_CTRL_OP_READ;
324929a5e93SHuang, Xiong } else {
325929a5e93SHuang, Xiong val = MDIO_CTRL_SPRES_PRMBL |
326929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) |
327929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_REG, reg) |
328929a5e93SHuang, Xiong MDIO_CTRL_START |
329929a5e93SHuang, Xiong MDIO_CTRL_OP_READ;
330929a5e93SHuang, Xiong }
331929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
332929a5e93SHuang, Xiong
333929a5e93SHuang, Xiong if (!atl1c_wait_mdio_idle(hw))
334929a5e93SHuang, Xiong return -1;
335929a5e93SHuang, Xiong
336929a5e93SHuang, Xiong AT_READ_REG(hw, REG_MDIO_CTRL, &val);
337929a5e93SHuang, Xiong *phy_data = (u16)FIELD_GETX(val, MDIO_CTRL_DATA);
338929a5e93SHuang, Xiong
339929a5e93SHuang, Xiong atl1c_start_phy_polling(hw, clk_sel);
340929a5e93SHuang, Xiong
341929a5e93SHuang, Xiong return 0;
342929a5e93SHuang, Xiong }
343929a5e93SHuang, Xiong
344929a5e93SHuang, Xiong /*
345929a5e93SHuang, Xiong * atl1c_write_phy_core
346dbedd44eSJoe Perches * core function to write to register in PHY via MDIO control register.
347929a5e93SHuang, Xiong * ext: extension register (see IEEE 802.3)
348929a5e93SHuang, Xiong * dev: device address (see IEEE 802.3 DEVAD, PRTAD is fixed to 0)
349929a5e93SHuang, Xiong * reg: reg to write
350929a5e93SHuang, Xiong */
atl1c_write_phy_core(struct atl1c_hw * hw,bool ext,u8 dev,u16 reg,u16 phy_data)351929a5e93SHuang, Xiong int atl1c_write_phy_core(struct atl1c_hw *hw, bool ext, u8 dev,
352929a5e93SHuang, Xiong u16 reg, u16 phy_data)
353929a5e93SHuang, Xiong {
354929a5e93SHuang, Xiong u32 val;
355929a5e93SHuang, Xiong u16 clk_sel = MDIO_CTRL_CLK_25_4;
356929a5e93SHuang, Xiong
357929a5e93SHuang, Xiong atl1c_stop_phy_polling(hw);
358929a5e93SHuang, Xiong
359929a5e93SHuang, Xiong
360929a5e93SHuang, Xiong /* only l2c_b2 & l1d_2 could use slow clock */
361929a5e93SHuang, Xiong if ((hw->nic_type == athr_l2c_b2 || hw->nic_type == athr_l1d_2) &&
362929a5e93SHuang, Xiong hw->hibernate)
363929a5e93SHuang, Xiong clk_sel = MDIO_CTRL_CLK_25_128;
364929a5e93SHuang, Xiong
365929a5e93SHuang, Xiong if (ext) {
366929a5e93SHuang, Xiong val = FIELDX(MDIO_EXTN_DEVAD, dev) | FIELDX(MDIO_EXTN_REG, reg);
367929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_EXTN, val);
368929a5e93SHuang, Xiong val = MDIO_CTRL_SPRES_PRMBL |
369929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) |
370929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_DATA, phy_data) |
371929a5e93SHuang, Xiong MDIO_CTRL_START |
372929a5e93SHuang, Xiong MDIO_CTRL_MODE_EXT;
373929a5e93SHuang, Xiong } else {
374929a5e93SHuang, Xiong val = MDIO_CTRL_SPRES_PRMBL |
375929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_CLK_SEL, clk_sel) |
376929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_DATA, phy_data) |
377929a5e93SHuang, Xiong FIELDX(MDIO_CTRL_REG, reg) |
378929a5e93SHuang, Xiong MDIO_CTRL_START;
379929a5e93SHuang, Xiong }
380929a5e93SHuang, Xiong AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
381929a5e93SHuang, Xiong
382929a5e93SHuang, Xiong if (!atl1c_wait_mdio_idle(hw))
383929a5e93SHuang, Xiong return -1;
384929a5e93SHuang, Xiong
385929a5e93SHuang, Xiong atl1c_start_phy_polling(hw, clk_sel);
386929a5e93SHuang, Xiong
387929a5e93SHuang, Xiong return 0;
388929a5e93SHuang, Xiong }
389929a5e93SHuang, Xiong
390929a5e93SHuang, Xiong /*
3912b133ad6SJeff Kirsher * Reads the value from a PHY register
3922b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
3932b133ad6SJeff Kirsher * reg_addr - address of the PHY register to read
3942b133ad6SJeff Kirsher */
atl1c_read_phy_reg(struct atl1c_hw * hw,u16 reg_addr,u16 * phy_data)3952b133ad6SJeff Kirsher int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data)
3962b133ad6SJeff Kirsher {
397929a5e93SHuang, Xiong return atl1c_read_phy_core(hw, false, 0, reg_addr, phy_data);
3982b133ad6SJeff Kirsher }
3992b133ad6SJeff Kirsher
4002b133ad6SJeff Kirsher /*
4012b133ad6SJeff Kirsher * Writes a value to a PHY register
4022b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
4032b133ad6SJeff Kirsher * reg_addr - address of the PHY register to write
4042b133ad6SJeff Kirsher * data - data to write to the PHY
4052b133ad6SJeff Kirsher */
atl1c_write_phy_reg(struct atl1c_hw * hw,u32 reg_addr,u16 phy_data)4062b133ad6SJeff Kirsher int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data)
4072b133ad6SJeff Kirsher {
408929a5e93SHuang, Xiong return atl1c_write_phy_core(hw, false, 0, reg_addr, phy_data);
4092b133ad6SJeff Kirsher }
4102b133ad6SJeff Kirsher
411929a5e93SHuang, Xiong /* read from PHY extension register */
atl1c_read_phy_ext(struct atl1c_hw * hw,u8 dev_addr,u16 reg_addr,u16 * phy_data)412929a5e93SHuang, Xiong int atl1c_read_phy_ext(struct atl1c_hw *hw, u8 dev_addr,
413929a5e93SHuang, Xiong u16 reg_addr, u16 *phy_data)
414929a5e93SHuang, Xiong {
415929a5e93SHuang, Xiong return atl1c_read_phy_core(hw, true, dev_addr, reg_addr, phy_data);
416929a5e93SHuang, Xiong }
4172b133ad6SJeff Kirsher
418929a5e93SHuang, Xiong /* write to PHY extension register */
atl1c_write_phy_ext(struct atl1c_hw * hw,u8 dev_addr,u16 reg_addr,u16 phy_data)419929a5e93SHuang, Xiong int atl1c_write_phy_ext(struct atl1c_hw *hw, u8 dev_addr,
420929a5e93SHuang, Xiong u16 reg_addr, u16 phy_data)
421929a5e93SHuang, Xiong {
422929a5e93SHuang, Xiong return atl1c_write_phy_core(hw, true, dev_addr, reg_addr, phy_data);
4232b133ad6SJeff Kirsher }
4242b133ad6SJeff Kirsher
atl1c_read_phy_dbg(struct atl1c_hw * hw,u16 reg_addr,u16 * phy_data)425ce5b972bSHuang, Xiong int atl1c_read_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data)
426ce5b972bSHuang, Xiong {
427ce5b972bSHuang, Xiong int err;
428ce5b972bSHuang, Xiong
429ce5b972bSHuang, Xiong err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr);
430ce5b972bSHuang, Xiong if (unlikely(err))
431ce5b972bSHuang, Xiong return err;
432ce5b972bSHuang, Xiong else
433ce5b972bSHuang, Xiong err = atl1c_read_phy_reg(hw, MII_DBG_DATA, phy_data);
434ce5b972bSHuang, Xiong
435ce5b972bSHuang, Xiong return err;
436ce5b972bSHuang, Xiong }
437ce5b972bSHuang, Xiong
atl1c_write_phy_dbg(struct atl1c_hw * hw,u16 reg_addr,u16 phy_data)438ce5b972bSHuang, Xiong int atl1c_write_phy_dbg(struct atl1c_hw *hw, u16 reg_addr, u16 phy_data)
439ce5b972bSHuang, Xiong {
440ce5b972bSHuang, Xiong int err;
441ce5b972bSHuang, Xiong
442ce5b972bSHuang, Xiong err = atl1c_write_phy_reg(hw, MII_DBG_ADDR, reg_addr);
443ce5b972bSHuang, Xiong if (unlikely(err))
444ce5b972bSHuang, Xiong return err;
445ce5b972bSHuang, Xiong else
446ce5b972bSHuang, Xiong err = atl1c_write_phy_reg(hw, MII_DBG_DATA, phy_data);
447ce5b972bSHuang, Xiong
448ce5b972bSHuang, Xiong return err;
449ce5b972bSHuang, Xiong }
450ce5b972bSHuang, Xiong
4512b133ad6SJeff Kirsher /*
4522b133ad6SJeff Kirsher * Configures PHY autoneg and flow control advertisement settings
4532b133ad6SJeff Kirsher *
4542b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
4552b133ad6SJeff Kirsher */
atl1c_phy_setup_adv(struct atl1c_hw * hw)4562b133ad6SJeff Kirsher static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
4572b133ad6SJeff Kirsher {
4582b133ad6SJeff Kirsher u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_ALL;
4592b133ad6SJeff Kirsher u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP &
4602b133ad6SJeff Kirsher ~GIGA_CR_1000T_SPEED_MASK;
4612b133ad6SJeff Kirsher
4622b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_10baseT_Half)
4632b133ad6SJeff Kirsher mii_adv_data |= ADVERTISE_10HALF;
4642b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_10baseT_Full)
4652b133ad6SJeff Kirsher mii_adv_data |= ADVERTISE_10FULL;
4662b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_100baseT_Half)
4672b133ad6SJeff Kirsher mii_adv_data |= ADVERTISE_100HALF;
4682b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_100baseT_Full)
4692b133ad6SJeff Kirsher mii_adv_data |= ADVERTISE_100FULL;
4702b133ad6SJeff Kirsher
4712b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_Autoneg)
4722b133ad6SJeff Kirsher mii_adv_data |= ADVERTISE_10HALF | ADVERTISE_10FULL |
4732b133ad6SJeff Kirsher ADVERTISE_100HALF | ADVERTISE_100FULL;
4742b133ad6SJeff Kirsher
4752b133ad6SJeff Kirsher if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M) {
4762b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
4772b133ad6SJeff Kirsher mii_giga_ctrl_data |= ADVERTISE_1000HALF;
4782b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
4792b133ad6SJeff Kirsher mii_giga_ctrl_data |= ADVERTISE_1000FULL;
4802b133ad6SJeff Kirsher if (hw->autoneg_advertised & ADVERTISED_Autoneg)
4812b133ad6SJeff Kirsher mii_giga_ctrl_data |= ADVERTISE_1000HALF |
4822b133ad6SJeff Kirsher ADVERTISE_1000FULL;
4832b133ad6SJeff Kirsher }
4842b133ad6SJeff Kirsher
4852b133ad6SJeff Kirsher if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 ||
4862b133ad6SJeff Kirsher atl1c_write_phy_reg(hw, MII_CTRL1000, mii_giga_ctrl_data) != 0)
4872b133ad6SJeff Kirsher return -1;
4882b133ad6SJeff Kirsher return 0;
4892b133ad6SJeff Kirsher }
4902b133ad6SJeff Kirsher
atl1c_phy_disable(struct atl1c_hw * hw)4912b133ad6SJeff Kirsher void atl1c_phy_disable(struct atl1c_hw *hw)
4922b133ad6SJeff Kirsher {
493319d013aSHuang, Xiong atl1c_power_saving(hw, 0);
4942b133ad6SJeff Kirsher }
4952b133ad6SJeff Kirsher
4962b133ad6SJeff Kirsher
atl1c_phy_reset(struct atl1c_hw * hw)4972b133ad6SJeff Kirsher int atl1c_phy_reset(struct atl1c_hw *hw)
4982b133ad6SJeff Kirsher {
4992b133ad6SJeff Kirsher struct atl1c_adapter *adapter = hw->adapter;
5002b133ad6SJeff Kirsher struct pci_dev *pdev = adapter->pdev;
5012b133ad6SJeff Kirsher u16 phy_data;
502ce5b972bSHuang, Xiong u32 phy_ctrl_data, lpi_ctrl;
5032b133ad6SJeff Kirsher int err;
5042b133ad6SJeff Kirsher
505ce5b972bSHuang, Xiong /* reset PHY core */
506ce5b972bSHuang, Xiong AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl_data);
507ce5b972bSHuang, Xiong phy_ctrl_data &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_PHY_IDDQ |
508ce5b972bSHuang, Xiong GPHY_CTRL_GATE_25M_EN | GPHY_CTRL_PWDOWN_HW | GPHY_CTRL_CLS);
509ce5b972bSHuang, Xiong phy_ctrl_data |= GPHY_CTRL_SEL_ANA_RST;
510ce5b972bSHuang, Xiong if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE))
511ce5b972bSHuang, Xiong phy_ctrl_data |= (GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE);
512ce5b972bSHuang, Xiong else
513ce5b972bSHuang, Xiong phy_ctrl_data &= ~(GPHY_CTRL_HIB_EN | GPHY_CTRL_HIB_PULSE);
5142b133ad6SJeff Kirsher AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
5152b133ad6SJeff Kirsher AT_WRITE_FLUSH(hw);
516ce5b972bSHuang, Xiong udelay(10);
517ce5b972bSHuang, Xiong AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data | GPHY_CTRL_EXT_RESET);
5182b133ad6SJeff Kirsher AT_WRITE_FLUSH(hw);
519ce5b972bSHuang, Xiong udelay(10 * GPHY_CTRL_EXT_RST_TO); /* delay 800us */
5202b133ad6SJeff Kirsher
521ce5b972bSHuang, Xiong /* switch clock */
5222b133ad6SJeff Kirsher if (hw->nic_type == athr_l2c_b) {
523ce5b972bSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_CFGLPSPD, &phy_data);
524ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_CFGLPSPD,
525ce5b972bSHuang, Xiong phy_data & ~CFGLPSPD_RSTCNT_CLK125SW);
5262b133ad6SJeff Kirsher }
5272b133ad6SJeff Kirsher
528ce5b972bSHuang, Xiong /* tx-half amplitude issue fix */
529ce5b972bSHuang, Xiong if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) {
530ce5b972bSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_CABLE1TH_DET, &phy_data);
531ce5b972bSHuang, Xiong phy_data |= CABLE1TH_DET_EN;
532ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_CABLE1TH_DET, phy_data);
5332b133ad6SJeff Kirsher }
534ce5b972bSHuang, Xiong
535ce5b972bSHuang, Xiong /* clear bit3 of dbgport 3B to lower voltage */
536ce5b972bSHuang, Xiong if (!(hw->ctrl_flags & ATL1C_HIB_DISABLE)) {
537ce5b972bSHuang, Xiong if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2) {
538ce5b972bSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_VOLT_CTRL, &phy_data);
539ce5b972bSHuang, Xiong phy_data &= ~VOLT_CTRL_SWLOWEST;
540ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_VOLT_CTRL, phy_data);
5412b133ad6SJeff Kirsher }
542ce5b972bSHuang, Xiong /* power saving config */
543ce5b972bSHuang, Xiong phy_data =
544ce5b972bSHuang, Xiong hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 ?
545ce5b972bSHuang, Xiong L1D_LEGCYPS_DEF : L1C_LEGCYPS_DEF;
546ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS, phy_data);
547ce5b972bSHuang, Xiong /* hib */
548ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
549ce5b972bSHuang, Xiong SYSMODCTRL_IECHOADJ_DEF);
550ce5b972bSHuang, Xiong } else {
551ce5b972bSHuang, Xiong /* disable pws */
552ce5b972bSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_LEGCYPS, &phy_data);
553ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_LEGCYPS,
554ce5b972bSHuang, Xiong phy_data & ~LEGCYPS_EN);
555ce5b972bSHuang, Xiong /* disable hibernate */
556ce5b972bSHuang, Xiong atl1c_read_phy_dbg(hw, MIIDBG_HIBNEG, &phy_data);
557ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_HIBNEG,
558ce5b972bSHuang, Xiong phy_data & HIBNEG_PSHIB_EN);
5592b133ad6SJeff Kirsher }
560ce5b972bSHuang, Xiong /* disable AZ(EEE) by default */
561ce5b972bSHuang, Xiong if (hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2 ||
562ce5b972bSHuang, Xiong hw->nic_type == athr_l2c_b2) {
563ce5b972bSHuang, Xiong AT_READ_REG(hw, REG_LPI_CTRL, &lpi_ctrl);
564ce5b972bSHuang, Xiong AT_WRITE_REG(hw, REG_LPI_CTRL, lpi_ctrl & ~LPI_CTRL_EN);
565ce5b972bSHuang, Xiong atl1c_write_phy_ext(hw, MIIEXT_ANEG, MIIEXT_LOCAL_EEEADV, 0);
566ce5b972bSHuang, Xiong atl1c_write_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL3,
567ce5b972bSHuang, Xiong L2CB_CLDCTRL3);
568ce5b972bSHuang, Xiong }
569ce5b972bSHuang, Xiong
570ce5b972bSHuang, Xiong /* other debug port to set */
571ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_ANACTRL, ANACTRL_DEF);
572ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_SRDSYSMOD, SRDSYSMOD_DEF);
573ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_TST10BTCFG, TST10BTCFG_DEF);
574ce5b972bSHuang, Xiong /* UNH-IOL test issue, set bit7 */
575ce5b972bSHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_TST100BTCFG,
576ce5b972bSHuang, Xiong TST100BTCFG_DEF | TST100BTCFG_LITCH_EN);
577ce5b972bSHuang, Xiong
578ce5b972bSHuang, Xiong /* set phy interrupt mask */
579ce5b972bSHuang, Xiong phy_data = IER_LINK_UP | IER_LINK_DOWN;
580ce5b972bSHuang, Xiong err = atl1c_write_phy_reg(hw, MII_IER, phy_data);
5812b133ad6SJeff Kirsher if (err) {
5822b133ad6SJeff Kirsher if (netif_msg_hw(adapter))
5832b133ad6SJeff Kirsher dev_err(&pdev->dev,
5842b133ad6SJeff Kirsher "Error enable PHY linkChange Interrupt\n");
5852b133ad6SJeff Kirsher return err;
5862b133ad6SJeff Kirsher }
5872b133ad6SJeff Kirsher return 0;
5882b133ad6SJeff Kirsher }
5892b133ad6SJeff Kirsher
atl1c_phy_init(struct atl1c_hw * hw)5902b133ad6SJeff Kirsher int atl1c_phy_init(struct atl1c_hw *hw)
5912b133ad6SJeff Kirsher {
59264699336SJoe Perches struct atl1c_adapter *adapter = hw->adapter;
5932b133ad6SJeff Kirsher struct pci_dev *pdev = adapter->pdev;
5942b133ad6SJeff Kirsher int ret_val;
5952b133ad6SJeff Kirsher u16 mii_bmcr_data = BMCR_RESET;
5962b133ad6SJeff Kirsher
597*b9d233eaSGatis Peisenieks if (hw->nic_type == athr_mt) {
598*b9d233eaSGatis Peisenieks hw->phy_configured = true;
599*b9d233eaSGatis Peisenieks return 0;
600*b9d233eaSGatis Peisenieks }
601*b9d233eaSGatis Peisenieks
6022b133ad6SJeff Kirsher if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &hw->phy_id1) != 0) ||
6032b133ad6SJeff Kirsher (atl1c_read_phy_reg(hw, MII_PHYSID2, &hw->phy_id2) != 0)) {
6042b133ad6SJeff Kirsher dev_err(&pdev->dev, "Error get phy ID\n");
6052b133ad6SJeff Kirsher return -1;
6062b133ad6SJeff Kirsher }
6072b133ad6SJeff Kirsher switch (hw->media_type) {
6082b133ad6SJeff Kirsher case MEDIA_TYPE_AUTO_SENSOR:
6092b133ad6SJeff Kirsher ret_val = atl1c_phy_setup_adv(hw);
6102b133ad6SJeff Kirsher if (ret_val) {
6112b133ad6SJeff Kirsher if (netif_msg_link(adapter))
6122b133ad6SJeff Kirsher dev_err(&pdev->dev,
6132b133ad6SJeff Kirsher "Error Setting up Auto-Negotiation\n");
6142b133ad6SJeff Kirsher return ret_val;
6152b133ad6SJeff Kirsher }
6162b133ad6SJeff Kirsher mii_bmcr_data |= BMCR_ANENABLE | BMCR_ANRESTART;
6172b133ad6SJeff Kirsher break;
6182b133ad6SJeff Kirsher case MEDIA_TYPE_100M_FULL:
6192b133ad6SJeff Kirsher mii_bmcr_data |= BMCR_SPEED100 | BMCR_FULLDPLX;
6202b133ad6SJeff Kirsher break;
6212b133ad6SJeff Kirsher case MEDIA_TYPE_100M_HALF:
6222b133ad6SJeff Kirsher mii_bmcr_data |= BMCR_SPEED100;
6232b133ad6SJeff Kirsher break;
6242b133ad6SJeff Kirsher case MEDIA_TYPE_10M_FULL:
6252b133ad6SJeff Kirsher mii_bmcr_data |= BMCR_FULLDPLX;
6262b133ad6SJeff Kirsher break;
6272b133ad6SJeff Kirsher case MEDIA_TYPE_10M_HALF:
6282b133ad6SJeff Kirsher break;
6292b133ad6SJeff Kirsher default:
6302b133ad6SJeff Kirsher if (netif_msg_link(adapter))
6312b133ad6SJeff Kirsher dev_err(&pdev->dev, "Wrong Media type %d\n",
6322b133ad6SJeff Kirsher hw->media_type);
6332b133ad6SJeff Kirsher return -1;
6342b133ad6SJeff Kirsher }
6352b133ad6SJeff Kirsher
6362b133ad6SJeff Kirsher ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
6372b133ad6SJeff Kirsher if (ret_val)
6382b133ad6SJeff Kirsher return ret_val;
6392b133ad6SJeff Kirsher hw->phy_configured = true;
6402b133ad6SJeff Kirsher
6412b133ad6SJeff Kirsher return 0;
6422b133ad6SJeff Kirsher }
6432b133ad6SJeff Kirsher
atl1c_get_link_status(struct atl1c_hw * hw)644ea0fbd05SGatis Peisenieks bool atl1c_get_link_status(struct atl1c_hw *hw)
645ea0fbd05SGatis Peisenieks {
646ea0fbd05SGatis Peisenieks u16 phy_data;
647ea0fbd05SGatis Peisenieks
648ea0fbd05SGatis Peisenieks if (hw->nic_type == athr_mt) {
649ea0fbd05SGatis Peisenieks u32 spd;
650ea0fbd05SGatis Peisenieks
651ea0fbd05SGatis Peisenieks AT_READ_REG(hw, REG_MT_SPEED, &spd);
652ea0fbd05SGatis Peisenieks return !!spd;
653ea0fbd05SGatis Peisenieks }
654ea0fbd05SGatis Peisenieks
655ea0fbd05SGatis Peisenieks /* MII_BMSR must be read twice */
656ea0fbd05SGatis Peisenieks atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
657ea0fbd05SGatis Peisenieks atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
658ea0fbd05SGatis Peisenieks return !!(phy_data & BMSR_LSTATUS);
659ea0fbd05SGatis Peisenieks }
660ea0fbd05SGatis Peisenieks
6612b133ad6SJeff Kirsher /*
6622b133ad6SJeff Kirsher * Detects the current speed and duplex settings of the hardware.
6632b133ad6SJeff Kirsher *
6642b133ad6SJeff Kirsher * hw - Struct containing variables accessed by shared code
6652b133ad6SJeff Kirsher * speed - Speed of the connection
6662b133ad6SJeff Kirsher * duplex - Duplex setting of the connection
6672b133ad6SJeff Kirsher */
atl1c_get_speed_and_duplex(struct atl1c_hw * hw,u16 * speed,u16 * duplex)6682b133ad6SJeff Kirsher int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
6692b133ad6SJeff Kirsher {
6702b133ad6SJeff Kirsher int err;
6712b133ad6SJeff Kirsher u16 phy_data;
6722b133ad6SJeff Kirsher
673f19d4997SGatis Peisenieks if (hw->nic_type == athr_mt) {
674f19d4997SGatis Peisenieks u32 spd;
675f19d4997SGatis Peisenieks
676f19d4997SGatis Peisenieks AT_READ_REG(hw, REG_MT_SPEED, &spd);
677f19d4997SGatis Peisenieks *speed = spd;
678f19d4997SGatis Peisenieks *duplex = FULL_DUPLEX;
679f19d4997SGatis Peisenieks return 0;
680f19d4997SGatis Peisenieks }
681f19d4997SGatis Peisenieks
6822b133ad6SJeff Kirsher /* Read PHY Specific Status Register (17) */
6832b133ad6SJeff Kirsher err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
6842b133ad6SJeff Kirsher if (err)
6852b133ad6SJeff Kirsher return err;
6862b133ad6SJeff Kirsher
6872b133ad6SJeff Kirsher if (!(phy_data & GIGA_PSSR_SPD_DPLX_RESOLVED))
6882b133ad6SJeff Kirsher return -1;
6892b133ad6SJeff Kirsher
6902b133ad6SJeff Kirsher switch (phy_data & GIGA_PSSR_SPEED) {
6912b133ad6SJeff Kirsher case GIGA_PSSR_1000MBS:
6922b133ad6SJeff Kirsher *speed = SPEED_1000;
6932b133ad6SJeff Kirsher break;
6942b133ad6SJeff Kirsher case GIGA_PSSR_100MBS:
6952b133ad6SJeff Kirsher *speed = SPEED_100;
6962b133ad6SJeff Kirsher break;
6972b133ad6SJeff Kirsher case GIGA_PSSR_10MBS:
6982b133ad6SJeff Kirsher *speed = SPEED_10;
6992b133ad6SJeff Kirsher break;
7002b133ad6SJeff Kirsher default:
7012b133ad6SJeff Kirsher return -1;
7022b133ad6SJeff Kirsher }
7032b133ad6SJeff Kirsher
7042b133ad6SJeff Kirsher if (phy_data & GIGA_PSSR_DPLX)
7052b133ad6SJeff Kirsher *duplex = FULL_DUPLEX;
7062b133ad6SJeff Kirsher else
7072b133ad6SJeff Kirsher *duplex = HALF_DUPLEX;
7082b133ad6SJeff Kirsher
7092b133ad6SJeff Kirsher return 0;
7102b133ad6SJeff Kirsher }
7112b133ad6SJeff Kirsher
712319d013aSHuang, Xiong /* select one link mode to get lower power consumption */
atl1c_phy_to_ps_link(struct atl1c_hw * hw)713319d013aSHuang, Xiong int atl1c_phy_to_ps_link(struct atl1c_hw *hw)
7142b133ad6SJeff Kirsher {
71564699336SJoe Perches struct atl1c_adapter *adapter = hw->adapter;
7162b133ad6SJeff Kirsher struct pci_dev *pdev = adapter->pdev;
7172b133ad6SJeff Kirsher int ret = 0;
7182b133ad6SJeff Kirsher u16 autoneg_advertised = ADVERTISED_10baseT_Half;
7192b133ad6SJeff Kirsher u16 save_autoneg_advertised;
7202b133ad6SJeff Kirsher u16 mii_lpa_data;
7212b133ad6SJeff Kirsher u16 speed = SPEED_0;
7222b133ad6SJeff Kirsher u16 duplex = FULL_DUPLEX;
7232b133ad6SJeff Kirsher int i;
7242b133ad6SJeff Kirsher
725ea0fbd05SGatis Peisenieks if (atl1c_get_link_status(hw)) {
7262b133ad6SJeff Kirsher atl1c_read_phy_reg(hw, MII_LPA, &mii_lpa_data);
7272b133ad6SJeff Kirsher if (mii_lpa_data & LPA_10FULL)
7282b133ad6SJeff Kirsher autoneg_advertised = ADVERTISED_10baseT_Full;
7292b133ad6SJeff Kirsher else if (mii_lpa_data & LPA_10HALF)
7302b133ad6SJeff Kirsher autoneg_advertised = ADVERTISED_10baseT_Half;
7312b133ad6SJeff Kirsher else if (mii_lpa_data & LPA_100HALF)
7322b133ad6SJeff Kirsher autoneg_advertised = ADVERTISED_100baseT_Half;
7332b133ad6SJeff Kirsher else if (mii_lpa_data & LPA_100FULL)
7342b133ad6SJeff Kirsher autoneg_advertised = ADVERTISED_100baseT_Full;
7352b133ad6SJeff Kirsher
7362b133ad6SJeff Kirsher save_autoneg_advertised = hw->autoneg_advertised;
7372b133ad6SJeff Kirsher hw->phy_configured = false;
7382b133ad6SJeff Kirsher hw->autoneg_advertised = autoneg_advertised;
7392b133ad6SJeff Kirsher if (atl1c_restart_autoneg(hw) != 0) {
7402b133ad6SJeff Kirsher dev_dbg(&pdev->dev, "phy autoneg failed\n");
7412b133ad6SJeff Kirsher ret = -1;
7422b133ad6SJeff Kirsher }
7432b133ad6SJeff Kirsher hw->autoneg_advertised = save_autoneg_advertised;
7442b133ad6SJeff Kirsher
7452b133ad6SJeff Kirsher if (mii_lpa_data) {
7462b133ad6SJeff Kirsher for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
7472b133ad6SJeff Kirsher mdelay(100);
748ea0fbd05SGatis Peisenieks if (atl1c_get_link_status(hw)) {
7492b133ad6SJeff Kirsher if (atl1c_get_speed_and_duplex(hw, &speed,
7502b133ad6SJeff Kirsher &duplex) != 0)
7512b133ad6SJeff Kirsher dev_dbg(&pdev->dev,
7522b133ad6SJeff Kirsher "get speed and duplex failed\n");
7532b133ad6SJeff Kirsher break;
7542b133ad6SJeff Kirsher }
7552b133ad6SJeff Kirsher }
7562b133ad6SJeff Kirsher }
7572b133ad6SJeff Kirsher } else {
7582b133ad6SJeff Kirsher speed = SPEED_10;
7592b133ad6SJeff Kirsher duplex = HALF_DUPLEX;
7602b133ad6SJeff Kirsher }
7612b133ad6SJeff Kirsher adapter->link_speed = speed;
7622b133ad6SJeff Kirsher adapter->link_duplex = duplex;
7632b133ad6SJeff Kirsher
7642b133ad6SJeff Kirsher return ret;
7652b133ad6SJeff Kirsher }
7662b133ad6SJeff Kirsher
atl1c_restart_autoneg(struct atl1c_hw * hw)7672b133ad6SJeff Kirsher int atl1c_restart_autoneg(struct atl1c_hw *hw)
7682b133ad6SJeff Kirsher {
7692b133ad6SJeff Kirsher int err = 0;
7702b133ad6SJeff Kirsher u16 mii_bmcr_data = BMCR_RESET;
7712b133ad6SJeff Kirsher
7722b133ad6SJeff Kirsher err = atl1c_phy_setup_adv(hw);
7732b133ad6SJeff Kirsher if (err)
7742b133ad6SJeff Kirsher return err;
7752b133ad6SJeff Kirsher mii_bmcr_data |= BMCR_ANENABLE | BMCR_ANRESTART;
7762b133ad6SJeff Kirsher
7772b133ad6SJeff Kirsher return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
7782b133ad6SJeff Kirsher }
779319d013aSHuang, Xiong
atl1c_power_saving(struct atl1c_hw * hw,u32 wufc)780319d013aSHuang, Xiong int atl1c_power_saving(struct atl1c_hw *hw, u32 wufc)
781319d013aSHuang, Xiong {
78264699336SJoe Perches struct atl1c_adapter *adapter = hw->adapter;
783319d013aSHuang, Xiong struct pci_dev *pdev = adapter->pdev;
784319d013aSHuang, Xiong u32 master_ctrl, mac_ctrl, phy_ctrl;
785319d013aSHuang, Xiong u32 wol_ctrl, speed;
786319d013aSHuang, Xiong u16 phy_data;
787319d013aSHuang, Xiong
788319d013aSHuang, Xiong wol_ctrl = 0;
789319d013aSHuang, Xiong speed = adapter->link_speed == SPEED_1000 ?
790319d013aSHuang, Xiong MAC_CTRL_SPEED_1000 : MAC_CTRL_SPEED_10_100;
791319d013aSHuang, Xiong
792319d013aSHuang, Xiong AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl);
793319d013aSHuang, Xiong AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl);
794319d013aSHuang, Xiong AT_READ_REG(hw, REG_GPHY_CTRL, &phy_ctrl);
795319d013aSHuang, Xiong
796319d013aSHuang, Xiong master_ctrl &= ~MASTER_CTRL_CLK_SEL_DIS;
797319d013aSHuang, Xiong mac_ctrl = FIELD_SETX(mac_ctrl, MAC_CTRL_SPEED, speed);
798319d013aSHuang, Xiong mac_ctrl &= ~(MAC_CTRL_DUPLX | MAC_CTRL_RX_EN | MAC_CTRL_TX_EN);
799319d013aSHuang, Xiong if (adapter->link_duplex == FULL_DUPLEX)
800319d013aSHuang, Xiong mac_ctrl |= MAC_CTRL_DUPLX;
801319d013aSHuang, Xiong phy_ctrl &= ~(GPHY_CTRL_EXT_RESET | GPHY_CTRL_CLS);
802319d013aSHuang, Xiong phy_ctrl |= GPHY_CTRL_SEL_ANA_RST | GPHY_CTRL_HIB_PULSE |
803319d013aSHuang, Xiong GPHY_CTRL_HIB_EN;
804319d013aSHuang, Xiong if (!wufc) { /* without WoL */
805319d013aSHuang, Xiong master_ctrl |= MASTER_CTRL_CLK_SEL_DIS;
806319d013aSHuang, Xiong phy_ctrl |= GPHY_CTRL_PHY_IDDQ | GPHY_CTRL_PWDOWN_HW;
807319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl);
808319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl);
809319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl);
810319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
811319d013aSHuang, Xiong hw->phy_configured = false; /* re-init PHY when resume */
812319d013aSHuang, Xiong return 0;
813319d013aSHuang, Xiong }
814319d013aSHuang, Xiong phy_ctrl |= GPHY_CTRL_EXT_RESET;
815319d013aSHuang, Xiong if (wufc & AT_WUFC_MAG) {
816319d013aSHuang, Xiong mac_ctrl |= MAC_CTRL_RX_EN | MAC_CTRL_BC_EN;
817319d013aSHuang, Xiong wol_ctrl |= WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
818319d013aSHuang, Xiong if (hw->nic_type == athr_l2c_b && hw->revision_id == L2CB_V11)
819319d013aSHuang, Xiong wol_ctrl |= WOL_PATTERN_EN | WOL_PATTERN_PME_EN;
820319d013aSHuang, Xiong }
821319d013aSHuang, Xiong if (wufc & AT_WUFC_LNKC) {
822319d013aSHuang, Xiong wol_ctrl |= WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
823319d013aSHuang, Xiong if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
8241051e9b3SMasanari Iida dev_dbg(&pdev->dev, "%s: write phy MII_IER failed.\n",
825319d013aSHuang, Xiong atl1c_driver_name);
826319d013aSHuang, Xiong }
827319d013aSHuang, Xiong }
828319d013aSHuang, Xiong /* clear PHY interrupt */
829319d013aSHuang, Xiong atl1c_read_phy_reg(hw, MII_ISR, &phy_data);
830319d013aSHuang, Xiong
831319d013aSHuang, Xiong dev_dbg(&pdev->dev, "%s: suspend MAC=%x,MASTER=%x,PHY=0x%x,WOL=%x\n",
832319d013aSHuang, Xiong atl1c_driver_name, mac_ctrl, master_ctrl, phy_ctrl, wol_ctrl);
833319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl);
834319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl);
835319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl);
836319d013aSHuang, Xiong AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl);
837319d013aSHuang, Xiong
838319d013aSHuang, Xiong return 0;
839319d013aSHuang, Xiong }
840903d7ce0SHuang, Xiong
841903d7ce0SHuang, Xiong
842903d7ce0SHuang, Xiong /* configure phy after Link change Event */
atl1c_post_phy_linkchg(struct atl1c_hw * hw,u16 link_speed)843903d7ce0SHuang, Xiong void atl1c_post_phy_linkchg(struct atl1c_hw *hw, u16 link_speed)
844903d7ce0SHuang, Xiong {
845903d7ce0SHuang, Xiong u16 phy_val;
846903d7ce0SHuang, Xiong bool adj_thresh = false;
847903d7ce0SHuang, Xiong
848903d7ce0SHuang, Xiong if (hw->nic_type == athr_l2c_b || hw->nic_type == athr_l2c_b2 ||
849903d7ce0SHuang, Xiong hw->nic_type == athr_l1d || hw->nic_type == athr_l1d_2)
850903d7ce0SHuang, Xiong adj_thresh = true;
851903d7ce0SHuang, Xiong
852903d7ce0SHuang, Xiong if (link_speed != SPEED_0) { /* link up */
853903d7ce0SHuang, Xiong /* az with brcm, half-amp */
854903d7ce0SHuang, Xiong if (hw->nic_type == athr_l1d_2) {
855903d7ce0SHuang, Xiong atl1c_read_phy_ext(hw, MIIEXT_PCS, MIIEXT_CLDCTRL6,
856903d7ce0SHuang, Xiong &phy_val);
857903d7ce0SHuang, Xiong phy_val = FIELD_GETX(phy_val, CLDCTRL6_CAB_LEN);
858903d7ce0SHuang, Xiong phy_val = phy_val > CLDCTRL6_CAB_LEN_SHORT ?
859903d7ce0SHuang, Xiong AZ_ANADECT_LONG : AZ_ANADECT_DEF;
860903d7ce0SHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_AZ_ANADECT, phy_val);
861903d7ce0SHuang, Xiong }
862903d7ce0SHuang, Xiong /* threshold adjust */
863903d7ce0SHuang, Xiong if (adj_thresh && link_speed == SPEED_100 && hw->msi_lnkpatch) {
864903d7ce0SHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB, L1D_MSE16DB_UP);
865903d7ce0SHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
866903d7ce0SHuang, Xiong L1D_SYSMODCTRL_IECHOADJ_DEF);
867903d7ce0SHuang, Xiong }
868903d7ce0SHuang, Xiong } else { /* link down */
869903d7ce0SHuang, Xiong if (adj_thresh && hw->msi_lnkpatch) {
870903d7ce0SHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_SYSMODCTRL,
871903d7ce0SHuang, Xiong SYSMODCTRL_IECHOADJ_DEF);
872903d7ce0SHuang, Xiong atl1c_write_phy_dbg(hw, MIIDBG_MSE16DB,
873903d7ce0SHuang, Xiong L1D_MSE16DB_DOWN);
874903d7ce0SHuang, Xiong }
875903d7ce0SHuang, Xiong }
876903d7ce0SHuang, Xiong }
877