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