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