cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pch_gbe_phy.c (11875B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 1999 - 2010 Intel Corporation.
      4 * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
      5 *
      6 * This code was derived from the Intel e1000e Linux driver.
      7 */
      8
      9#include "pch_gbe.h"
     10#include "pch_gbe_phy.h"
     11
     12#define PHY_MAX_REG_ADDRESS   0x1F	/* 5 bit address bus (0-0x1F) */
     13
     14/* PHY 1000 MII Register/Bit Definitions */
     15/* PHY Registers defined by IEEE */
     16#define PHY_CONTROL           0x00  /* Control Register */
     17#define PHY_STATUS            0x01  /* Status Regiser */
     18#define PHY_ID1               0x02  /* Phy Id Register (word 1) */
     19#define PHY_ID2               0x03  /* Phy Id Register (word 2) */
     20#define PHY_AUTONEG_ADV       0x04  /* Autoneg Advertisement */
     21#define PHY_LP_ABILITY        0x05  /* Link Partner Ability (Base Page) */
     22#define PHY_AUTONEG_EXP       0x06  /* Autoneg Expansion Register */
     23#define PHY_NEXT_PAGE_TX      0x07  /* Next Page TX */
     24#define PHY_LP_NEXT_PAGE      0x08  /* Link Partner Next Page */
     25#define PHY_1000T_CTRL        0x09  /* 1000Base-T Control Register */
     26#define PHY_1000T_STATUS      0x0A  /* 1000Base-T Status Register */
     27#define PHY_EXT_STATUS        0x0F  /* Extended Status Register */
     28#define PHY_PHYSP_CONTROL     0x10  /* PHY Specific Control Register */
     29#define PHY_EXT_PHYSP_CONTROL 0x14  /* Extended PHY Specific Control Register */
     30#define PHY_LED_CONTROL       0x18  /* LED Control Register */
     31#define PHY_EXT_PHYSP_STATUS  0x1B  /* Extended PHY Specific Status Register */
     32
     33/* PHY Control Register */
     34#define MII_CR_SPEED_SELECT_MSB 0x0040	/* bits 6,13: 10=1000, 01=100, 00=10 */
     35#define MII_CR_COLL_TEST_ENABLE 0x0080	/* Collision test enable */
     36#define MII_CR_FULL_DUPLEX      0x0100	/* FDX =1, half duplex =0 */
     37#define MII_CR_RESTART_AUTO_NEG 0x0200	/* Restart auto negotiation */
     38#define MII_CR_ISOLATE          0x0400	/* Isolate PHY from MII */
     39#define MII_CR_POWER_DOWN       0x0800	/* Power down */
     40#define MII_CR_AUTO_NEG_EN      0x1000	/* Auto Neg Enable */
     41#define MII_CR_SPEED_SELECT_LSB 0x2000	/* bits 6,13: 10=1000, 01=100, 00=10 */
     42#define MII_CR_LOOPBACK         0x4000	/* 0 = normal, 1 = loopback */
     43#define MII_CR_RESET            0x8000	/* 0 = normal, 1 = PHY reset */
     44#define MII_CR_SPEED_1000       0x0040
     45#define MII_CR_SPEED_100        0x2000
     46#define MII_CR_SPEED_10         0x0000
     47
     48/* PHY Status Register */
     49#define MII_SR_EXTENDED_CAPS     0x0001	/* Extended register capabilities */
     50#define MII_SR_JABBER_DETECT     0x0002	/* Jabber Detected */
     51#define MII_SR_LINK_STATUS       0x0004	/* Link Status 1 = link */
     52#define MII_SR_AUTONEG_CAPS      0x0008	/* Auto Neg Capable */
     53#define MII_SR_REMOTE_FAULT      0x0010	/* Remote Fault Detect */
     54#define MII_SR_AUTONEG_COMPLETE  0x0020	/* Auto Neg Complete */
     55#define MII_SR_PREAMBLE_SUPPRESS 0x0040	/* Preamble may be suppressed */
     56#define MII_SR_EXTENDED_STATUS   0x0100	/* Ext. status info in Reg 0x0F */
     57#define MII_SR_100T2_HD_CAPS     0x0200	/* 100T2 Half Duplex Capable */
     58#define MII_SR_100T2_FD_CAPS     0x0400	/* 100T2 Full Duplex Capable */
     59#define MII_SR_10T_HD_CAPS       0x0800	/* 10T   Half Duplex Capable */
     60#define MII_SR_10T_FD_CAPS       0x1000	/* 10T   Full Duplex Capable */
     61#define MII_SR_100X_HD_CAPS      0x2000	/* 100X  Half Duplex Capable */
     62#define MII_SR_100X_FD_CAPS      0x4000	/* 100X  Full Duplex Capable */
     63#define MII_SR_100T4_CAPS        0x8000	/* 100T4 Capable */
     64
     65/* AR8031 PHY Debug Registers */
     66#define PHY_AR803X_ID           0x00001374
     67#define PHY_AR8031_DBG_OFF      0x1D
     68#define PHY_AR8031_DBG_DAT      0x1E
     69#define PHY_AR8031_SERDES       0x05
     70#define PHY_AR8031_HIBERNATE    0x0B
     71#define PHY_AR8031_SERDES_TX_CLK_DLY   0x0100 /* TX clock delay of 2.0ns */
     72#define PHY_AR8031_PS_HIB_EN           0x8000 /* Hibernate enable */
     73
     74/* Phy Id Register (word 2) */
     75#define PHY_REVISION_MASK        0x000F
     76
     77/* PHY Specific Control Register */
     78#define PHYSP_CTRL_ASSERT_CRS_TX  0x0800
     79
     80
     81/* Default value of PHY register */
     82#define PHY_CONTROL_DEFAULT         0x1140 /* Control Register */
     83#define PHY_AUTONEG_ADV_DEFAULT     0x01e0 /* Autoneg Advertisement */
     84#define PHY_NEXT_PAGE_TX_DEFAULT    0x2001 /* Next Page TX */
     85#define PHY_1000T_CTRL_DEFAULT      0x0300 /* 1000Base-T Control Register */
     86#define PHY_PHYSP_CONTROL_DEFAULT   0x01EE /* PHY Specific Control Register */
     87
     88/**
     89 * pch_gbe_phy_get_id - Retrieve the PHY ID and revision
     90 * @hw:	       Pointer to the HW structure
     91 * Returns
     92 *	0:			Successful.
     93 *	Negative value:		Failed.
     94 */
     95s32 pch_gbe_phy_get_id(struct pch_gbe_hw *hw)
     96{
     97	struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
     98	struct pch_gbe_phy_info *phy = &hw->phy;
     99	s32 ret;
    100	u16 phy_id1;
    101	u16 phy_id2;
    102
    103	ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID1, &phy_id1);
    104	if (ret)
    105		return ret;
    106	ret = pch_gbe_phy_read_reg_miic(hw, PHY_ID2, &phy_id2);
    107	if (ret)
    108		return ret;
    109	/*
    110	 * PHY_ID1: [bit15-0:ID(21-6)]
    111	 * PHY_ID2: [bit15-10:ID(5-0)][bit9-4:Model][bit3-0:revision]
    112	 */
    113	phy->id = (u32)phy_id1;
    114	phy->id = ((phy->id << 6) | ((phy_id2 & 0xFC00) >> 10));
    115	phy->revision = (u32) (phy_id2 & 0x000F);
    116	netdev_dbg(adapter->netdev,
    117		   "phy->id : 0x%08x  phy->revision : 0x%08x\n",
    118		   phy->id, phy->revision);
    119	return 0;
    120}
    121
    122/**
    123 * pch_gbe_phy_read_reg_miic - Read MII control register
    124 * @hw:	     Pointer to the HW structure
    125 * @offset:  Register offset to be read
    126 * @data:    Pointer to the read data
    127 * Returns
    128 *	0:		Successful.
    129 *	-EINVAL:	Invalid argument.
    130 */
    131s32 pch_gbe_phy_read_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 *data)
    132{
    133	struct pch_gbe_phy_info *phy = &hw->phy;
    134
    135	if (offset > PHY_MAX_REG_ADDRESS) {
    136		struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
    137
    138		netdev_err(adapter->netdev, "PHY Address %d is out of range\n",
    139			   offset);
    140		return -EINVAL;
    141	}
    142	*data = pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_READ,
    143				      offset, (u16)0);
    144	return 0;
    145}
    146
    147/**
    148 * pch_gbe_phy_write_reg_miic - Write MII control register
    149 * @hw:	     Pointer to the HW structure
    150 * @offset:  Register offset to be read
    151 * @data:    data to write to register at offset
    152 * Returns
    153 *	0:		Successful.
    154 *	-EINVAL:	Invalid argument.
    155 */
    156s32 pch_gbe_phy_write_reg_miic(struct pch_gbe_hw *hw, u32 offset, u16 data)
    157{
    158	struct pch_gbe_phy_info *phy = &hw->phy;
    159
    160	if (offset > PHY_MAX_REG_ADDRESS) {
    161		struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
    162
    163		netdev_err(adapter->netdev, "PHY Address %d is out of range\n",
    164			   offset);
    165		return -EINVAL;
    166	}
    167	pch_gbe_mac_ctrl_miim(hw, phy->addr, PCH_GBE_HAL_MIIM_WRITE,
    168				 offset, data);
    169	return 0;
    170}
    171
    172/**
    173 * pch_gbe_phy_sw_reset - PHY software reset
    174 * @hw:	            Pointer to the HW structure
    175 */
    176static void pch_gbe_phy_sw_reset(struct pch_gbe_hw *hw)
    177{
    178	u16 phy_ctrl;
    179
    180	pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &phy_ctrl);
    181	phy_ctrl |= MII_CR_RESET;
    182	pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, phy_ctrl);
    183	udelay(1);
    184}
    185
    186/**
    187 * pch_gbe_phy_hw_reset - PHY hardware reset
    188 * @hw:	   Pointer to the HW structure
    189 */
    190void pch_gbe_phy_hw_reset(struct pch_gbe_hw *hw)
    191{
    192	pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, PHY_CONTROL_DEFAULT);
    193	pch_gbe_phy_write_reg_miic(hw, PHY_AUTONEG_ADV,
    194					PHY_AUTONEG_ADV_DEFAULT);
    195	pch_gbe_phy_write_reg_miic(hw, PHY_NEXT_PAGE_TX,
    196					PHY_NEXT_PAGE_TX_DEFAULT);
    197	pch_gbe_phy_write_reg_miic(hw, PHY_1000T_CTRL, PHY_1000T_CTRL_DEFAULT);
    198	pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL,
    199					PHY_PHYSP_CONTROL_DEFAULT);
    200}
    201
    202/**
    203 * pch_gbe_phy_power_up - restore link in case the phy was powered down
    204 * @hw:	   Pointer to the HW structure
    205 */
    206void pch_gbe_phy_power_up(struct pch_gbe_hw *hw)
    207{
    208	u16 mii_reg;
    209
    210	mii_reg = 0;
    211	/* Just clear the power down bit to wake the phy back up */
    212	/* according to the manual, the phy will retain its
    213	 * settings across a power-down/up cycle */
    214	pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
    215	mii_reg &= ~MII_CR_POWER_DOWN;
    216	pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
    217}
    218
    219/**
    220 * pch_gbe_phy_power_down - Power down PHY
    221 * @hw:	   Pointer to the HW structure
    222 */
    223void pch_gbe_phy_power_down(struct pch_gbe_hw *hw)
    224{
    225	u16 mii_reg;
    226
    227	mii_reg = 0;
    228	/* Power down the PHY so no link is implied when interface is down *
    229	 * The PHY cannot be powered down if any of the following is TRUE *
    230	 * (a) WoL is enabled
    231	 * (b) AMT is active
    232	 */
    233	pch_gbe_phy_read_reg_miic(hw, PHY_CONTROL, &mii_reg);
    234	mii_reg |= MII_CR_POWER_DOWN;
    235	pch_gbe_phy_write_reg_miic(hw, PHY_CONTROL, mii_reg);
    236	mdelay(1);
    237}
    238
    239/**
    240 * pch_gbe_phy_set_rgmii - RGMII interface setting
    241 * @hw:	            Pointer to the HW structure
    242 */
    243void pch_gbe_phy_set_rgmii(struct pch_gbe_hw *hw)
    244{
    245	pch_gbe_phy_sw_reset(hw);
    246}
    247
    248/**
    249 * pch_gbe_phy_tx_clk_delay - Setup TX clock delay via the PHY
    250 * @hw:	            Pointer to the HW structure
    251 * Returns
    252 *	0:		Successful.
    253 *	-EINVAL:	Invalid argument.
    254 */
    255static int pch_gbe_phy_tx_clk_delay(struct pch_gbe_hw *hw)
    256{
    257	/* The RGMII interface requires a ~2ns TX clock delay. This is typically
    258	 * done in layout with a longer trace or via PHY strapping, but can also
    259	 * be done via PHY configuration registers.
    260	 */
    261	struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
    262	u16 mii_reg;
    263	int ret = 0;
    264
    265	switch (hw->phy.id) {
    266	case PHY_AR803X_ID:
    267		netdev_dbg(adapter->netdev,
    268			   "Configuring AR803X PHY for 2ns TX clock delay\n");
    269		pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_OFF, &mii_reg);
    270		ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
    271						 PHY_AR8031_SERDES);
    272		if (ret)
    273			break;
    274
    275		pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
    276		mii_reg |= PHY_AR8031_SERDES_TX_CLK_DLY;
    277		ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
    278						 mii_reg);
    279		break;
    280	default:
    281		netdev_err(adapter->netdev,
    282			   "Unknown PHY (%x), could not set TX clock delay\n",
    283			   hw->phy.id);
    284		return -EINVAL;
    285	}
    286
    287	if (ret)
    288		netdev_err(adapter->netdev,
    289			   "Could not configure tx clock delay for PHY\n");
    290	return ret;
    291}
    292
    293/**
    294 * pch_gbe_phy_init_setting - PHY initial setting
    295 * @hw:	            Pointer to the HW structure
    296 */
    297void pch_gbe_phy_init_setting(struct pch_gbe_hw *hw)
    298{
    299	struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
    300	struct ethtool_cmd     cmd = { .cmd = ETHTOOL_GSET };
    301	int ret;
    302	u16 mii_reg;
    303
    304	mii_ethtool_gset(&adapter->mii, &cmd);
    305
    306	ethtool_cmd_speed_set(&cmd, hw->mac.link_speed);
    307	cmd.duplex = hw->mac.link_duplex;
    308	cmd.advertising = hw->phy.autoneg_advertised;
    309	cmd.autoneg = hw->mac.autoneg;
    310	pch_gbe_phy_write_reg_miic(hw, MII_BMCR, BMCR_RESET);
    311	ret = mii_ethtool_sset(&adapter->mii, &cmd);
    312	if (ret)
    313		netdev_err(adapter->netdev, "Error: mii_ethtool_sset\n");
    314
    315	pch_gbe_phy_sw_reset(hw);
    316
    317	pch_gbe_phy_read_reg_miic(hw, PHY_PHYSP_CONTROL, &mii_reg);
    318	mii_reg |= PHYSP_CTRL_ASSERT_CRS_TX;
    319	pch_gbe_phy_write_reg_miic(hw, PHY_PHYSP_CONTROL, mii_reg);
    320
    321	/* Setup a TX clock delay on certain platforms */
    322	if (adapter->pdata && adapter->pdata->phy_tx_clk_delay)
    323		pch_gbe_phy_tx_clk_delay(hw);
    324}
    325
    326/**
    327 * pch_gbe_phy_disable_hibernate - Disable the PHY low power state
    328 * @hw:	            Pointer to the HW structure
    329 * Returns
    330 *	0:		Successful.
    331 *	-EINVAL:	Invalid argument.
    332 */
    333int pch_gbe_phy_disable_hibernate(struct pch_gbe_hw *hw)
    334{
    335	struct pch_gbe_adapter *adapter = pch_gbe_hw_to_adapter(hw);
    336	u16 mii_reg;
    337	int ret = 0;
    338
    339	switch (hw->phy.id) {
    340	case PHY_AR803X_ID:
    341		netdev_dbg(adapter->netdev,
    342			   "Disabling hibernation for AR803X PHY\n");
    343		ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_OFF,
    344						 PHY_AR8031_HIBERNATE);
    345		if (ret)
    346			break;
    347
    348		pch_gbe_phy_read_reg_miic(hw, PHY_AR8031_DBG_DAT, &mii_reg);
    349		mii_reg &= ~PHY_AR8031_PS_HIB_EN;
    350		ret = pch_gbe_phy_write_reg_miic(hw, PHY_AR8031_DBG_DAT,
    351						 mii_reg);
    352		break;
    353	default:
    354		netdev_err(adapter->netdev,
    355			   "Unknown PHY (%x), could not disable hibernation\n",
    356			   hw->phy.id);
    357		return -EINVAL;
    358	}
    359
    360	if (ret)
    361		netdev_err(adapter->netdev,
    362			   "Could not disable PHY hibernation\n");
    363	return ret;
    364}