18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright(c) 2007 Atheros Corporation. All rights reserved. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Derived from Intel e1000 driver 68c2ecf20Sopenharmony_ci * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci#include <linux/pci.h> 98c2ecf20Sopenharmony_ci#include <linux/delay.h> 108c2ecf20Sopenharmony_ci#include <linux/mii.h> 118c2ecf20Sopenharmony_ci#include <linux/crc32.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "atl1e.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * check_eeprom_exist 178c2ecf20Sopenharmony_ci * return 0 if eeprom exist 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ciint atl1e_check_eeprom_exist(struct atl1e_hw *hw) 208c2ecf20Sopenharmony_ci{ 218c2ecf20Sopenharmony_ci u32 value; 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci value = AT_READ_REG(hw, REG_SPI_FLASH_CTRL); 248c2ecf20Sopenharmony_ci if (value & SPI_FLASH_CTRL_EN_VPD) { 258c2ecf20Sopenharmony_ci value &= ~SPI_FLASH_CTRL_EN_VPD; 268c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_SPI_FLASH_CTRL, value); 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci value = AT_READ_REGW(hw, REG_PCIE_CAP_LIST); 298c2ecf20Sopenharmony_ci return ((value & 0xFF00) == 0x6C00) ? 0 : 1; 308c2ecf20Sopenharmony_ci} 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_civoid atl1e_hw_set_mac_addr(struct atl1e_hw *hw) 338c2ecf20Sopenharmony_ci{ 348c2ecf20Sopenharmony_ci u32 value; 358c2ecf20Sopenharmony_ci /* 368c2ecf20Sopenharmony_ci * 00-0B-6A-F6-00-DC 378c2ecf20Sopenharmony_ci * 0: 6AF600DC 1: 000B 388c2ecf20Sopenharmony_ci * low dword 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci value = (((u32)hw->mac_addr[2]) << 24) | 418c2ecf20Sopenharmony_ci (((u32)hw->mac_addr[3]) << 16) | 428c2ecf20Sopenharmony_ci (((u32)hw->mac_addr[4]) << 8) | 438c2ecf20Sopenharmony_ci (((u32)hw->mac_addr[5])) ; 448c2ecf20Sopenharmony_ci AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value); 458c2ecf20Sopenharmony_ci /* hight dword */ 468c2ecf20Sopenharmony_ci value = (((u32)hw->mac_addr[0]) << 8) | 478c2ecf20Sopenharmony_ci (((u32)hw->mac_addr[1])) ; 488c2ecf20Sopenharmony_ci AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value); 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci/* 528c2ecf20Sopenharmony_ci * atl1e_get_permanent_address 538c2ecf20Sopenharmony_ci * return 0 if get valid mac address, 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_cistatic int atl1e_get_permanent_address(struct atl1e_hw *hw) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci u32 addr[2]; 588c2ecf20Sopenharmony_ci u32 i; 598c2ecf20Sopenharmony_ci u32 twsi_ctrl_data; 608c2ecf20Sopenharmony_ci u8 eth_addr[ETH_ALEN]; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (is_valid_ether_addr(hw->perm_mac_addr)) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* init */ 668c2ecf20Sopenharmony_ci addr[0] = addr[1] = 0; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci if (!atl1e_check_eeprom_exist(hw)) { 698c2ecf20Sopenharmony_ci /* eeprom exist */ 708c2ecf20Sopenharmony_ci twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL); 718c2ecf20Sopenharmony_ci twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART; 728c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data); 738c2ecf20Sopenharmony_ci for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) { 748c2ecf20Sopenharmony_ci msleep(10); 758c2ecf20Sopenharmony_ci twsi_ctrl_data = AT_READ_REG(hw, REG_TWSI_CTRL); 768c2ecf20Sopenharmony_ci if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0) 778c2ecf20Sopenharmony_ci break; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci if (i >= AT_TWSI_EEPROM_TIMEOUT) 808c2ecf20Sopenharmony_ci return AT_ERR_TIMEOUT; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci /* maybe MAC-address is from BIOS */ 848c2ecf20Sopenharmony_ci addr[0] = AT_READ_REG(hw, REG_MAC_STA_ADDR); 858c2ecf20Sopenharmony_ci addr[1] = AT_READ_REG(hw, REG_MAC_STA_ADDR + 4); 868c2ecf20Sopenharmony_ci *(u32 *) ð_addr[2] = swab32(addr[0]); 878c2ecf20Sopenharmony_ci *(u16 *) ð_addr[0] = swab16(*(u16 *)&addr[1]); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci if (is_valid_ether_addr(eth_addr)) { 908c2ecf20Sopenharmony_ci memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN); 918c2ecf20Sopenharmony_ci return 0; 928c2ecf20Sopenharmony_ci } 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return AT_ERR_EEPROM; 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cibool atl1e_write_eeprom(struct atl1e_hw *hw, u32 offset, u32 value) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci return true; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cibool atl1e_read_eeprom(struct atl1e_hw *hw, u32 offset, u32 *p_value) 1038c2ecf20Sopenharmony_ci{ 1048c2ecf20Sopenharmony_ci int i; 1058c2ecf20Sopenharmony_ci u32 control; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (offset & 3) 1088c2ecf20Sopenharmony_ci return false; /* address do not align */ 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_VPD_DATA, 0); 1118c2ecf20Sopenharmony_ci control = (offset & VPD_CAP_VPD_ADDR_MASK) << VPD_CAP_VPD_ADDR_SHIFT; 1128c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_VPD_CAP, control); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci for (i = 0; i < 10; i++) { 1158c2ecf20Sopenharmony_ci msleep(2); 1168c2ecf20Sopenharmony_ci control = AT_READ_REG(hw, REG_VPD_CAP); 1178c2ecf20Sopenharmony_ci if (control & VPD_CAP_VPD_FLAG) 1188c2ecf20Sopenharmony_ci break; 1198c2ecf20Sopenharmony_ci } 1208c2ecf20Sopenharmony_ci if (control & VPD_CAP_VPD_FLAG) { 1218c2ecf20Sopenharmony_ci *p_value = AT_READ_REG(hw, REG_VPD_DATA); 1228c2ecf20Sopenharmony_ci return true; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci return false; /* timeout */ 1258c2ecf20Sopenharmony_ci} 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_civoid atl1e_force_ps(struct atl1e_hw *hw) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci AT_WRITE_REGW(hw, REG_GPHY_CTRL, 1308c2ecf20Sopenharmony_ci GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci/* 1348c2ecf20Sopenharmony_ci * Reads the adapter's MAC address from the EEPROM 1358c2ecf20Sopenharmony_ci * 1368c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_ciint atl1e_read_mac_addr(struct atl1e_hw *hw) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci int err = 0; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci err = atl1e_get_permanent_address(hw); 1438c2ecf20Sopenharmony_ci if (err) 1448c2ecf20Sopenharmony_ci return AT_ERR_EEPROM; 1458c2ecf20Sopenharmony_ci memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr)); 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci/* 1508c2ecf20Sopenharmony_ci * atl1e_hash_mc_addr 1518c2ecf20Sopenharmony_ci * purpose 1528c2ecf20Sopenharmony_ci * set hash value for a multicast address 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ciu32 atl1e_hash_mc_addr(struct atl1e_hw *hw, u8 *mc_addr) 1558c2ecf20Sopenharmony_ci{ 1568c2ecf20Sopenharmony_ci u32 crc32; 1578c2ecf20Sopenharmony_ci u32 value = 0; 1588c2ecf20Sopenharmony_ci int i; 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci crc32 = ether_crc_le(6, mc_addr); 1618c2ecf20Sopenharmony_ci for (i = 0; i < 32; i++) 1628c2ecf20Sopenharmony_ci value |= (((crc32 >> i) & 1) << (31 - i)); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return value; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/* 1688c2ecf20Sopenharmony_ci * Sets the bit in the multicast table corresponding to the hash value. 1698c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 1708c2ecf20Sopenharmony_ci * hash_value - Multicast address hash value 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_civoid atl1e_hash_set(struct atl1e_hw *hw, u32 hash_value) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 hash_bit, hash_reg; 1758c2ecf20Sopenharmony_ci u32 mta; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci /* 1788c2ecf20Sopenharmony_ci * The HASH Table is a register array of 2 32-bit registers. 1798c2ecf20Sopenharmony_ci * It is treated like an array of 64 bits. We want to set 1808c2ecf20Sopenharmony_ci * bit BitArray[hash_value]. So we figure out what register 1818c2ecf20Sopenharmony_ci * the bit is in, read it, OR in the new bit, then write 1828c2ecf20Sopenharmony_ci * back the new value. The register is determined by the 1838c2ecf20Sopenharmony_ci * upper 7 bits of the hash value and the bit within that 1848c2ecf20Sopenharmony_ci * register are determined by the lower 5 bits of the value. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci hash_reg = (hash_value >> 31) & 0x1; 1878c2ecf20Sopenharmony_ci hash_bit = (hash_value >> 26) & 0x1F; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg); 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci mta |= (1 << hash_bit); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ci/* 1968c2ecf20Sopenharmony_ci * Reads the value from a PHY register 1978c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 1988c2ecf20Sopenharmony_ci * reg_addr - address of the PHY register to read 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ciint atl1e_read_phy_reg(struct atl1e_hw *hw, u16 reg_addr, u16 *phy_data) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci u32 val; 2038c2ecf20Sopenharmony_ci int i; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT | 2068c2ecf20Sopenharmony_ci MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW | 2078c2ecf20Sopenharmony_ci MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_MDIO_CTRL, val); 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci wmb(); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci for (i = 0; i < MDIO_WAIT_TIMES; i++) { 2148c2ecf20Sopenharmony_ci udelay(2); 2158c2ecf20Sopenharmony_ci val = AT_READ_REG(hw, REG_MDIO_CTRL); 2168c2ecf20Sopenharmony_ci if (!(val & (MDIO_START | MDIO_BUSY))) 2178c2ecf20Sopenharmony_ci break; 2188c2ecf20Sopenharmony_ci wmb(); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci if (!(val & (MDIO_START | MDIO_BUSY))) { 2218c2ecf20Sopenharmony_ci *phy_data = (u16)val; 2228c2ecf20Sopenharmony_ci return 0; 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci return AT_ERR_PHY; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci/* 2298c2ecf20Sopenharmony_ci * Writes a value to a PHY register 2308c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 2318c2ecf20Sopenharmony_ci * reg_addr - address of the PHY register to write 2328c2ecf20Sopenharmony_ci * data - data to write to the PHY 2338c2ecf20Sopenharmony_ci */ 2348c2ecf20Sopenharmony_ciint atl1e_write_phy_reg(struct atl1e_hw *hw, u32 reg_addr, u16 phy_data) 2358c2ecf20Sopenharmony_ci{ 2368c2ecf20Sopenharmony_ci int i; 2378c2ecf20Sopenharmony_ci u32 val; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT | 2408c2ecf20Sopenharmony_ci (reg_addr&MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT | 2418c2ecf20Sopenharmony_ci MDIO_SUP_PREAMBLE | 2428c2ecf20Sopenharmony_ci MDIO_START | 2438c2ecf20Sopenharmony_ci MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_MDIO_CTRL, val); 2468c2ecf20Sopenharmony_ci wmb(); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci for (i = 0; i < MDIO_WAIT_TIMES; i++) { 2498c2ecf20Sopenharmony_ci udelay(2); 2508c2ecf20Sopenharmony_ci val = AT_READ_REG(hw, REG_MDIO_CTRL); 2518c2ecf20Sopenharmony_ci if (!(val & (MDIO_START | MDIO_BUSY))) 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci wmb(); 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (!(val & (MDIO_START | MDIO_BUSY))) 2578c2ecf20Sopenharmony_ci return 0; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci return AT_ERR_PHY; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci/* 2638c2ecf20Sopenharmony_ci * atl1e_init_pcie - init PCIE module 2648c2ecf20Sopenharmony_ci */ 2658c2ecf20Sopenharmony_cistatic void atl1e_init_pcie(struct atl1e_hw *hw) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci u32 value; 2688c2ecf20Sopenharmony_ci /* comment 2lines below to save more power when sususpend 2698c2ecf20Sopenharmony_ci value = LTSSM_TEST_MODE_DEF; 2708c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_LTSSM_TEST_MODE, value); 2718c2ecf20Sopenharmony_ci */ 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* pcie flow control mode change */ 2748c2ecf20Sopenharmony_ci value = AT_READ_REG(hw, 0x1008); 2758c2ecf20Sopenharmony_ci value |= 0x8000; 2768c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, 0x1008, value); 2778c2ecf20Sopenharmony_ci} 2788c2ecf20Sopenharmony_ci/* 2798c2ecf20Sopenharmony_ci * Configures PHY autoneg and flow control advertisement settings 2808c2ecf20Sopenharmony_ci * 2818c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 2828c2ecf20Sopenharmony_ci */ 2838c2ecf20Sopenharmony_cistatic int atl1e_phy_setup_autoneg_adv(struct atl1e_hw *hw) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci s32 ret_val; 2868c2ecf20Sopenharmony_ci u16 mii_autoneg_adv_reg; 2878c2ecf20Sopenharmony_ci u16 mii_1000t_ctrl_reg; 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (0 != hw->mii_autoneg_adv_reg) 2908c2ecf20Sopenharmony_ci return 0; 2918c2ecf20Sopenharmony_ci /* Read the MII Auto-Neg Advertisement Register (Address 4/9). */ 2928c2ecf20Sopenharmony_ci mii_autoneg_adv_reg = MII_AR_DEFAULT_CAP_MASK; 2938c2ecf20Sopenharmony_ci mii_1000t_ctrl_reg = MII_AT001_CR_1000T_DEFAULT_CAP_MASK; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* 2968c2ecf20Sopenharmony_ci * Need to parse autoneg_advertised and set up 2978c2ecf20Sopenharmony_ci * the appropriate PHY registers. First we will parse for 2988c2ecf20Sopenharmony_ci * autoneg_advertised software override. Since we can advertise 2998c2ecf20Sopenharmony_ci * a plethora of combinations, we need to check each bit 3008c2ecf20Sopenharmony_ci * individually. 3018c2ecf20Sopenharmony_ci */ 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci /* 3048c2ecf20Sopenharmony_ci * First we clear all the 10/100 mb speed bits in the Auto-Neg 3058c2ecf20Sopenharmony_ci * Advertisement Register (Address 4) and the 1000 mb speed bits in 3068c2ecf20Sopenharmony_ci * the 1000Base-T control Register (Address 9). 3078c2ecf20Sopenharmony_ci */ 3088c2ecf20Sopenharmony_ci mii_autoneg_adv_reg &= ~ADVERTISE_ALL; 3098c2ecf20Sopenharmony_ci mii_1000t_ctrl_reg &= ~MII_AT001_CR_1000T_SPEED_MASK; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* 3128c2ecf20Sopenharmony_ci * Need to parse MediaType and setup the 3138c2ecf20Sopenharmony_ci * appropriate PHY registers. 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci switch (hw->media_type) { 3168c2ecf20Sopenharmony_ci case MEDIA_TYPE_AUTO_SENSOR: 3178c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= ADVERTISE_ALL; 3188c2ecf20Sopenharmony_ci hw->autoneg_advertised = ADVERTISE_ALL; 3198c2ecf20Sopenharmony_ci if (hw->nic_type == athr_l1e) { 3208c2ecf20Sopenharmony_ci mii_1000t_ctrl_reg |= ADVERTISE_1000FULL; 3218c2ecf20Sopenharmony_ci hw->autoneg_advertised |= ADVERTISE_1000_FULL; 3228c2ecf20Sopenharmony_ci } 3238c2ecf20Sopenharmony_ci break; 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci case MEDIA_TYPE_100M_FULL: 3268c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= ADVERTISE_100FULL; 3278c2ecf20Sopenharmony_ci hw->autoneg_advertised = ADVERTISE_100_FULL; 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci case MEDIA_TYPE_100M_HALF: 3318c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= ADVERTISE_100_HALF; 3328c2ecf20Sopenharmony_ci hw->autoneg_advertised = ADVERTISE_100_HALF; 3338c2ecf20Sopenharmony_ci break; 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci case MEDIA_TYPE_10M_FULL: 3368c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= ADVERTISE_10_FULL; 3378c2ecf20Sopenharmony_ci hw->autoneg_advertised = ADVERTISE_10_FULL; 3388c2ecf20Sopenharmony_ci break; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci default: 3418c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= ADVERTISE_10_HALF; 3428c2ecf20Sopenharmony_ci hw->autoneg_advertised = ADVERTISE_10_HALF; 3438c2ecf20Sopenharmony_ci break; 3448c2ecf20Sopenharmony_ci } 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* flow control fixed to enable all */ 3478c2ecf20Sopenharmony_ci mii_autoneg_adv_reg |= (ADVERTISE_PAUSE_ASYM | ADVERTISE_PAUSE_CAP); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci hw->mii_autoneg_adv_reg = mii_autoneg_adv_reg; 3508c2ecf20Sopenharmony_ci hw->mii_1000t_ctrl_reg = mii_1000t_ctrl_reg; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_ADVERTISE, mii_autoneg_adv_reg); 3538c2ecf20Sopenharmony_ci if (ret_val) 3548c2ecf20Sopenharmony_ci return ret_val; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) { 3578c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_CTRL1000, 3588c2ecf20Sopenharmony_ci mii_1000t_ctrl_reg); 3598c2ecf20Sopenharmony_ci if (ret_val) 3608c2ecf20Sopenharmony_ci return ret_val; 3618c2ecf20Sopenharmony_ci } 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci return 0; 3648c2ecf20Sopenharmony_ci} 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci/* 3688c2ecf20Sopenharmony_ci * Resets the PHY and make all config validate 3698c2ecf20Sopenharmony_ci * 3708c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 3718c2ecf20Sopenharmony_ci * 3728c2ecf20Sopenharmony_ci * Sets bit 15 and 12 of the MII control regiser (for F001 bug) 3738c2ecf20Sopenharmony_ci */ 3748c2ecf20Sopenharmony_ciint atl1e_phy_commit(struct atl1e_hw *hw) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct atl1e_adapter *adapter = hw->adapter; 3778c2ecf20Sopenharmony_ci int ret_val; 3788c2ecf20Sopenharmony_ci u16 phy_data; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci phy_data = BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_BMCR, phy_data); 3838c2ecf20Sopenharmony_ci if (ret_val) { 3848c2ecf20Sopenharmony_ci u32 val; 3858c2ecf20Sopenharmony_ci int i; 3868c2ecf20Sopenharmony_ci /************************************** 3878c2ecf20Sopenharmony_ci * pcie serdes link may be down ! 3888c2ecf20Sopenharmony_ci **************************************/ 3898c2ecf20Sopenharmony_ci for (i = 0; i < 25; i++) { 3908c2ecf20Sopenharmony_ci msleep(1); 3918c2ecf20Sopenharmony_ci val = AT_READ_REG(hw, REG_MDIO_CTRL); 3928c2ecf20Sopenharmony_ci if (!(val & (MDIO_START | MDIO_BUSY))) 3938c2ecf20Sopenharmony_ci break; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (0 != (val & (MDIO_START | MDIO_BUSY))) { 3978c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 3988c2ecf20Sopenharmony_ci "pcie linkdown at least for 25ms\n"); 3998c2ecf20Sopenharmony_ci return ret_val; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, "pcie linkup after %d ms\n", i); 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci return 0; 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ciint atl1e_phy_init(struct atl1e_hw *hw) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci struct atl1e_adapter *adapter = hw->adapter; 4108c2ecf20Sopenharmony_ci s32 ret_val; 4118c2ecf20Sopenharmony_ci u16 phy_val; 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci if (hw->phy_configured) { 4148c2ecf20Sopenharmony_ci if (hw->re_autoneg) { 4158c2ecf20Sopenharmony_ci hw->re_autoneg = false; 4168c2ecf20Sopenharmony_ci return atl1e_restart_autoneg(hw); 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci return 0; 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci /* RESET GPHY Core */ 4228c2ecf20Sopenharmony_ci AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT); 4238c2ecf20Sopenharmony_ci msleep(2); 4248c2ecf20Sopenharmony_ci AT_WRITE_REGW(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT | 4258c2ecf20Sopenharmony_ci GPHY_CTRL_EXT_RESET); 4268c2ecf20Sopenharmony_ci msleep(2); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci /* patches */ 4298c2ecf20Sopenharmony_ci /* p1. eable hibernation mode */ 4308c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0xB); 4318c2ecf20Sopenharmony_ci if (ret_val) 4328c2ecf20Sopenharmony_ci return ret_val; 4338c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0xBC00); 4348c2ecf20Sopenharmony_ci if (ret_val) 4358c2ecf20Sopenharmony_ci return ret_val; 4368c2ecf20Sopenharmony_ci /* p2. set Class A/B for all modes */ 4378c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0); 4388c2ecf20Sopenharmony_ci if (ret_val) 4398c2ecf20Sopenharmony_ci return ret_val; 4408c2ecf20Sopenharmony_ci phy_val = 0x02ef; 4418c2ecf20Sopenharmony_ci /* remove Class AB */ 4428c2ecf20Sopenharmony_ci /* phy_val = hw->emi_ca ? 0x02ef : 0x02df; */ 4438c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, phy_val); 4448c2ecf20Sopenharmony_ci if (ret_val) 4458c2ecf20Sopenharmony_ci return ret_val; 4468c2ecf20Sopenharmony_ci /* p3. 10B ??? */ 4478c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x12); 4488c2ecf20Sopenharmony_ci if (ret_val) 4498c2ecf20Sopenharmony_ci return ret_val; 4508c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x4C04); 4518c2ecf20Sopenharmony_ci if (ret_val) 4528c2ecf20Sopenharmony_ci return ret_val; 4538c2ecf20Sopenharmony_ci /* p4. 1000T power */ 4548c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x4); 4558c2ecf20Sopenharmony_ci if (ret_val) 4568c2ecf20Sopenharmony_ci return ret_val; 4578c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x8BBB); 4588c2ecf20Sopenharmony_ci if (ret_val) 4598c2ecf20Sopenharmony_ci return ret_val; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_ADDR, 0x5); 4628c2ecf20Sopenharmony_ci if (ret_val) 4638c2ecf20Sopenharmony_ci return ret_val; 4648c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_DBG_DATA, 0x2C46); 4658c2ecf20Sopenharmony_ci if (ret_val) 4668c2ecf20Sopenharmony_ci return ret_val; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci msleep(1); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /*Enable PHY LinkChange Interrupt */ 4718c2ecf20Sopenharmony_ci ret_val = atl1e_write_phy_reg(hw, MII_INT_CTRL, 0xC00); 4728c2ecf20Sopenharmony_ci if (ret_val) { 4738c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 4748c2ecf20Sopenharmony_ci "Error enable PHY linkChange Interrupt\n"); 4758c2ecf20Sopenharmony_ci return ret_val; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci /* setup AutoNeg parameters */ 4788c2ecf20Sopenharmony_ci ret_val = atl1e_phy_setup_autoneg_adv(hw); 4798c2ecf20Sopenharmony_ci if (ret_val) { 4808c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 4818c2ecf20Sopenharmony_ci "Error Setting up Auto-Negotiation\n"); 4828c2ecf20Sopenharmony_ci return ret_val; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci /* SW.Reset & En-Auto-Neg to restart Auto-Neg*/ 4858c2ecf20Sopenharmony_ci netdev_dbg(adapter->netdev, "Restarting Auto-Negotiation\n"); 4868c2ecf20Sopenharmony_ci ret_val = atl1e_phy_commit(hw); 4878c2ecf20Sopenharmony_ci if (ret_val) { 4888c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, "Error resetting the phy\n"); 4898c2ecf20Sopenharmony_ci return ret_val; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci hw->phy_configured = true; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci} 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* 4988c2ecf20Sopenharmony_ci * Reset the transmit and receive units; mask and clear all interrupts. 4998c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 5008c2ecf20Sopenharmony_ci * return : 0 or idle status (if error) 5018c2ecf20Sopenharmony_ci */ 5028c2ecf20Sopenharmony_ciint atl1e_reset_hw(struct atl1e_hw *hw) 5038c2ecf20Sopenharmony_ci{ 5048c2ecf20Sopenharmony_ci struct atl1e_adapter *adapter = hw->adapter; 5058c2ecf20Sopenharmony_ci struct pci_dev *pdev = adapter->pdev; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci u32 idle_status_data = 0; 5088c2ecf20Sopenharmony_ci u16 pci_cfg_cmd_word = 0; 5098c2ecf20Sopenharmony_ci int timeout = 0; 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* Workaround for PCI problem when BIOS sets MMRBC incorrectly. */ 5128c2ecf20Sopenharmony_ci pci_read_config_word(pdev, PCI_REG_COMMAND, &pci_cfg_cmd_word); 5138c2ecf20Sopenharmony_ci if ((pci_cfg_cmd_word & (CMD_IO_SPACE | 5148c2ecf20Sopenharmony_ci CMD_MEMORY_SPACE | CMD_BUS_MASTER)) 5158c2ecf20Sopenharmony_ci != (CMD_IO_SPACE | CMD_MEMORY_SPACE | CMD_BUS_MASTER)) { 5168c2ecf20Sopenharmony_ci pci_cfg_cmd_word |= (CMD_IO_SPACE | 5178c2ecf20Sopenharmony_ci CMD_MEMORY_SPACE | CMD_BUS_MASTER); 5188c2ecf20Sopenharmony_ci pci_write_config_word(pdev, PCI_REG_COMMAND, pci_cfg_cmd_word); 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci /* 5228c2ecf20Sopenharmony_ci * Issue Soft Reset to the MAC. This will reset the chip's 5238c2ecf20Sopenharmony_ci * transmit, receive, DMA. It will not effect 5248c2ecf20Sopenharmony_ci * the current PCI configuration. The global reset bit is self- 5258c2ecf20Sopenharmony_ci * clearing, and should clear within a microsecond. 5268c2ecf20Sopenharmony_ci */ 5278c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_MASTER_CTRL, 5288c2ecf20Sopenharmony_ci MASTER_CTRL_LED_MODE | MASTER_CTRL_SOFT_RST); 5298c2ecf20Sopenharmony_ci wmb(); 5308c2ecf20Sopenharmony_ci msleep(1); 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci /* Wait at least 10ms for All module to be Idle */ 5338c2ecf20Sopenharmony_ci for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) { 5348c2ecf20Sopenharmony_ci idle_status_data = AT_READ_REG(hw, REG_IDLE_STATUS); 5358c2ecf20Sopenharmony_ci if (idle_status_data == 0) 5368c2ecf20Sopenharmony_ci break; 5378c2ecf20Sopenharmony_ci msleep(1); 5388c2ecf20Sopenharmony_ci cpu_relax(); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci if (timeout >= AT_HW_MAX_IDLE_DELAY) { 5428c2ecf20Sopenharmony_ci netdev_err(adapter->netdev, 5438c2ecf20Sopenharmony_ci "MAC state machine can't be idle since disabled for 10ms second\n"); 5448c2ecf20Sopenharmony_ci return AT_ERR_TIMEOUT; 5458c2ecf20Sopenharmony_ci } 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return 0; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci/* 5528c2ecf20Sopenharmony_ci * Performs basic configuration of the adapter. 5538c2ecf20Sopenharmony_ci * 5548c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 5558c2ecf20Sopenharmony_ci * Assumes that the controller has previously been reset and is in a 5568c2ecf20Sopenharmony_ci * post-reset uninitialized state. Initializes multicast table, 5578c2ecf20Sopenharmony_ci * and Calls routines to setup link 5588c2ecf20Sopenharmony_ci * Leaves the transmit and receive units disabled and uninitialized. 5598c2ecf20Sopenharmony_ci */ 5608c2ecf20Sopenharmony_ciint atl1e_init_hw(struct atl1e_hw *hw) 5618c2ecf20Sopenharmony_ci{ 5628c2ecf20Sopenharmony_ci s32 ret_val = 0; 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci atl1e_init_pcie(hw); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci /* Zero out the Multicast HASH table */ 5678c2ecf20Sopenharmony_ci /* clear the old settings from the multicast hash table */ 5688c2ecf20Sopenharmony_ci AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0); 5698c2ecf20Sopenharmony_ci AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0); 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci ret_val = atl1e_phy_init(hw); 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci return ret_val; 5748c2ecf20Sopenharmony_ci} 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci/* 5778c2ecf20Sopenharmony_ci * Detects the current speed and duplex settings of the hardware. 5788c2ecf20Sopenharmony_ci * 5798c2ecf20Sopenharmony_ci * hw - Struct containing variables accessed by shared code 5808c2ecf20Sopenharmony_ci * speed - Speed of the connection 5818c2ecf20Sopenharmony_ci * duplex - Duplex setting of the connection 5828c2ecf20Sopenharmony_ci */ 5838c2ecf20Sopenharmony_ciint atl1e_get_speed_and_duplex(struct atl1e_hw *hw, u16 *speed, u16 *duplex) 5848c2ecf20Sopenharmony_ci{ 5858c2ecf20Sopenharmony_ci int err; 5868c2ecf20Sopenharmony_ci u16 phy_data; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci /* Read PHY Specific Status Register (17) */ 5898c2ecf20Sopenharmony_ci err = atl1e_read_phy_reg(hw, MII_AT001_PSSR, &phy_data); 5908c2ecf20Sopenharmony_ci if (err) 5918c2ecf20Sopenharmony_ci return err; 5928c2ecf20Sopenharmony_ci 5938c2ecf20Sopenharmony_ci if (!(phy_data & MII_AT001_PSSR_SPD_DPLX_RESOLVED)) 5948c2ecf20Sopenharmony_ci return AT_ERR_PHY_RES; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci switch (phy_data & MII_AT001_PSSR_SPEED) { 5978c2ecf20Sopenharmony_ci case MII_AT001_PSSR_1000MBS: 5988c2ecf20Sopenharmony_ci *speed = SPEED_1000; 5998c2ecf20Sopenharmony_ci break; 6008c2ecf20Sopenharmony_ci case MII_AT001_PSSR_100MBS: 6018c2ecf20Sopenharmony_ci *speed = SPEED_100; 6028c2ecf20Sopenharmony_ci break; 6038c2ecf20Sopenharmony_ci case MII_AT001_PSSR_10MBS: 6048c2ecf20Sopenharmony_ci *speed = SPEED_10; 6058c2ecf20Sopenharmony_ci break; 6068c2ecf20Sopenharmony_ci default: 6078c2ecf20Sopenharmony_ci return AT_ERR_PHY_SPEED; 6088c2ecf20Sopenharmony_ci } 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci if (phy_data & MII_AT001_PSSR_DPLX) 6118c2ecf20Sopenharmony_ci *duplex = FULL_DUPLEX; 6128c2ecf20Sopenharmony_ci else 6138c2ecf20Sopenharmony_ci *duplex = HALF_DUPLEX; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci return 0; 6168c2ecf20Sopenharmony_ci} 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ciint atl1e_restart_autoneg(struct atl1e_hw *hw) 6198c2ecf20Sopenharmony_ci{ 6208c2ecf20Sopenharmony_ci int err = 0; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci err = atl1e_write_phy_reg(hw, MII_ADVERTISE, hw->mii_autoneg_adv_reg); 6238c2ecf20Sopenharmony_ci if (err) 6248c2ecf20Sopenharmony_ci return err; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (hw->nic_type == athr_l1e || hw->nic_type == athr_l2e_revA) { 6278c2ecf20Sopenharmony_ci err = atl1e_write_phy_reg(hw, MII_CTRL1000, 6288c2ecf20Sopenharmony_ci hw->mii_1000t_ctrl_reg); 6298c2ecf20Sopenharmony_ci if (err) 6308c2ecf20Sopenharmony_ci return err; 6318c2ecf20Sopenharmony_ci } 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci err = atl1e_write_phy_reg(hw, MII_BMCR, 6348c2ecf20Sopenharmony_ci BMCR_RESET | BMCR_ANENABLE | BMCR_ANRESTART); 6358c2ecf20Sopenharmony_ci return err; 6368c2ecf20Sopenharmony_ci} 6378c2ecf20Sopenharmony_ci 638