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