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."); 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."); 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."); 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."); 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."); 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 UNREFERENCED_PARAMETER(autoneg_wait_to_complete); 144 145 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &autoneg_reg); 146 147 if (!hw->mac.autoneg) { 148 hw->phy.reset_hw(hw); 149 150 switch (speed) { 151 case NGBE_LINK_SPEED_1GB_FULL: 152 value = RTL_BMCR_SPEED_SELECT1; 153 break; 154 case NGBE_LINK_SPEED_100M_FULL: 155 value = RTL_BMCR_SPEED_SELECT0; 156 break; 157 case NGBE_LINK_SPEED_10M_FULL: 158 value = 0; 159 break; 160 default: 161 value = RTL_BMCR_SPEED_SELECT1 | RTL_BMCR_SPEED_SELECT0; 162 DEBUGOUT("unknown speed = 0x%x.", speed); 163 break; 164 } 165 /* duplex full */ 166 value |= RTL_BMCR_DUPLEX; 167 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value); 168 169 goto skip_an; 170 } 171 172 /* 173 * Clear autoneg_advertised and set new values based on input link 174 * speed. 175 */ 176 if (speed) { 177 hw->phy.autoneg_advertised = 0; 178 179 if (speed & NGBE_LINK_SPEED_1GB_FULL) 180 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_1GB_FULL; 181 182 if (speed & NGBE_LINK_SPEED_100M_FULL) 183 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_100M_FULL; 184 185 if (speed & NGBE_LINK_SPEED_10M_FULL) 186 hw->phy.autoneg_advertised |= NGBE_LINK_SPEED_10M_FULL; 187 } 188 189 /* disable 10/100M Half Duplex */ 190 hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &autoneg_reg); 191 autoneg_reg &= 0xFF5F; 192 hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, autoneg_reg); 193 194 /* set advertise enable according to input speed */ 195 if (!(speed & NGBE_LINK_SPEED_1GB_FULL)) { 196 hw->phy.read_reg(hw, RTL_GBCR, 197 RTL_DEV_ZERO, &autoneg_reg); 198 autoneg_reg &= ~RTL_GBCR_1000F; 199 hw->phy.write_reg(hw, RTL_GBCR, 200 RTL_DEV_ZERO, autoneg_reg); 201 } else { 202 hw->phy.read_reg(hw, RTL_GBCR, 203 RTL_DEV_ZERO, &autoneg_reg); 204 autoneg_reg |= RTL_GBCR_1000F; 205 hw->phy.write_reg(hw, RTL_GBCR, 206 RTL_DEV_ZERO, autoneg_reg); 207 } 208 209 if (!(speed & NGBE_LINK_SPEED_100M_FULL)) { 210 hw->phy.read_reg(hw, RTL_ANAR, 211 RTL_DEV_ZERO, &autoneg_reg); 212 autoneg_reg &= ~RTL_ANAR_100F; 213 autoneg_reg &= ~RTL_ANAR_100H; 214 hw->phy.write_reg(hw, RTL_ANAR, 215 RTL_DEV_ZERO, autoneg_reg); 216 } else { 217 hw->phy.read_reg(hw, RTL_ANAR, 218 RTL_DEV_ZERO, &autoneg_reg); 219 autoneg_reg |= RTL_ANAR_100F; 220 hw->phy.write_reg(hw, RTL_ANAR, 221 RTL_DEV_ZERO, autoneg_reg); 222 } 223 224 if (!(speed & NGBE_LINK_SPEED_10M_FULL)) { 225 hw->phy.read_reg(hw, RTL_ANAR, 226 RTL_DEV_ZERO, &autoneg_reg); 227 autoneg_reg &= ~RTL_ANAR_10F; 228 autoneg_reg &= ~RTL_ANAR_10H; 229 hw->phy.write_reg(hw, RTL_ANAR, 230 RTL_DEV_ZERO, autoneg_reg); 231 } else { 232 hw->phy.read_reg(hw, RTL_ANAR, 233 RTL_DEV_ZERO, &autoneg_reg); 234 autoneg_reg |= RTL_ANAR_10F; 235 hw->phy.write_reg(hw, RTL_ANAR, 236 RTL_DEV_ZERO, autoneg_reg); 237 } 238 239 /* restart AN and wait AN done interrupt */ 240 autoneg_reg = RTL_BMCR_RESTART_AN | RTL_BMCR_ANE; 241 hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, autoneg_reg); 242 243 skip_an: 244 ngbe_phy_led_ctrl_rtl(hw); 245 246 return 0; 247 } 248 249 s32 ngbe_reset_phy_rtl(struct ngbe_hw *hw) 250 { 251 u16 value = 0; 252 s32 status = 0; 253 254 value |= RTL_BMCR_RESET; 255 status = hw->phy.write_reg(hw, RTL_BMCR, RTL_DEV_ZERO, value); 256 257 msec_delay(5); 258 259 return status; 260 } 261 262 s32 ngbe_get_phy_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) 263 { 264 u16 value; 265 s32 status = 0; 266 267 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); 268 value &= RTL_ANAR_APAUSE | RTL_ANAR_PAUSE; 269 *pause_bit = (u8)(value >> 10); 270 return status; 271 } 272 273 s32 ngbe_get_phy_lp_advertised_pause_rtl(struct ngbe_hw *hw, u8 *pause_bit) 274 { 275 u16 value; 276 s32 status = 0; 277 278 status = hw->phy.read_reg(hw, RTL_INSR, 0xa43, &value); 279 280 status = hw->phy.read_reg(hw, RTL_BMSR, RTL_DEV_ZERO, &value); 281 value = value & RTL_BMSR_ANC; 282 283 /* if AN complete then check lp adv pause */ 284 status = hw->phy.read_reg(hw, RTL_ANLPAR, RTL_DEV_ZERO, &value); 285 value &= RTL_ANLPAR_LP; 286 *pause_bit = (u8)(value >> 10); 287 return status; 288 } 289 290 s32 ngbe_set_phy_pause_adv_rtl(struct ngbe_hw *hw, u16 pause_bit) 291 { 292 u16 value; 293 s32 status = 0; 294 295 status = hw->phy.read_reg(hw, RTL_ANAR, RTL_DEV_ZERO, &value); 296 value &= ~(RTL_ANAR_APAUSE | RTL_ANAR_PAUSE); 297 value |= pause_bit; 298 299 status = hw->phy.write_reg(hw, RTL_ANAR, RTL_DEV_ZERO, value); 300 301 return status; 302 } 303 304 s32 ngbe_check_phy_link_rtl(struct ngbe_hw *hw, u32 *speed, bool *link_up) 305 { 306 s32 status = 0; 307 u16 phy_link = 0; 308 u16 phy_speed = 0; 309 u16 phy_data = 0; 310 u16 insr = 0; 311 312 hw->phy.read_reg(hw, RTL_INSR, 0xa43, &insr); 313 314 /* Initialize speed and link to default case */ 315 *link_up = false; 316 *speed = NGBE_LINK_SPEED_UNKNOWN; 317 318 /* 319 * Check current speed and link status of the PHY register. 320 * This is a vendor specific register and may have to 321 * be changed for other copper PHYs. 322 */ 323 status = hw->phy.read_reg(hw, RTL_PHYSR, 0xa43, &phy_data); 324 phy_link = phy_data & RTL_PHYSR_RTLS; 325 phy_speed = phy_data & (RTL_PHYSR_SPEED_MASK | RTL_PHYSR_DP); 326 if (phy_link == RTL_PHYSR_RTLS) { 327 *link_up = true; 328 329 if (phy_speed == (RTL_PHYSR_SPEED_1000M | RTL_PHYSR_DP)) 330 *speed = NGBE_LINK_SPEED_1GB_FULL; 331 else if (phy_speed == (RTL_PHYSR_SPEED_100M | RTL_PHYSR_DP)) 332 *speed = NGBE_LINK_SPEED_100M_FULL; 333 else if (phy_speed == (RTL_PHYSR_SPEED_10M | RTL_PHYSR_DP)) 334 *speed = NGBE_LINK_SPEED_10M_FULL; 335 } 336 337 return status; 338 } 339 340