1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018-2021 Beijing WangXun Technology Co., Ltd. 3 * Copyright(c) 2010-2017 Intel Corporation 4 */ 5 6 #include "ngbe_hw.h" 7 #include "ngbe_phy.h" 8 9 s32 ngbe_mdi_map_register(mdi_reg_t *reg, mdi_reg_22_t *reg22) 10 { 11 bool match = 1; 12 switch (reg->device_type) { 13 case NGBE_MD_DEV_PMA_PMD: 14 switch (reg->addr) { 15 case NGBE_MD_PHY_ID_HIGH: 16 case NGBE_MD_PHY_ID_LOW: 17 reg22->page = 0; 18 reg22->addr = reg->addr; 19 reg22->device_type = 0; 20 break; 21 default: 22 match = 0; 23 } 24 break; 25 default: 26 match = 0; 27 break; 28 } 29 30 if (!match) { 31 reg22->page = reg->device_type; 32 reg22->device_type = reg->device_type; 33 reg22->addr = reg->addr; 34 } 35 36 return 0; 37 } 38 39 /** 40 * ngbe_probe_phy - Identify a single address for a PHY 41 * @hw: pointer to hardware structure 42 * @phy_addr: PHY address to probe 43 * 44 * Returns true if PHY found 45 */ 46 static bool ngbe_probe_phy(struct ngbe_hw *hw, u16 phy_addr) 47 { 48 if (!ngbe_validate_phy_addr(hw, phy_addr)) { 49 DEBUGOUT("Unable to validate PHY address 0x%04X\n", 50 phy_addr); 51 return false; 52 } 53 54 if (ngbe_get_phy_id(hw)) 55 return false; 56 57 if (ngbe_get_phy_type_from_id(hw)) 58 return false; 59 60 return true; 61 } 62 63 /** 64 * ngbe_identify_phy - Get physical layer module 65 * @hw: pointer to hardware structure 66 * 67 * Determines the physical layer module found on the current adapter. 68 **/ 69 s32 ngbe_identify_phy(struct ngbe_hw *hw) 70 { 71 s32 err = NGBE_ERR_PHY_ADDR_INVALID; 72 u16 phy_addr; 73 74 DEBUGFUNC("ngbe_identify_phy"); 75 76 if (hw->phy.type != ngbe_phy_unknown) 77 return 0; 78 79 /* select clause22 */ 80 wr32(hw, NGBE_MDIOMODE, NGBE_MDIOMODE_MASK); 81 82 for (phy_addr = 0; phy_addr < NGBE_MAX_PHY_ADDR; phy_addr++) { 83 if (ngbe_probe_phy(hw, phy_addr)) { 84 err = 0; 85 break; 86 } 87 } 88 89 return err; 90 } 91 92 /** 93 * ngbe_check_reset_blocked - check status of MNG FW veto bit 94 * @hw: pointer to the hardware structure 95 * 96 * This function checks the STAT.MNGVETO bit to see if there are 97 * any constraints on link from manageability. For MAC's that don't 98 * have this bit just return faluse since the link can not be blocked 99 * via this method. 100 **/ 101 s32 ngbe_check_reset_blocked(struct ngbe_hw *hw) 102 { 103 u32 mmngc; 104 105 DEBUGFUNC("ngbe_check_reset_blocked"); 106 107 mmngc = rd32(hw, NGBE_STAT); 108 if (mmngc & NGBE_STAT_MNGVETO) { 109 DEBUGOUT("MNG_VETO bit detected.\n"); 110 return true; 111 } 112 113 return false; 114 } 115 116 /** 117 * ngbe_validate_phy_addr - Determines phy address is valid 118 * @hw: pointer to hardware structure 119 * @phy_addr: PHY address 120 * 121 **/ 122 bool ngbe_validate_phy_addr(struct ngbe_hw *hw, u32 phy_addr) 123 { 124 u16 phy_id = 0; 125 bool valid = false; 126 127 DEBUGFUNC("ngbe_validate_phy_addr"); 128 129 if (hw->sub_device_id == NGBE_SUB_DEV_ID_EM_YT8521S_SFP) 130 return true; 131 132 hw->phy.addr = phy_addr; 133 hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH, 134 NGBE_MD_DEV_PMA_PMD, &phy_id); 135 136 if (phy_id != 0xFFFF && phy_id != 0x0) 137 valid = true; 138 139 DEBUGOUT("PHY ID HIGH is 0x%04X\n", phy_id); 140 141 return valid; 142 } 143 144 /** 145 * ngbe_get_phy_id - Get the phy ID 146 * @hw: pointer to hardware structure 147 * 148 **/ 149 s32 ngbe_get_phy_id(struct ngbe_hw *hw) 150 { 151 u32 err; 152 u16 phy_id_high = 0; 153 u16 phy_id_low = 0; 154 155 DEBUGFUNC("ngbe_get_phy_id"); 156 157 err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_HIGH, 158 NGBE_MD_DEV_PMA_PMD, 159 &phy_id_high); 160 hw->phy.id = (u32)(phy_id_high << 16); 161 162 err = hw->phy.read_reg(hw, NGBE_MD_PHY_ID_LOW, 163 NGBE_MD_DEV_PMA_PMD, 164 &phy_id_low); 165 hw->phy.id |= (u32)(phy_id_low & NGBE_PHY_REVISION_MASK); 166 hw->phy.revision = (u32)(phy_id_low & ~NGBE_PHY_REVISION_MASK); 167 168 DEBUGOUT("PHY_ID_HIGH 0x%04X, PHY_ID_LOW 0x%04X\n", 169 phy_id_high, phy_id_low); 170 171 return err; 172 } 173 174 /** 175 * ngbe_get_phy_type_from_id - Get the phy type 176 * 177 **/ 178 s32 ngbe_get_phy_type_from_id(struct ngbe_hw *hw) 179 { 180 s32 status = 0; 181 182 DEBUGFUNC("ngbe_get_phy_type_from_id"); 183 184 switch (hw->phy.id) { 185 case NGBE_PHYID_RTL: 186 hw->phy.type = ngbe_phy_rtl; 187 break; 188 case NGBE_PHYID_MVL: 189 if (hw->phy.media_type == ngbe_media_type_fiber) 190 hw->phy.type = ngbe_phy_mvl_sfi; 191 else if (hw->phy.media_type == ngbe_media_type_copper) 192 hw->phy.type = ngbe_phy_mvl; 193 else 194 status = ngbe_check_phy_mode_mvl(hw); 195 break; 196 case NGBE_PHYID_YT: 197 if (hw->phy.media_type == ngbe_media_type_fiber) 198 hw->phy.type = ngbe_phy_yt8521s_sfi; 199 else 200 hw->phy.type = ngbe_phy_yt8521s; 201 break; 202 default: 203 hw->phy.type = ngbe_phy_unknown; 204 status = NGBE_ERR_DEVICE_NOT_SUPPORTED; 205 break; 206 } 207 208 return status; 209 } 210 211 /** 212 * ngbe_reset_phy - Performs a PHY reset 213 * @hw: pointer to hardware structure 214 **/ 215 s32 ngbe_reset_phy(struct ngbe_hw *hw) 216 { 217 s32 err = 0; 218 219 DEBUGFUNC("ngbe_reset_phy"); 220 221 if (hw->phy.type == ngbe_phy_unknown) 222 err = ngbe_identify_phy(hw); 223 224 if (err != 0 || hw->phy.type == ngbe_phy_none) 225 return err; 226 227 /* Don't reset PHY if it's shut down due to overtemp. */ 228 if (hw->mac.check_overtemp(hw) == NGBE_ERR_OVERTEMP) 229 return err; 230 231 /* Blocked by MNG FW so bail */ 232 if (ngbe_check_reset_blocked(hw)) 233 return err; 234 235 switch (hw->phy.type) { 236 case ngbe_phy_rtl: 237 err = ngbe_reset_phy_rtl(hw); 238 break; 239 case ngbe_phy_mvl: 240 case ngbe_phy_mvl_sfi: 241 err = ngbe_reset_phy_mvl(hw); 242 break; 243 case ngbe_phy_yt8521s: 244 case ngbe_phy_yt8521s_sfi: 245 err = ngbe_reset_phy_yt(hw); 246 break; 247 default: 248 break; 249 } 250 251 return err; 252 } 253 254 /** 255 * ngbe_read_phy_mdi - Reads a value from a specified PHY register without 256 * the SWFW lock 257 * @hw: pointer to hardware structure 258 * @reg_addr: 32 bit address of PHY register to read 259 * @device_type: 5 bit device type 260 * @phy_data: Pointer to read data from PHY register 261 **/ 262 s32 ngbe_read_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr, u32 device_type, 263 u16 *phy_data) 264 { 265 u32 command, data; 266 267 /* Setup and write the address cycle command */ 268 command = NGBE_MDIOSCA_REG(reg_addr) | 269 NGBE_MDIOSCA_DEV(device_type) | 270 NGBE_MDIOSCA_PORT(hw->phy.addr); 271 wr32(hw, NGBE_MDIOSCA, command); 272 273 command = NGBE_MDIOSCD_CMD_READ | 274 NGBE_MDIOSCD_BUSY | 275 NGBE_MDIOSCD_CLOCK(6); 276 wr32(hw, NGBE_MDIOSCD, command); 277 278 /* 279 * Check every 10 usec to see if the address cycle completed. 280 * The MDI Command bit will clear when the operation is 281 * complete 282 */ 283 if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY, 284 0, NULL, 100, 100)) { 285 DEBUGOUT("PHY address command did not complete\n"); 286 return NGBE_ERR_PHY; 287 } 288 289 data = rd32(hw, NGBE_MDIOSCD); 290 *phy_data = (u16)NGBE_MDIOSCD_DAT_R(data); 291 292 return 0; 293 } 294 295 /** 296 * ngbe_read_phy_reg - Reads a value from a specified PHY register 297 * using the SWFW lock - this function is needed in most cases 298 * @hw: pointer to hardware structure 299 * @reg_addr: 32 bit address of PHY register to read 300 * @device_type: 5 bit device type 301 * @phy_data: Pointer to read data from PHY register 302 **/ 303 s32 ngbe_read_phy_reg(struct ngbe_hw *hw, u32 reg_addr, 304 u32 device_type, u16 *phy_data) 305 { 306 s32 err; 307 u32 gssr = hw->phy.phy_semaphore_mask; 308 309 DEBUGFUNC("ngbe_read_phy_reg"); 310 311 if (hw->mac.acquire_swfw_sync(hw, gssr)) 312 return NGBE_ERR_SWFW_SYNC; 313 314 err = hw->phy.read_reg_unlocked(hw, reg_addr, device_type, 315 phy_data); 316 317 hw->mac.release_swfw_sync(hw, gssr); 318 319 return err; 320 } 321 322 /** 323 * ngbe_write_phy_reg_mdi - Writes a value to specified PHY register 324 * without SWFW lock 325 * @hw: pointer to hardware structure 326 * @reg_addr: 32 bit PHY register to write 327 * @device_type: 5 bit device type 328 * @phy_data: Data to write to the PHY register 329 **/ 330 s32 ngbe_write_phy_reg_mdi(struct ngbe_hw *hw, u32 reg_addr, 331 u32 device_type, u16 phy_data) 332 { 333 u32 command; 334 335 /* write command */ 336 command = NGBE_MDIOSCA_REG(reg_addr) | 337 NGBE_MDIOSCA_DEV(device_type) | 338 NGBE_MDIOSCA_PORT(hw->phy.addr); 339 wr32(hw, NGBE_MDIOSCA, command); 340 341 command = NGBE_MDIOSCD_CMD_WRITE | 342 NGBE_MDIOSCD_DAT(phy_data) | 343 NGBE_MDIOSCD_BUSY | 344 NGBE_MDIOSCD_CLOCK(6); 345 wr32(hw, NGBE_MDIOSCD, command); 346 347 /* wait for completion */ 348 if (!po32m(hw, NGBE_MDIOSCD, NGBE_MDIOSCD_BUSY, 349 0, NULL, 100, 100)) { 350 TLOG_DEBUG("PHY write cmd didn't complete\n"); 351 return NGBE_ERR_PHY; 352 } 353 354 return 0; 355 } 356 357 /** 358 * ngbe_write_phy_reg - Writes a value to specified PHY register 359 * using SWFW lock- this function is needed in most cases 360 * @hw: pointer to hardware structure 361 * @reg_addr: 32 bit PHY register to write 362 * @device_type: 5 bit device type 363 * @phy_data: Data to write to the PHY register 364 **/ 365 s32 ngbe_write_phy_reg(struct ngbe_hw *hw, u32 reg_addr, 366 u32 device_type, u16 phy_data) 367 { 368 s32 err; 369 u32 gssr = hw->phy.phy_semaphore_mask; 370 371 DEBUGFUNC("ngbe_write_phy_reg"); 372 373 if (hw->mac.acquire_swfw_sync(hw, gssr)) 374 err = NGBE_ERR_SWFW_SYNC; 375 376 err = hw->phy.write_reg_unlocked(hw, reg_addr, device_type, 377 phy_data); 378 379 hw->mac.release_swfw_sync(hw, gssr); 380 381 return err; 382 } 383 384 /** 385 * ngbe_init_phy - PHY specific init 386 * @hw: pointer to hardware structure 387 * 388 * Initialize any function pointers that were not able to be 389 * set during init_shared_code because the PHY type was 390 * not known. 391 * 392 **/ 393 s32 ngbe_init_phy(struct ngbe_hw *hw) 394 { 395 struct ngbe_phy_info *phy = &hw->phy; 396 s32 err = 0; 397 398 DEBUGFUNC("ngbe_init_phy"); 399 400 hw->phy.addr = 0; 401 402 switch (hw->sub_device_id) { 403 case NGBE_SUB_DEV_ID_EM_RTL_SGMII: 404 case NGBE_SUB_DEV_ID_EM_RTL_YT8521S_SFP: 405 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_rtl; 406 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_rtl; 407 break; 408 case NGBE_SUB_DEV_ID_EM_MVL_RGMII: 409 case NGBE_SUB_DEV_ID_EM_MVL_SFP: 410 case NGBE_SUB_DEV_ID_EM_MVL_MIX: 411 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_mvl; 412 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_mvl; 413 break; 414 case NGBE_SUB_DEV_ID_EM_YT8521S_SFP: 415 hw->phy.read_reg_unlocked = ngbe_read_phy_reg_yt; 416 hw->phy.write_reg_unlocked = ngbe_write_phy_reg_yt; 417 break; 418 default: 419 break; 420 } 421 422 hw->phy.phy_semaphore_mask = NGBE_MNGSEM_SWPHY; 423 424 /* Identify the PHY */ 425 err = phy->identify(hw); 426 if (err == NGBE_ERR_PHY_ADDR_INVALID) 427 goto init_phy_ops_out; 428 429 /* Set necessary function pointers based on PHY type */ 430 switch (hw->phy.type) { 431 case ngbe_phy_rtl: 432 hw->phy.init_hw = ngbe_init_phy_rtl; 433 hw->phy.check_link = ngbe_check_phy_link_rtl; 434 hw->phy.setup_link = ngbe_setup_phy_link_rtl; 435 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_rtl; 436 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_rtl; 437 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_rtl; 438 break; 439 case ngbe_phy_mvl: 440 case ngbe_phy_mvl_sfi: 441 hw->phy.init_hw = ngbe_init_phy_mvl; 442 hw->phy.check_link = ngbe_check_phy_link_mvl; 443 hw->phy.setup_link = ngbe_setup_phy_link_mvl; 444 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_mvl; 445 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_mvl; 446 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_mvl; 447 break; 448 case ngbe_phy_yt8521s: 449 case ngbe_phy_yt8521s_sfi: 450 hw->phy.init_hw = ngbe_init_phy_yt; 451 hw->phy.check_link = ngbe_check_phy_link_yt; 452 hw->phy.setup_link = ngbe_setup_phy_link_yt; 453 hw->phy.get_adv_pause = ngbe_get_phy_advertised_pause_yt; 454 hw->phy.get_lp_adv_pause = ngbe_get_phy_lp_advertised_pause_yt; 455 hw->phy.set_pause_adv = ngbe_set_phy_pause_adv_yt; 456 default: 457 break; 458 } 459 460 init_phy_ops_out: 461 return err; 462 } 463 464