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_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) 253 { 254 u16 value; 255 s32 status = 0; 256 257 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); 258 value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE; 259 *pause_bit = (u8)(value >> 10); 260 return status; 261 } 262 263 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) 264 { 265 u16 value; 266 s32 status = 0; 267 268 status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 269 270 status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value); 271 value = value & RTL_BMSR_ANC; 272 273 /* if AN complete then check lp adv pause */ 274 status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value); 275 value &= RTL_ANLPAR_LP; 276 *pause_bit = (u8)(value >> 10); 277 return status; 278 } 279 280 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit) 281 { 282 u16 value; 283 s32 status = 0; 284 285 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); 286 value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE); 287 value |= pause_bit; 288 289 status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value); 290 291 return status; 292 } 293 294 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up) 295 { 296 s32 status = 0; 297 u16 phy_link = 0; 298 u16 phy_speed = 0; 299 u16 phy_data = 0; 300 u16 insr = 0; 301 302 DEBUGFUNC("ngbe_check_phy_link_rtl"); 303 304 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr); 305 306 /* Initialize speed and link to default case */ 307 *link_up = false; 308 *speed = NGBE_LINK_SPEED_UNKNOWN; 309 310 /* 311 * Check current speed and link status of the PHY register. 312 * This is a vendor specific register and may have to 313 * be changed for other copper PHYs. 314 */ 315 status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data); 316 phy_link = phy_data & RTL_PHYSR_RTLS; 317 phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP); 318 if (phy_link == RTL_PHYSR_RTLS) { 319 *link_up = true; 320 321 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP)) 322 *speed = NGBE_LINK_SPEED_1GB_FULL; 323 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP)) 324 *speed = NGBE_LINK_SPEED_100M_FULL; 325 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP)) 326 *speed = NGBE_LINK_SPEED_10M_FULL; 327 } 328 329 return status; 330 } 331 332