1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd. 3 */ 4 5 #include "ngbe_phy_rtl.h" 6 7 #define RTL_PHY_RST_WAIT_PERIOD 5 8 9 s32 ngbe_read_phy_reg_rtl(struct ngbe_hw *hw, 10 u32 reg_addr, u32 device_type, u16 *phy_data) 11 { 12 mdi_reg_t reg; 13 mdi_reg_22_t reg22; 14 15 reg.device_type = device_type; 16 reg.addr = reg_addr; 17 ngbe_mdi_map_register(®, ®22); 18 19 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page); 20 *phy_data = 0xFFFF & rd32(hw, NGBE_PHY_CONFIG(reg22.addr)); 21 22 return 0; 23 } 24 25 s32 ngbe_write_phy_reg_rtl(struct ngbe_hw *hw, 26 u32 reg_addr, u32 device_type, u16 phy_data) 27 { 28 mdi_reg_t reg; 29 mdi_reg_22_t reg22; 30 31 reg.device_type = device_type; 32 reg.addr = reg_addr; 33 ngbe_mdi_map_register(®, ®22); 34 35 wr32(hw, NGBE_PHY_CONFIG(RTL_PAGE_SELECT), reg22.page); 36 wr32(hw, NGBE_PHY_CONFIG(reg22.addr), phy_data); 37 38 return 0; 39 } 40 41 s32 ngbe_init_phy_rtl(struct ngbe_hw *hw) 42 { 43 int i; 44 u16 value = 0; 45 46 /* enable interrupts, only link status change and an done is allowed */ 47 value = RTL_INER_LSC | RTL_INER_ANC; 48 hw->phy.write_reg(hw, RTL_INER, 0xa42, value); 49 50 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 51 52 for (i = 0; i < 15; i++) { 53 if (!rd32m(hw, NGBE_STAT, 54 NGBE_STAT_GPHY_IN_RST(hw->bus.lan_id))) 55 break; 56 57 msec_delay(10); 58 } 59 if (i == 15) { 60 DEBUGOUT("GPhy reset exceeds maximum times.\n"); 61 return NGBE_ERR_PHY_TIMEOUT; 62 } 63 64 for (i = 0; i < 1000; i++) { 65 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 66 if (value & RTL_INSR_ACCESS) 67 break; 68 } 69 70 hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EFUSE); 71 for (i = 0; i < 1000; i++) { 72 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 73 if (value & RTL_INSR_ACCESS) 74 break; 75 } 76 if (i == 1000) 77 return NGBE_ERR_PHY_TIMEOUT; 78 79 hw->phy.write_reg(hw, RTL_SCR, 0xa46, RTL_SCR_EXTINI); 80 for (i = 0; i < 1000; i++) { 81 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 82 if (value & RTL_INSR_ACCESS) 83 break; 84 } 85 if (i == 1000) 86 return NGBE_ERR_PHY_TIMEOUT; 87 88 for (i = 0; i < 1000; i++) { 89 hw->phy.read_reg(hw, RTL_GSR, 0xa42, &value); 90 if ((value & RTL_GSR_ST) == RTL_GSR_ST_LANON) 91 break; 92 } 93 if (i == 1000) 94 return NGBE_ERR_PHY_TIMEOUT; 95 96 return 0; 97 } 98 99 /** 100 * ngbe_setup_phy_link_rtl - Set and restart auto-neg 101 * @hw: pointer to hardware structure 102 * 103 * Restart auto-negotiation and PHY and waits for completion. 104 **/ 105 s32 ngbe_setup_phy_link_rtl(struct ngbe_hw *hw, 106 u32 speed, bool autoneg_wait_to_complete) 107 { 108 u16 autoneg_reg = NGBE_MII_AUTONEG_REG; 109 u16 value = 0; 110 111 DEBUGFUNC("ngbe_setup_phy_link_rtl"); 112 113 UNREFERENCED_PARAMETER(autoneg_wait_to_complete); 114 115 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg); 116 117 if (!hw->mac.autoneg) { 118 hw->phy.reset_hw(hw); 119 120 switch (speed) { 121 case NGBE_LINK_SPEED_1GB_FULL: 122 value = RTL_BMCR_SPEED_SELECT1; 123 break; 124 case NGBE_LINK_SPEED_100M_FULL: 125 value = RTL_BMCR_SPEED_SELECT0; 126 break; 127 case NGBE_LINK_SPEED_10M_FULL: 128 value = 0; 129 break; 130 default: 131 value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0; 132 DEBUGOUT("unknown speed = 0x%x.\n", speed); 133 break; 134 } 135 /* duplex full */ 136 value |= RTL_BMCR_DUPLEX; 137 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value); 138 139 goto skip_an; 140 } 141 142 /* 143 * Clear autoneg_advertised and set new values based on input link 144 * speed. 145 */ 146 if (speed) { 147 hw->phy.autoneg_advertised = 0; 148 149 if (speed & NGBE_LINK_SPEED_1GB_FULL) 150 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; 151 152 if (speed & NGBE_LINK_SPEED_100M_FULL) 153 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL; 154 155 if (speed & NGBE_LINK_SPEED_10M_FULL) 156 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL; 157 } 158 159 /* disable 10/100M Half Duplex */ 160 hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg); 161 autoneg_reg &= 0xFF5F; 162 hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg); 163 164 /* set advertise enable according to input speed */ 165 if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) { 166 hw->phy.read_reg(hw, RTL_GBCR, 167 RTL_DEV_ZERO, &autoneg_reg); 168 autoneg_reg &= ~RTL_GBCR_1000F; 169 hw->phy.write_reg(hw, RTL_GBCR, 170 RTL_DEV_ZERO, autoneg_reg); 171 } else { 172 hw->phy.read_reg(hw, RTL_GBCR, 173 RTL_DEV_ZERO, &autoneg_reg); 174 autoneg_reg |= RTL_GBCR_1000F; 175 hw->phy.write_reg(hw, RTL_GBCR, 176 RTL_DEV_ZERO, autoneg_reg); 177 } 178 179 if (!(speed & NGBE_LINK_SPEED_100M_FULL)) { 180 hw->phy.read_reg(hw, RTL_ANAR, 181 RTL_DEV_ZERO, &autoneg_reg); 182 autoneg_reg &= ~RTL_ANAR_100F; 183 autoneg_reg &= ~RTL_ANAR_100H; 184 hw->phy.write_reg(hw, RTL_ANAR, 185 RTL_DEV_ZERO, autoneg_reg); 186 } else { 187 hw->phy.read_reg(hw, RTL_ANAR, 188 RTL_DEV_ZERO, &autoneg_reg); 189 autoneg_reg |= RTL_ANAR_100F; 190 hw->phy.write_reg(hw, RTL_ANAR, 191 RTL_DEV_ZERO, autoneg_reg); 192 } 193 194 if (!(speed & NGBE_LINK_SPEED_10M_FULL)) { 195 hw->phy.read_reg(hw, RTL_ANAR, 196 RTL_DEV_ZERO, &autoneg_reg); 197 autoneg_reg &= ~RTL_ANAR_10F; 198 autoneg_reg &= ~RTL_ANAR_10H; 199 hw->phy.write_reg(hw, RTL_ANAR, 200 RTL_DEV_ZERO, autoneg_reg); 201 } else { 202 hw->phy.read_reg(hw, RTL_ANAR, 203 RTL_DEV_ZERO, &autoneg_reg); 204 autoneg_reg |= RTL_ANAR_10F; 205 hw->phy.write_reg(hw, RTL_ANAR, 206 RTL_DEV_ZERO, autoneg_reg); 207 } 208 209 /* restart AN and wait AN done interrupt */ 210 autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE; 211 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg); 212 213 skip_an: 214 autoneg_reg = 0x205B; 215 hw->phy.write_reg(hw, RTL_LCR, 0xd04, autoneg_reg); 216 hw->phy.write_reg(hw, RTL_EEELCR, 0xd04, 0); 217 218 hw->phy.read_reg(hw, RTL_LPCR, 0xd04, &autoneg_reg); 219 autoneg_reg = autoneg_reg & 0xFFFC; 220 /* act led blinking mode set to 60ms */ 221 autoneg_reg |= 0x2; 222 hw->phy.write_reg(hw, RTL_LPCR, 0xd04, autoneg_reg); 223 224 return 0; 225 } 226 227 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw) 228 { 229 u16 value = 0, i; 230 s32 status = 0; 231 232 DEBUGFUNC("ngbe_reset_phy_rtl"); 233 234 value |= RTL_BMCR_RESET; 235 status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value); 236 237 for (i = 0; i < RTL_PHY_RST_WAIT_PERIOD; i++) { 238 status = hw->phy.read_reg(hw, RTL_BMCR, RTL_DEV_ZERO, &value); 239 if (!(value & RTL_BMCR_RESET)) 240 break; 241 msleep(1); 242 } 243 244 if (i == RTL_PHY_RST_WAIT_PERIOD) { 245 DEBUGOUT("PHY reset polling failed to complete.\n"); 246 return NGBE_ERR_RESET_FAILED; 247 } 248 249 return status; 250 } 251 252 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up) 253 { 254 s32 status = 0; 255 u16 phy_link = 0; 256 u16 phy_speed = 0; 257 u16 phy_data = 0; 258 u16 insr = 0; 259 260 DEBUGFUNC("ngbe_check_phy_link_rtl"); 261 262 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr); 263 264 /* Initialize speed and link to default case */ 265 *link_up = false; 266 *speed = NGBE_LINK_SPEED_UNKNOWN; 267 268 /* 269 * Check current speed and link status of the PHY register. 270 * This is a vendor specific register and may have to 271 * be changed for other copper PHYs. 272 */ 273 status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data); 274 phy_link = phy_data & RTL_PHYSR_RTLS; 275 phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP); 276 if (phy_link == RTL_PHYSR_RTLS) { 277 *link_up = true; 278 279 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP)) 280 *speed = NGBE_LINK_SPEED_1GB_FULL; 281 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP)) 282 *speed = NGBE_LINK_SPEED_100M_FULL; 283 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP)) 284 *speed = NGBE_LINK_SPEED_10M_FULL; 285 } 286 287 return status; 288 } 289 290