phy8072.c (70555B)
1 2 /* 3 * 4 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 5 * 6 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 7 * 8 * File: phy8072.c 9 * Purpose: Phys Driver support for Broadcom 8072 Serial 10Gig 10 * transceiver with XAUI interface. 11 */ 12 13 #include <sal/types.h> 14 #include <shared/bsl.h> 15 #include <soc/drv.h> 16 #include <soc/debug.h> 17 #include <soc/error.h> 18 #include <soc/phyreg.h> 19 20 #include <soc/phy.h> 21 #include <soc/phy/phyctrl.h> 22 #include <soc/phy/drv.h> 23 24 #include "phydefs.h" /* Must include before other phy related includes */ 25 26 #if defined(INCLUDE_PHY_8072) 27 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 28 #include "phyident.h" 29 #include "phyreg.h" 30 #include "phynull.h" 31 #include "phyxehg.h" 32 #include "phy8072.h" 33 34 #define PHY_ID1_8072 0x6035 35 #define PHY_ID1_8073 0x6036 36 #define PHY_ID1_8074 0x6036 37 #define PHY_8073_A0 0x0000 38 #define PHY_8073_A1 0x0001 39 40 #define PHY_8072_PMA_PMD_LOOPBACK 1 41 #if 0 42 #define PHY_8072_PCS_LOOPBACK 1 43 #define PHY_8072_SYSTEM_LOOPBACK 1 44 #define PHY_8072_XAUI_LOOPBACK 1 45 #endif 46 47 #define APPLY_SNR_PATCH(dev, ver) \ 48 ((dev == PHY_8073_A1) && (ver == 0x0102)) || \ 49 ((dev == PHY_8073_A0) && ((ver == 0x0101) || (ver == 0x0102))) 50 51 /* 52 * SPI-ROM Program related defs 53 */ 54 #define SPI_CTRL_1_L 0xC000 55 #define SPI_CTRL_1_H 0xC002 56 #define SPI_CTRL_2_L 0xC400 57 #define SPI_CTRL_2_H 0xC402 58 #define SPI_TXFIFO 0xD000 59 #define SPI_RXFIFO 0xD400 60 #define WR_CPU_CTRL_REGS 0x11 61 #define RD_CPU_CTRL_REGS 0xEE 62 #define WR_CPU_CTRL_FIFO 0x66 63 /* 64 * SPI Controller Commands(Messages). 65 */ 66 #define MSGTYPE_HWR 0x40 67 #define MSGTYPE_HRD 0x80 68 #define WRSR_OPCODE 0x01 69 #define WR_OPCODE 0x02 70 #define WRDI_OPCODE 0x04 71 #define RDSR_OPCODE 0x05 72 #define WREN_OPCODE 0x06 73 #define WR_BLOCK_SIZE 0x40 74 #define TOTAL_WR_BYTE 0x4000 75 76 #define WR_TIMEOUT 1000000 77 static int write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, uint16 * rddata); 78 79 STATIC int phy_8072_ability_local_get(int, soc_port_t, soc_port_ability_t *); 80 STATIC int phy_8072_speed_get(int, soc_port_t, int *); 81 STATIC int phy_8072_ability_advert_set(int, soc_port_t, soc_port_ability_t *); 82 STATIC int phy_8072_an_get(int, soc_port_t, int *, int *); 83 84 85 STATIC int 86 _8072_rom_load(int unit,phy_ctrl_t * pc,int phy_id1) 87 { 88 if (phy_id1 == PHY_ID1_8072) { 89 /* reset the device */ 90 SOC_IF_ERROR_RETURN 91 (MODIFY_PHY8072_PMA_PMD_CTRLr(unit, pc, 92 MII_CTRL_RESET, MII_CTRL_RESET)); 93 94 /* Wait 200ms after PCB reboot, for internal ROM load to finish */ 95 sal_usleep(200000); 96 97 SOC_IF_ERROR_RETURN 98 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xca85, 0x0001)); 99 sal_usleep(1000); 100 SOC_IF_ERROR_RETURN 101 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 102 0x0188)); 103 sal_usleep(1000); 104 SOC_IF_ERROR_RETURN 105 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 106 0x018a)); 107 sal_usleep(1000); 108 SOC_IF_ERROR_RETURN 109 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 110 0x0188)); 111 /* 112 * Wait for atleast 100ms for code to download via SPI port 113 */ 114 sal_usleep(200000); 115 SOC_IF_ERROR_RETURN 116 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xca85, 0x0000)); 117 sal_usleep(1000); 118 119 } else if (phy_id1 == PHY_ID1_8073) { 120 /* reset the device */ 121 SOC_IF_ERROR_RETURN 122 (MODIFY_PHY8072_PMA_PMD_CTRLr(unit, pc, 123 MII_CTRL_RESET, MII_CTRL_RESET)); 124 125 /* no delay is needed for 8073 per chip designer*/ 126 SOC_IF_ERROR_RETURN 127 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 128 0x0001)); 129 SOC_IF_ERROR_RETURN 130 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 131 0x008C)); 132 SOC_IF_ERROR_RETURN 133 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA85, 0x0001)); 134 SOC_IF_ERROR_RETURN 135 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 136 0x018A)); 137 SOC_IF_ERROR_RETURN 138 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN_CTRL_STAT_REG, 139 0x0188)); 140 141 /* 142 * Wait for atleast 100ms for code to download via SPI port 143 */ 144 sal_usleep(200000); 145 SOC_IF_ERROR_RETURN 146 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xca85, 0x0000)); 147 sal_usleep(1000); 148 } 149 return SOC_E_NONE; 150 151 } 152 153 STATIC int 154 _8074_rom_load(int unit,phy_ctrl_t * pc,int phy_id1) 155 { 156 uint16 phy_addr; 157 int i; 158 159 phy_addr = pc->phy_id & 0xfffc; 160 for(i = 0; i < 4; i++) { 161 /* Disable SPI for all ports, return value ignored on purpose */ 162 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc843), 0x000f); 163 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc840), 0x000C); 164 165 /* Set bit SPI Download (15), SER Boot (14) And SPI Port Enable (0) In C848, SPI_PORT_CTRL */ 166 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc848), 0xC0F1); 167 } 168 169 /* Place Micro in reset */ 170 SOC_IF_ERROR_RETURN 171 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xca10, 0x018f)); 172 173 /* Enable SPI */ 174 SOC_IF_ERROR_RETURN 175 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xc843, 0x0000)); 176 SOC_IF_ERROR_RETURN 177 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xc840, 0x0000)); 178 179 /* Remove M8051 resets */ 180 SOC_IF_ERROR_RETURN 181 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xca10, 0x0188)); 182 183 /* The rest is moved outside this routine. */ 184 return SOC_E_NONE; 185 } 186 187 STATIC int 188 _8073_A0_xaui_check(int unit, int port) 189 { 190 uint8 count; 191 uint16 data16; 192 phy_ctrl_t *pc; 193 soc_timeout_t to; 194 sal_usecs_t start, end; 195 pc = EXT_PHY_SW_STATE(unit, port); 196 197 /* 198 * Get the Chip revision or chip id 199 * XAUI Workaround is not needed for Rev A1 and 8074 device 200 */ 201 202 SOC_IF_ERROR_RETURN 203 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_CHIP_REV_REG, &data16)); 204 if (data16 == PHY_8073_A1) { 205 return SOC_E_NONE; 206 } 207 208 SOC_IF_ERROR_RETURN 209 (READ_PHY8072_PMA_PMD_REG(unit,pc,0xC802,&data16)); 210 if ( data16 == 0x8074) { 211 return SOC_E_NONE; 212 } 213 214 SOC_IF_ERROR_RETURN 215 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_USR_STATUS_REG, &data16)); 216 217 if (!PMAD_STATUS_AN_10G(data16)) { 218 return SOC_E_NONE; 219 } 220 221 start = sal_time_usecs(); 222 LOG_INFO(BSL_LS_SOC_PHY, 223 (BSL_META_U(unit, 224 "xaui w/a in progress \n"))); 225 for (count = 0; count < 12; count++) { 226 soc_timeout_init(&to, 5000000, 0); 227 LOG_INFO(BSL_LS_SOC_PHY, 228 (BSL_META_U(unit, 229 "."))); 230 do { 231 SOC_IF_ERROR_RETURN 232 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_USR_STATUS_REG, 233 &data16)); 234 if (!(data16 & PMAD_STATUS_1G_LINKDOWN) || 235 !(data16 & PMAD_STATUS_2p5G_LINKDOWN)) { 236 return SOC_E_NONE; 237 } else if (!(data16 & PMAD_STATUS_10G_LINKDOWN)) { 238 SOC_IF_ERROR_RETURN 239 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0xC841, &data16)); 240 if (data16 & (1<<15)) { 241 end = sal_time_usecs(); 242 LOG_INFO(BSL_LS_SOC_PHY, 243 (BSL_META_U(unit, 244 "\nxaui w/a completed successfully u=%d,p=%d" 245 " time taken = %d\n"), unit, port, 246 SAL_USECS_SUB(end, start))); 247 return SOC_E_NONE; 248 } 249 } 250 } while (!soc_timeout_check(&to)); 251 } 252 253 LOG_WARN(BSL_LS_SOC_PHY, 254 (BSL_META_U(unit, 255 "\nWarning! : u=%d, p=%d:" 256 "8073A0 XAUI Work Around may not have completed\n"), unit, port)); 257 258 SOC_IF_ERROR_RETURN /* Restart AN ..HP*/ 259 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, AN_ENABLE|AN_RESTART)); 260 261 return SOC_E_NONE; 262 } 263 264 /* Function: 265 * phy_8072_init 266 * Purpose: 267 * Initialize 8072 phys 268 * Parameters: 269 * unit - StrataSwitch unit #. 270 * port - StrataSwitch port #. 271 * Returns: 272 * SOC_E_NONE 273 */ 274 275 STATIC int 276 phy_8072_init(int unit, soc_port_t port) 277 { 278 soc_timeout_t to; 279 int rv; 280 uint16 data16; 281 phy_ctrl_t *pc; 282 uint32 phy_ext_rom_boot; 283 soc_port_ability_t ability; 284 int phy_8074; 285 286 pc = EXT_PHY_SW_STATE(unit, port); 287 288 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER | PHY_FLAGS_C45); 289 290 phy_ext_rom_boot = soc_property_port_get(unit, port, spn_PHY_EXT_ROM_BOOT, 1); 291 292 phy_8074 = FALSE; 293 294 if (phy_ext_rom_boot) { 295 296 if (pc->phy_id1 == PHY_ID1_8073) { 297 uint16 data; 298 /* Check register 0xc802 to find out if it is a real 8074 device. */ 299 SOC_IF_ERROR_RETURN 300 (READ_PHY8072_PMA_PMD_REG(unit,pc,0xC802,&data)); 301 if ( data == 0x8074 ) { 302 phy_8074 = TRUE; 303 _8074_rom_load(unit,pc,pc->phy_id1); 304 } else { 305 _8072_rom_load(unit,pc,pc->phy_id1); 306 } 307 308 } else { 309 _8072_rom_load(unit,pc,pc->phy_id1); 310 } 311 312 /* Make sure SPI-ROM load is complete */ 313 soc_timeout_init(&to, 500000, 0); 314 do { 315 rv = (READ_PHY8072_GENREG1r(unit, pc, &data16)); 316 if (((data16 & 0xFFF0) == PMDA_ROM_LOAD_8072ID) || 317 ((data16 & 0xFFF0) == PMDA_ROM_LOAD_8073ID) || 318 SOC_FAILURE(rv)) { 319 break; 320 } 321 } while (!soc_timeout_check(&to)); 322 323 if (phy_8074) { 324 SOC_IF_ERROR_RETURN 325 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc843, 0x000f, 0x000f)); 326 SOC_IF_ERROR_RETURN 327 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc840, 0x000c, 0x000c)); 328 } 329 330 SOC_IF_ERROR_RETURN 331 (READ_PHY8072_GENREG1r(unit, pc,&data16)); 332 if (PMDA_ROM_LOAD_8072ID == (data16 & 0xFFF0) || 333 PMDA_ROM_LOAD_8073ID == (data16 & 0xFFF0)) { 334 SOC_IF_ERROR_RETURN 335 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0xCA1A,&data16)); 336 LOG_CLI((BSL_META_U(unit, 337 "8072: u=%d p=%d external rom boot complete f/w ver. " 338 "0x%x: init.\n"), 339 unit, port,data16)); 340 341 } else { 342 LOG_WARN(BSL_LS_SOC_PHY, 343 (BSL_META_U(unit, 344 "ROM_CODE read : u=%d p=%d 0x%x Expected 0xBCB0\n"), 345 unit, port, data16)); 346 } 347 348 if (pc->phy_id1 == PHY_ID1_8073) { 349 uint16 dev_rev; 350 uint16 snr_val; 351 uint16 rom_ver; 352 353 SOC_IF_ERROR_RETURN 354 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_CHIP_REV_REG, 355 &dev_rev)); 356 SOC_IF_ERROR_RETURN 357 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN2_REG, &rom_ver)); 358 /* 359 * Dis/En Tx to avoid Autoneg stuck for A1 devices. 360 */ 361 if (dev_rev == PHY_8073_A1 || dev_rev == PHY_8073_A0) { 362 SOC_IF_ERROR_RETURN 363 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xCA02, 0x400, 0x400)); 364 sal_usleep(1000000); 365 SOC_IF_ERROR_RETURN 366 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xCA02, 0x000, 0x400)); 367 } 368 369 SOC_IF_ERROR_RETURN 370 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xCA1B, 0x1000, 0x1000)); 371 372 sal_usleep(10000); 373 /* 374 * SNR Improvement: Change FFE main cursor to 5. 375 */ 376 if (APPLY_SNR_PATCH(dev_rev, rom_ver)) { 377 snr_val = (dev_rev == PHY_8073_A0) ? 0xFA0C : 0xFB0C; 378 SOC_IF_ERROR_RETURN 379 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA1B, snr_val)); 380 } 381 SOC_IF_ERROR_RETURN /* FEC Advert Enable */ 382 (MODIFY_PHY8072_AN_REG(unit, pc, AN_ADVERT_2_REG, 383 AN_ADVERT_FEC, AN_ADVERT_FEC)); 384 } 385 } 386 387 SOC_IF_ERROR_RETURN /* Restart AN */ 388 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, AN_ENABLE|AN_RESTART)); 389 390 if (pc->phy_id1 == PHY_ID1_8073) { 391 sal_usleep(50000); 392 393 /* XAUI Workaround */ 394 SOC_IF_ERROR_RETURN(_8073_A0_xaui_check(unit, port)); 395 } 396 397 /* fix for PHY-443 */ 398 SOC_IF_ERROR_RETURN 399 (MODIFY_PHY8072_PHYXS_REG(unit, pc, 0x8111, 1 << 3, 1 << 3)); 400 401 /* Set Local Advertising Configuration */ 402 SOC_IF_ERROR_RETURN 403 (phy_8072_ability_local_get(unit, port, &ability)); 404 SOC_IF_ERROR_RETURN 405 (phy_8072_ability_advert_set(unit, port, &ability)); 406 407 LOG_INFO(BSL_LS_SOC_PHY, 408 (BSL_META_U(unit, 409 "8072: u=%d port%d: init.\n"), unit, port)); 410 411 return SOC_E_NONE; 412 } 413 414 415 /* 416 * Function: 417 * phy_8072_link_get 418 * Purpose: 419 * Get layer2 connection status. 420 * Parameters: 421 * unit - StrataSwitch unit #. 422 * port - StrataSwitch port #. 423 * link - address of memory to store link up/down state. 424 * Returns: 425 * SOC_E_NONE 426 */ 427 428 STATIC int 429 phy_8072_link_get(int unit, soc_port_t port, int *link) 430 { 431 uint16 pma_mii_stat, pcs_mii_stat, link_stat,speed_val; 432 phy_ctrl_t *pc; 433 int an = 0,an_done = 0,cur_speed; 434 435 if (link == NULL) { 436 return SOC_E_NONE; 437 } 438 439 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 440 *link = FALSE; 441 return SOC_E_NONE; 442 } 443 444 pc = EXT_PHY_SW_STATE(unit, port); 445 446 phy_8072_an_get(unit,port,&an,&an_done); 447 448 /* return link false if in the middle of autoneg */ 449 if (an == TRUE && an_done == FALSE) { 450 *link = FALSE; 451 return SOC_E_NONE; 452 } 453 454 /* check if the current speed is set to 10G */ 455 cur_speed = 0; 456 if (an) { /* autoneg is enabled */ 457 SOC_IF_ERROR_RETURN 458 (READ_PHY8072_AN_REG(unit, pc, AN_ETH_STATUS_REG, &speed_val)); 459 if (speed_val & AN_SPEED_10GBASE_KR) { 460 cur_speed = 10000; 461 } 462 } else { /* force mode */ 463 SOC_IF_ERROR_RETURN 464 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 465 if ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK)==PMAD_CTRL2r_PMA_TYPE_10G) { 466 cur_speed = 10000; 467 } 468 } 469 470 if (cur_speed == 10000) { /* check all 2 device's link status if 10G */ 471 /* Receive Link status */ 472 SOC_IF_ERROR_RETURN 473 (READ_PHY8072_PCS_STATr(unit, pc, &pcs_mii_stat)); 474 } 475 476 SOC_IF_ERROR_RETURN 477 (READ_PHY8072_PMA_PMD_STATr(unit, pc, &pma_mii_stat)); 478 479 link_stat = (cur_speed == 10000)? 480 pma_mii_stat & pcs_mii_stat: 481 pma_mii_stat; 482 483 *link = (link_stat & MII_STAT_LA) ? TRUE : FALSE; 484 485 return SOC_E_NONE; 486 } 487 488 /* 489 * Function: 490 * phy_8072_enable_set 491 * Purpose: 492 * Enable/Disable phy 493 * Parameters: 494 * unit - StrataSwitch unit #. 495 * port - StrataSwitch port #. 496 * enable - on/off state to set 497 * Returns: 498 * SOC_E_NONE 499 */ 500 501 STATIC int 502 phy_8072_enable_set(int unit, soc_port_t port, int enable) 503 { 504 uint16 data; /* Holder for new value to write to PHY reg */ 505 uint16 mask; /* Holder for bit mask to update in PHY reg */ 506 phy_ctrl_t *pc; 507 508 pc = EXT_PHY_SW_STATE(unit, port); 509 510 data = 0; 511 mask = 1 << 0; /* Global PMD transmit disable */ 512 if (enable) { 513 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 514 } else { 515 data = 1 << 0; /* Global PMD transmit disable */ 516 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 517 } 518 519 SOC_IF_ERROR_RETURN 520 (MODIFY_PHY8072_PMA_PMD_TX_DISABLEr(unit, pc, data, mask)); 521 return (SOC_E_NONE); 522 } 523 524 /* 525 * Function: 526 * phy_8072_lb_set 527 * Purpose: 528 * Put 8072 in PHY PCS/PMA/PMD loopback 529 * Parameters: 530 * unit - StrataSwitch unit #. 531 * port - StrataSwitch port #. 532 * enable - binary value for on/off (1/0) 533 * Returns: 534 * SOC_E_NONE 535 */ 536 537 STATIC int 538 phy_8072_lb_set(int unit, soc_port_t port, int enable) 539 { 540 phy_ctrl_t *pc; 541 uint16 tmp; 542 543 pc = EXT_PHY_SW_STATE(unit, port); 544 545 #if defined(PHY_8072_PCS_LOOPBACK) 546 tmp = enable ? MII_CTRL_LE : 0; 547 548 SOC_IF_ERROR_RETURN 549 (MODIFY_PHY8072_PCS_CTRLr(unit, pc, tmp, MII_CTRL_LE)); 550 #endif /* PHY_8072_PCS_LOOPBACK */ 551 552 #if defined(PHY_8072_PMA_PMD_LOOPBACK) 553 tmp = enable ? MII_CTRL_PMA_LOOPBACK : 0; 554 555 SOC_IF_ERROR_RETURN 556 (MODIFY_PHY8072_PMA_PMD_CTRLr(unit, pc, 557 tmp, MII_CTRL_PMA_LOOPBACK)); 558 #endif /* PHY_8072_PMA_PMD_LOOPBACK */ 559 560 #if defined(PHY_8072_SYSTEM_LOOPBACK) 561 562 tmp = enable? XGXS_MODE_SYSTEM_LOOPBACK | XGXS_CTRL_RLOOP 563 :XGXS_MODE_NORMAL; 564 SOC_IF_ERROR_RETURN 565 (MODIFY_PHY8072_PHYXS_REG(unit,pc,XGXS_MODE_CTRLr, 566 tmp, 567 XGXS_MODE_MASK | XGXS_CTRL_RLOOP)); 568 569 #endif /* PHY_8072_SYSTEM_LOOPBACK */ 570 571 #if defined(PHY_8072_XAUI_LOOPBACK) 572 SOC_IF_ERROR_RETURN 573 (READ_PHY8072_PHYXS_REG(unit, pc, PHYXS_MODE_CTRL_REG, &tmp)); 574 tmp &= ~(0xf << 8); 575 tmp |= ((enable) ? 6 : 1) << 8; 576 SOC_IF_ERROR_RETURN 577 (WRITE_PHY8072_PHYXS_REG(unit, pc, PHYXS_MODE_CTRL_REG, tmp)); 578 579 tmp = (enable) ? (0x00f0) : (0x0000); 580 SOC_IF_ERROR_RETURN 581 (WRITE_PHY8072_PHYXS_REG(unit, pc, 0x8017, tmp)); 582 #endif /* PHY_8072_XAUI_LOOPBACK */ 583 584 return SOC_E_NONE; 585 } 586 587 /* 588 * Function: 589 * phy_8072_lb_get 590 * Purpose: 591 * Get 8072 PHY loopback state 592 * Parameters: 593 * unit - StrataSwitch unit #. 594 * port - StrataSwitch port #. 595 * enable - address of location to store binary value for on/off (1/0) 596 * Returns: 597 * SOC_E_NONE 598 */ 599 600 STATIC int 601 phy_8072_lb_get(int unit, soc_port_t port, int *enable) 602 { 603 uint16 tmp; 604 phy_ctrl_t *pc; 605 606 pc = EXT_PHY_SW_STATE(unit, port); 607 608 #if defined(PHY_8072_PCS_LOOPBACK) 609 SOC_IF_ERROR_RETURN 610 (READ_PHY8072_PCS_CTRLr(unit, pc, &tmp)); 611 612 *enable = (tmp & MII_CTRL_LE) ? TRUE : FALSE; 613 #endif /* PHY_8072_PCS_LOOPBACK */ 614 615 616 617 #if defined(PHY_8072_PMA_PMD_LOOPBACK) 618 SOC_IF_ERROR_RETURN 619 (READ_PHY8072_PMA_PMD_CTRLr(unit, pc, &tmp)); 620 621 *enable = (tmp & MII_CTRL_PMA_LOOPBACK) ? TRUE : FALSE; 622 #endif /* PHY_8072_PMA_PMD_LOOPBACK */ 623 624 #if defined(PHY_8072_SYSTEM_LOOPBACK) 625 SOC_IF_ERROR_RETURN 626 (READ_PHY8072_PHYXS_REG(unit,pc,XGXS_MODE_CTRLr,&tmp)); 627 *enable = (tmp & XGXS_MODE_MASK)? FALSE:TRUE; 628 #endif /* PHY_8072_SYSTEM_LOOPBACK */ 629 630 #if defined(PHY_8072_XAUI_LOOPBACK) 631 SOC_IF_ERROR_RETURN 632 (READ_PHY8072_PHYXS_REG(unit, pc, PHYXS_MODE_CTRL_REG, &tmp)); 633 *enable = ((tmp & (0xf << 8)) == (6 << 8)); 634 #endif /* PHY_8072_XAUI_LOOPBACK */ 635 636 LOG_INFO(BSL_LS_SOC_PHY, 637 (BSL_META_U(unit, 638 "phy_8072_lb_get: u=%d port%d: loopback:%s\n"), 639 unit, port, *enable ? "Enabled": "Disabled")); 640 641 return SOC_E_NONE; 642 } 643 644 645 STATIC int 646 phy_8072_linkup_evt(int unit, soc_port_t port) 647 { 648 phy_ctrl_t *pc; /* PHY software state */ 649 uint16 dev_rev; 650 uint16 snr_val; 651 uint16 rom_ver; 652 uint16 link; 653 654 pc = EXT_PHY_SW_STATE(unit, port); 655 SOC_IF_ERROR_RETURN(_8073_A0_xaui_check(unit, port)); 656 657 if (pc->phy_id1 == PHY_ID1_8072) { 658 return SOC_E_NONE; 659 } 660 SOC_IF_ERROR_RETURN 661 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_CHIP_REV_REG, &dev_rev)); 662 SOC_IF_ERROR_RETURN 663 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_GEN2_REG, &rom_ver)); 664 if(APPLY_SNR_PATCH(dev_rev, rom_ver)) { 665 /* 666 * Change CDR Bandwidth. 667 */ 668 SOC_IF_ERROR_RETURN 669 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA46, 0x0333)); 670 /* 671 * Change PLL Bandwidth. 672 */ 673 SOC_IF_ERROR_RETURN 674 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA1D, 0x26BC)); 675 /* 676 * SNR Improvement. 677 */ 678 snr_val = (dev_rev == PHY_8073_A0) ? 0xFA0C : 0xFB0C; 679 SOC_IF_ERROR_RETURN 680 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA1B, snr_val)); 681 } 682 SOC_IF_ERROR_RETURN 683 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_USR_STATUS_REG, &link)); 684 685 /* if autoneg to 10G, sync up the serdes's speed in case it's not done*/ 686 if (PMAD_STATUS_AN_10G(link)) { 687 SOC_IF_ERROR_RETURN 688 (soc_phyctrl_notify(unit, port, phyEventSpeed, 10000)); 689 } 690 LOG_INFO(BSL_LS_SOC_PHY, 691 (BSL_META_U(unit, 692 "phy_8072_linkup_evt: u=%d p=%d\n"), 693 unit, port)); 694 return SOC_E_NONE; 695 } 696 697 STATIC int 698 _phy_8072_control_tx_driver_set(int unit, soc_port_t port, 699 soc_phy_control_t type, uint32 value) 700 { 701 uint16 data; /* Temporary holder of reg value to be written */ 702 uint16 mask; /* Bit mask of reg value to be updated */ 703 phy_ctrl_t *pc; /* PHY software state */ 704 705 pc = EXT_PHY_SW_STATE(unit, port); 706 707 /* Dozen SerDes */ 708 switch(type) { 709 case SOC_PHY_CONTROL_PREEMPHASIS: 710 data = (uint16)(value & 0xf); 711 data = data << 12; 712 mask = 0xf000; 713 break; 714 case SOC_PHY_CONTROL_DRIVER_CURRENT: 715 data = (uint16)(value & 0xf); 716 data = data << 8; 717 mask = 0x0f00; 718 break; 719 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 720 data = (uint16)(value & 0xf); 721 data = data << 4; 722 mask = 0x00f0; 723 break; 724 default: 725 /* should never get here */ 726 return SOC_E_PARAM; 727 } 728 SOC_IF_ERROR_RETURN 729 (MODIFY_PHY8072_TXA_ACTRL_3r(unit, pc, data, mask)); 730 731 return SOC_E_NONE; 732 } 733 734 STATIC int 735 _phy_8072_control_tx_driver_get(int unit, soc_port_t port, 736 soc_phy_control_t type, uint32 *value) 737 { 738 uint16 data16; /* Temporary holder of a reg value */ 739 phy_ctrl_t *pc; /* PHY software state */ 740 741 pc = EXT_PHY_SW_STATE(unit, port); 742 743 data16 = 0; 744 SOC_IF_ERROR_RETURN 745 (READ_PHY8072_TXA_ACTRL_3r(unit, pc, &data16)); 746 switch(type) { 747 case SOC_PHY_CONTROL_PREEMPHASIS: 748 *value = (data16 & 0xf000) >> 12; 749 break; 750 case SOC_PHY_CONTROL_DRIVER_CURRENT: 751 *value = (data16 & 0x0f00) >> 8; 752 break; 753 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 754 *value = (data16 & 0x00f0) >> 4; 755 break; 756 default: 757 /* should never get here */ 758 return SOC_E_PARAM; 759 } 760 761 return SOC_E_NONE; 762 } 763 764 /* 765 * Function: 766 * phy_8072_control_set 767 * Purpose: 768 * Configure PHY device specific control fucntion. 769 * Parameters: 770 * unit - StrataSwitch unit #. 771 * port - StrataSwitch port #. 772 * type - Control to update 773 * value - New setting for the control 774 * Returns: 775 * SOC_E_NONE 776 */ 777 STATIC int 778 phy_8072_control_set(int unit, soc_port_t port, 779 soc_phy_control_t type, uint32 value) 780 { 781 int rv; 782 783 PHY_CONTROL_TYPE_CHECK(type); 784 785 rv = SOC_E_UNAVAIL; 786 switch(type) { 787 case SOC_PHY_CONTROL_PREEMPHASIS: 788 /* fall through */ 789 case SOC_PHY_CONTROL_DRIVER_CURRENT: 790 /* fall through */ 791 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 792 rv = _phy_8072_control_tx_driver_set(unit, port, type, value); 793 break; 794 default: 795 rv = SOC_E_UNAVAIL; 796 break; 797 } 798 return rv; 799 } 800 /* 801 * Function: 802 * phy_8072_control_get 803 * Purpose: 804 * Get current control settign of the PHY. 805 * Parameters: 806 * unit - StrataSwitch unit #. 807 * port - StrataSwitch port #. 808 * type - Control to update 809 * value - (OUT)Current setting for the control 810 * Returns: 811 * SOC_E_NONE 812 */ 813 STATIC int 814 phy_8072_control_get(int unit, soc_port_t port, 815 soc_phy_control_t type, uint32 *value) 816 { 817 int rv; 818 819 PHY_CONTROL_TYPE_CHECK(type); 820 821 rv = SOC_E_UNAVAIL; 822 switch(type) { 823 case SOC_PHY_CONTROL_PREEMPHASIS: 824 /* fall through */ 825 case SOC_PHY_CONTROL_DRIVER_CURRENT: 826 /* fall through */ 827 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 828 rv = _phy_8072_control_tx_driver_get(unit, port, type, value); 829 break; 830 default: 831 rv = SOC_E_UNAVAIL; 832 break; 833 } 834 835 return rv; 836 } 837 838 /* 839 * Function: 840 * phy_8072_probe 841 * Purpose: 842 * Complement the generic phy probe routine to identify this phy when its 843 * phy id0 and id1 is same as some other phy's. 844 * Parameters: 845 * unit - StrataSwitch unit #. 846 * pc - phy ctrl descriptor. 847 * Returns: 848 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 849 */ 850 851 852 STATIC int 853 phy_8072_probe(int unit, phy_ctrl_t *pc) 854 { 855 uint16 data0 = 0; 856 uint16 data1 = 0; 857 858 if (soc_property_port_get(unit, pc->port, spn_PHY_8072, FALSE)) { 859 return SOC_E_NONE; 860 } 861 862 /* device 8072 and 8073 has different id1, but uses the same driver. 863 * First check if the device's id1 matches 8073. 864 */ 865 SOC_IF_ERROR_RETURN 866 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_ID1_REG,&data1)); 867 868 if (data1 == PHY_ID1_8073) { 869 870 /* PHY 8727 has the same phyid1, check register 0xc802 to find out if 871 * it is a real 8073 or 8074 device. 872 */ 873 SOC_IF_ERROR_RETURN 874 (READ_PHY8072_PMA_PMD_REG(unit,pc,0xC802,&data1)); 875 if (data1 != 0x8073) { 876 return SOC_E_NOT_FOUND; 877 } else { 878 /* found a 8073 */ 879 return SOC_E_NONE; 880 } 881 } 882 883 /* 8072 has the same phy id0 and id1. The difference is the register 884 * 0 device 7 reads as 0 for 87x6, 0x1000 for 8072 after powerup. 885 */ 886 SOC_IF_ERROR_RETURN 887 (READ_PHY8072_AN_REG(unit,pc,0,&data0)); 888 889 /* needed for subsequent initialization after powerup */ 890 SOC_IF_ERROR_RETURN 891 (READ_PHY8072_GENREG1r(unit,pc,&data1)); 892 893 /* the id after the SPI-ROM is loaded for 8072 */ 894 if ((data1 & 0xFFF0) == PMDA_ROM_LOAD_8072ID) { 895 return SOC_E_NONE; 896 } 897 898 /* the id after the SPI-ROM is loaded for 8706 */ 899 if ((data1 == 0x4321) || (data1 == 0x1234)) { 900 return SOC_E_NOT_FOUND; 901 } 902 903 /* powerup case */ 904 if (data0 == 0x1000) { 905 return SOC_E_NONE; 906 } 907 908 return SOC_E_NOT_FOUND; 909 } 910 911 STATIC int 912 phy_8074_probe(int unit, phy_ctrl_t *pc) 913 { 914 uint16 data = 0; 915 916 /* device 8072 and 8073/8074 have different id1, but use the same driver. 917 * First check if the device's id1 matches 8074. 918 */ 919 SOC_IF_ERROR_RETURN 920 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_ID1_REG,&data)); 921 922 if (data == PHY_ID1_8074) { 923 /* PHYs 8727/8073/8074 have the same phyid1, check register 0xc802 to find out if 924 * 8074 device. 925 */ 926 SOC_IF_ERROR_RETURN 927 (READ_PHY8072_PMA_PMD_REG(unit,pc,0xC802,&data)); 928 if (data == 0x8074) { 929 return SOC_E_NONE; 930 } 931 } 932 return SOC_E_NOT_FOUND; 933 } 934 935 /* 936 * Function: 937 * phy_8072_speed_set 938 * Purpose: 939 * Set PHY speed 940 * Parameters: 941 * unit - StrataSwitch unit #. 942 * port - StrataSwitch port #. 943 * speed - link speed in Mbps 944 * Returns: 945 * SOC_E_NONE 946 */ 947 948 STATIC int 949 phy_8072_speed_set(int unit, soc_port_t port, int speed) 950 { 951 phy_ctrl_t *pc; 952 phy_ctrl_t *int_pc; 953 int rv = SOC_E_NONE; 954 955 LOG_INFO(BSL_LS_SOC_PHY, 956 (BSL_META_U(unit, 957 "phy_8072_speed_set: u=%d p=%d speed=%d\n"), 958 unit, port,speed)); 959 960 if (!(speed == 10000 || speed == 1000 || speed==2500)) { 961 return SOC_E_PARAM; 962 } 963 964 pc = EXT_PHY_SW_STATE(unit, port); 965 int_pc = INT_PHY_SW_STATE(unit, port); 966 967 SOC_IF_ERROR_RETURN 968 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0x0096, 0x0000)); 969 970 if (speed == 10000 || speed == 1000) { 971 SOC_IF_ERROR_RETURN 972 (MODIFY_PHY8072_AN_REG(unit,pc,0x8309,(1 << 5),(1 << 5))); 973 } 974 975 if (speed == 10000) { 976 SOC_IF_ERROR_RETURN 977 (MODIFY_PHY8072_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, 978 PMAD_CTRL2r_PMA_TYPE_10G,PMAD_CTRL2r_PMA_TYPE_MASK)); 979 980 SOC_IF_ERROR_RETURN 981 (MODIFY_PHY8072_PMA_PMD_REG(unit,pc, MII_CTRL_REG, 982 MII_CTRL_SS_LSB,MII_CTRL_SS_LSB)); 983 SOC_IF_ERROR_RETURN 984 (WRITE_PHY8072_AN_REG(unit,pc,0x8308,0x1C)); 985 SOC_IF_ERROR_RETURN 986 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, 987 AN_ENABLE | 988 AN_RESTART)); 989 990 sal_usleep(40000); 991 SOC_IF_ERROR_RETURN 992 (WRITE_PHY8072_AN_REG(unit,pc,AN_CTRL_REG,0)); 993 994 } else if (speed == 1000) { 995 SOC_IF_ERROR_RETURN 996 (MODIFY_PHY8072_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, 997 PMAD_CTRL2r_PMA_TYPE_1G,PMAD_CTRL2r_PMA_TYPE_MASK)); 998 999 SOC_IF_ERROR_RETURN 1000 (MODIFY_PHY8072_PMA_PMD_REG(unit,pc,MII_CTRL_REG, 1001 0,MII_CTRL_SS_LSB)); 1002 } else if (speed == 2500) { 1003 1004 SOC_IF_ERROR_RETURN 1005 (MODIFY_PHY8072_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, 1006 PMAD_CTRL2r_PMA_TYPE_1G,PMAD_CTRL2r_PMA_TYPE_MASK)); 1007 1008 SOC_IF_ERROR_RETURN 1009 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, 1010 AN_ENABLE | 1011 AN_RESTART)); 1012 1013 sal_usleep(40000); 1014 SOC_IF_ERROR_RETURN 1015 (WRITE_PHY8072_AN_REG(unit,pc,AN_CTRL_REG,0)); 1016 1017 SOC_IF_ERROR_RETURN 1018 (WRITE_PHY8072_AN_REG(unit,pc,0xffe0,0)); 1019 SOC_IF_ERROR_RETURN 1020 (MODIFY_PHY8072_AN_REG(unit,pc,0x8309,0,(1 << 5))); 1021 sal_usleep(10000); 1022 1023 SOC_IF_ERROR_RETURN 1024 (WRITE_PHY8072_AN_REG(unit,pc,0x8308,0x10)); 1025 } 1026 1027 1028 /* need to set the internal phy's speed accordingly */ 1029 1030 if (NULL != int_pc) { 1031 rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed); 1032 } 1033 return rv; 1034 } 1035 1036 /* 1037 * Function: 1038 * phy_8072_speed_get 1039 * Purpose: 1040 * Get PHY speed 1041 * Parameters: 1042 * unit - StrataSwitch unit #. 1043 * port - StrataSwitch port #. 1044 * speed - current link speed in Mbps 1045 * Returns: 1046 * SOC_E_NONE 1047 */ 1048 1049 STATIC int 1050 phy_8072_speed_get(int unit, soc_port_t port, int *speed) 1051 { 1052 phy_ctrl_t *pc; 1053 uint16 speed_val; 1054 int an = 0; 1055 int an_done = 0; 1056 uint16 an_cl37 = 0; 1057 uint16 status = 0; 1058 1059 pc = EXT_PHY_SW_STATE(unit, port); 1060 speed_val = 0; 1061 *speed = 10000; 1062 1063 phy_8072_an_get(unit, port, &an, &an_done); 1064 if (pc->phy_id1 == PHY_ID1_8073) { 1065 SOC_IF_ERROR_RETURN 1066 (READ_PHY8072_PMA_PMD_REG(unit, pc, PMAD_USR_STATUS_REG, 1067 &status)); 1068 } 1069 1070 if (an) { /* autoneg is enabled */ 1071 SOC_IF_ERROR_RETURN 1072 (READ_PHY8072_AN_REG(unit, pc, AN_ETH_STATUS_REG, &speed_val)); 1073 if (speed_val & AN_SPEED_10GBASE_KR) { 1074 *speed = 10000; 1075 } else if (PMAD_STATUS_AN_2p5G(status)) { 1076 *speed = 2500; 1077 } else if (speed_val & AN_SPEED_1000BASE_KX) { 1078 *speed = 1000; 1079 } else { 1080 uint16 phy_id1; 1081 int link_cl37; 1082 1083 SOC_IF_ERROR_RETURN 1084 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_ID1_REG,&phy_id1)); 1085 1086 /* check CL37 link status */ 1087 SOC_IF_ERROR_RETURN 1088 (READ_PHY8072_AN_REG(unit, pc, 0x8304, &an_cl37)); 1089 link_cl37 = an_cl37 & 0x2; 1090 1091 /* check if CL37 enabled. automatically enabled for 8073 */ 1092 if (phy_id1 == PHY_ID1_8072) { 1093 SOC_IF_ERROR_RETURN 1094 (READ_PHY8072_AN_REG(unit, pc, 0xFFE0, &an_cl37)); 1095 link_cl37 = link_cl37 && (an_cl37 & AN_ENABLE); 1096 } 1097 1098 if (link_cl37) { 1099 *speed = 1000; 1100 } 1101 } 1102 } else { /* autoneg is not enabled, forced speed */ 1103 1104 SOC_IF_ERROR_RETURN 1105 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_USR_STATUS_REG,&speed_val)); 1106 if (speed_val & PMAD_STATUS_MODE_2p5G) { 1107 *speed = 2500; 1108 } else { 1109 SOC_IF_ERROR_RETURN 1110 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 1111 if ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) == 1112 PMAD_CTRL2r_PMA_TYPE_1G) { 1113 *speed = 1000; 1114 } else if ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) == 1115 PMAD_CTRL2r_PMA_TYPE_10G) { 1116 *speed = 10000; 1117 } 1118 } 1119 } 1120 1121 LOG_INFO(BSL_LS_SOC_PHY, 1122 (BSL_META_U(unit, 1123 "phy_8072_speed_get: u=%d p=%d speed=%d\n"), 1124 unit, port, *speed)); 1125 return SOC_E_NONE; 1126 } 1127 1128 /* 1129 * Function: 1130 * phy_8072_an_get 1131 * Purpose: 1132 * Get the current auto-negotiation status (enabled/busy) 1133 * Parameters: 1134 * unit - StrataSwitch unit #. 1135 * port - StrataSwitch port #. 1136 * an - (OUT) if true, auto-negotiation is enabled. 1137 * an_done - (OUT) if true, auto-negotiation is complete. This 1138 * value is undefined if an == false. 1139 * Returns: 1140 * SOC_E_XXX 1141 */ 1142 1143 STATIC int 1144 phy_8072_an_get(int unit, soc_port_t port, int *an, int *an_done) 1145 { 1146 phy_ctrl_t *pc; 1147 uint16 an_status; 1148 1149 pc = EXT_PHY_SW_STATE(unit, port); 1150 SOC_IF_ERROR_RETURN 1151 (READ_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, &an_status)); 1152 *an = (an_status & AN_ENABLE)? TRUE: FALSE; 1153 1154 SOC_IF_ERROR_RETURN 1155 (READ_PHY8072_AN_REG(unit, pc, AN_STATUS_REG, &an_status)); 1156 *an_done = (an_status & AN_DONE)? TRUE: FALSE; 1157 return SOC_E_NONE; 1158 } 1159 1160 /* 1161 * Function: 1162 * phy_8072_an_set 1163 * Purpose: 1164 * Enable or disabled auto-negotiation on the specified port. 1165 * Parameters: 1166 * unit - StrataSwitch unit #. 1167 * port - StrataSwitch port #. 1168 * an - Boolean, if true, auto-negotiation is enabled 1169 * (and/or restarted). If false, autonegotiation is disabled. 1170 * Returns: 1171 * SOC_E_XXX 1172 */ 1173 1174 STATIC int 1175 phy_8072_an_set(int unit, soc_port_t port, int an) 1176 { 1177 phy_ctrl_t *pc; 1178 uint16 phy_id1; 1179 1180 pc = EXT_PHY_SW_STATE(unit, port); 1181 1182 LOG_INFO(BSL_LS_SOC_PHY, 1183 (BSL_META_U(unit, 1184 "phy_8072_an_set: u=%d p=%d an=%d\n"), 1185 unit, port, an)); 1186 1187 SOC_IF_ERROR_RETURN 1188 (READ_PHY8072_PMA_PMD_REG(unit,pc,PMAD_ID1_REG,&phy_id1)); 1189 1190 if (an) { 1191 SOC_IF_ERROR_RETURN 1192 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0x0096, 0x0002)); 1193 1194 if (phy_id1 == PHY_ID1_8072) { 1195 /* Allow Clause 37 through Clause 73 */ 1196 SOC_IF_ERROR_RETURN 1197 (WRITE_PHY8072_AN_REG(unit, pc, 0x8370,0x040c)); 1198 1199 } 1200 1201 /* Enable Clause 37 AN */ 1202 SOC_IF_ERROR_RETURN 1203 (WRITE_PHY8072_AN_REG(unit, pc, 0xFFE0, 0x1100)); 1204 1205 SOC_IF_ERROR_RETURN 1206 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, 1207 AN_EXT_NXT_PAGE | 1208 AN_ENABLE | 1209 AN_RESTART)); 1210 } else { 1211 SOC_IF_ERROR_RETURN 1212 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0x0096, 0x0000)); 1213 1214 if (phy_id1 == PHY_ID1_8072) { 1215 /* no Clause 37 through Clause 73 */ 1216 SOC_IF_ERROR_RETURN 1217 (WRITE_PHY8072_AN_REG(unit, pc, 0x8370,0x0)); 1218 1219 } 1220 /* disable Clause 37 AN */ 1221 SOC_IF_ERROR_RETURN 1222 (WRITE_PHY8072_AN_REG(unit, pc, 0xFFE0, 0x0)); 1223 1224 SOC_IF_ERROR_RETURN 1225 (WRITE_PHY8072_AN_REG(unit, pc, AN_CTRL_REG, 0x0)); 1226 } 1227 return SOC_E_NONE; 1228 } 1229 1230 /* 1231 * Function: 1232 * phy_8072_ability_advert_get 1233 * Purpose: 1234 * Get the current advertisement for auto-negotiation. 1235 * Parameters: 1236 * unit - StrataSwitch unit #. 1237 * port - StrataSwitch port #. 1238 * mode - (OUT) Port mode mask indicating supported options/speeds. 1239 * Returns: 1240 * SOC_E_XXX 1241 * Notes: 1242 * The advertisement is retrieved for the ACTIVE medium. 1243 * No synchronization performed at this level. 1244 */ 1245 1246 STATIC int 1247 phy_8072_ability_advert_get(int unit, soc_port_t port, 1248 soc_port_ability_t *ability) 1249 { 1250 uint16 an_adv; 1251 uint16 pause; 1252 soc_port_mode_t mode; 1253 phy_ctrl_t *pc; 1254 1255 if (NULL == ability) { 1256 return (SOC_E_PARAM); 1257 } 1258 1259 pc = EXT_PHY_SW_STATE(unit, port); 1260 1261 /* advert register 1 */ 1262 SOC_IF_ERROR_RETURN 1263 (READ_PHY8072_AN_REG(unit, pc, AN_ADVERT_1_REG, &an_adv)); 1264 1265 mode = 0; 1266 pause = 0; 1267 mode |= (an_adv & AN_ADVERT_10G) ? SOC_PA_SPEED_10GB : 0; 1268 mode |= (an_adv & AN_ADVERT_1G) ? SOC_PA_SPEED_1000MB : 0; 1269 1270 /* check Full Duplex advertisement on Clause 37 */ 1271 SOC_IF_ERROR_RETURN 1272 (READ_PHY8072_AN_REG(unit, pc, 0xFFE4,&an_adv)); 1273 1274 mode |= (an_adv & 0x20) ? SOC_PA_SPEED_1000MB : 0; 1275 1276 if (pc->phy_id1 == PHY_ID1_8073) { 1277 SOC_IF_ERROR_RETURN 1278 (READ_PHY8072_AN_REG(unit, pc, 0x8329,&an_adv)); 1279 mode |= (an_adv & 0x1) ? SOC_PA_SPEED_2500MB : 0; 1280 } 1281 1282 SOC_IF_ERROR_RETURN 1283 (READ_PHY8072_AN_REG(unit, pc, AN_ADVERT_0_REG, &pause)); 1284 1285 ability->speed_full_duplex = mode; 1286 ability->pause = 0; 1287 switch (pause & (AN_ADVERT_PAUSE | AN_ADVERT_PAUSE_ASYM)) { 1288 case AN_ADVERT_PAUSE: 1289 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1290 break; 1291 case AN_ADVERT_PAUSE_ASYM: 1292 ability->pause = SOC_PA_PAUSE_TX; 1293 break; 1294 case AN_ADVERT_PAUSE | AN_ADVERT_PAUSE_ASYM: 1295 ability->pause = SOC_PA_PAUSE_RX; 1296 break; 1297 } 1298 1299 LOG_INFO(BSL_LS_SOC_PHY, 1300 (BSL_META_U(unit, 1301 "phy_8072_ability_advert_get: u=%d p=%d speed=0x%x pause=0x%x\n"), 1302 unit, port, ability->speed_full_duplex, ability->pause)); 1303 return SOC_E_NONE; 1304 } 1305 1306 /* 1307 * Function: 1308 * phy_8072_ability_advert_set 1309 * Purpose: 1310 * Set the current advertisement for auto-negotiation. 1311 * Parameters: 1312 * unit - StrataSwitch unit #. 1313 * port - StrataSwitch port #. 1314 * mode - Port mode mask indicating supported options/speeds. 1315 * Returns: 1316 * SOC_E_XXX 1317 * Notes: 1318 * The advertisement is set only for the ACTIVE medium. 1319 * No synchronization performed at this level. 1320 */ 1321 1322 STATIC int 1323 phy_8072_ability_advert_set(int unit, soc_port_t port, 1324 soc_port_ability_t *ability) 1325 { 1326 uint16 an_adv; 1327 uint16 an_adv_cl37; 1328 phy_ctrl_t *pc; 1329 if (NULL == ability) { 1330 return (SOC_E_PARAM); 1331 } 1332 1333 pc = EXT_PHY_SW_STATE(unit, port); 1334 1335 /* 1336 * Set advertised duplex (only FD supported). 1337 */ 1338 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 1339 AN_ADVERT_1G : 0; 1340 1341 /* write Full Duplex advertisement on Clause 37 */ 1342 SOC_IF_ERROR_RETURN 1343 (WRITE_PHY8072_AN_REG(unit, pc, 0xFFE4,an_adv)); 1344 1345 an_adv = (ability->speed_full_duplex & 1346 (SOC_PA_SPEED_1000MB | SOC_PA_SPEED_2500MB)) ? 1347 AN_ADVERT_1G : 0; 1348 an_adv |= (ability->speed_full_duplex & SOC_PA_SPEED_10GB) ? 1349 AN_ADVERT_10G : 0; 1350 1351 /* advert register 1 */ 1352 SOC_IF_ERROR_RETURN 1353 (WRITE_PHY8072_AN_REG(unit, pc, AN_ADVERT_1_REG, an_adv)); 1354 1355 if (pc->phy_id1 == PHY_ID1_8073) { 1356 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_2500MB) ? 0x1 : 0; 1357 SOC_IF_ERROR_RETURN 1358 (WRITE_PHY8072_AN_REG(unit, pc, 0x8329, an_adv)); 1359 } 1360 1361 an_adv = an_adv_cl37 = 0; 1362 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 1363 case SOC_PA_PAUSE_TX: 1364 an_adv = AN_ADVERT_PAUSE_ASYM; 1365 an_adv_cl37 = MII_ANA_C37_ASYM_PAUSE; 1366 break; 1367 case SOC_PA_PAUSE_RX: 1368 an_adv = AN_ADVERT_PAUSE_ASYM | AN_ADVERT_PAUSE; 1369 an_adv_cl37 = MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE; 1370 break; 1371 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 1372 an_adv_cl37 = MII_ANA_C37_PAUSE; 1373 an_adv = AN_ADVERT_PAUSE; 1374 break; 1375 } 1376 SOC_IF_ERROR_RETURN 1377 (MODIFY_PHY8072_AN_REG(unit, pc, AN_ADVERT_0_REG, an_adv, 1378 AN_ADVERT_PAUSE | AN_ADVERT_PAUSE_ASYM)); 1379 /* write Pause advertisement on Clause 37 */ 1380 SOC_IF_ERROR_RETURN 1381 (MODIFY_PHY8072_AN_REG(unit, pc, 0xFFE4, an_adv_cl37, 1382 MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE)); 1383 1384 LOG_INFO(BSL_LS_SOC_PHY, 1385 (BSL_META_U(unit, 1386 "phy_8072_ability_advert_set: u=%d p=%d pause=0x%08x adv_reg1=0x%04x\n"), 1387 unit, port, ability->pause, an_adv)); 1388 return SOC_E_NONE; 1389 } 1390 1391 /* 1392 * Function: 1393 * phy_8072_ability_local_get 1394 * Purpose: 1395 * Get the device's complete abilities. 1396 * Parameters: 1397 * unit - StrataSwitch unit #. 1398 * port - StrataSwitch port #. 1399 * ability - return device's abilities. 1400 * Returns: 1401 * SOC_E_XXX 1402 */ 1403 1404 STATIC int 1405 phy_8072_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1406 { 1407 phy_ctrl_t *pc; 1408 1409 pc = EXT_PHY_SW_STATE(unit, port); 1410 1411 LOG_INFO(BSL_LS_SOC_PHY, 1412 (BSL_META_U(unit, 1413 "phy_8072_ability_local_get: u=%d p=%d\n"), 1414 unit, port)); 1415 1416 if (NULL == ability) { 1417 return SOC_E_PARAM; 1418 } 1419 1420 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 1421 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 1422 1423 switch(pc->speed_max) { 1424 case 10000: 1425 default: 1426 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 1427 if (pc->phy_id1 == PHY_ID1_8073) { 1428 ability->speed_full_duplex |= SOC_PA_SPEED_2500MB; 1429 } 1430 break; 1431 } 1432 1433 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 1434 ability->interface = SOC_PA_INTF_XGMII; 1435 ability->medium = SOC_PA_MEDIUM_FIBER; 1436 ability->loopback = SOC_PA_LB_PHY; 1437 ability->flags = SOC_PA_AUTONEG; 1438 1439 LOG_INFO(BSL_LS_SOC_PHY, 1440 (BSL_META_U(unit, 1441 "phy_8072_ability_local_get: u=%d p=%d speed=0x%x pause=0x%x\n"), 1442 unit, port, ability->speed_full_duplex,ability->pause)); 1443 1444 return (SOC_E_NONE); 1445 } 1446 1447 /* 1448 * Function: 1449 * phy_8072_ability_remote_get 1450 * Purpose: 1451 * Get the device's complete abilities. 1452 * Parameters: 1453 * unit - StrataSwitch unit #. 1454 * port - StrataSwitch port #. 1455 * ability - return device's abilities. 1456 * Returns: 1457 * SOC_E_XXX 1458 */ 1459 1460 STATIC int 1461 phy_8072_ability_remote_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1462 { 1463 phy_ctrl_t *pc; 1464 uint16 lp_abil, lp_abil_cl37; 1465 soc_port_mode_t mode; 1466 int speed; 1467 1468 pc = EXT_PHY_SW_STATE(unit, port); 1469 1470 LOG_INFO(BSL_LS_SOC_PHY, 1471 (BSL_META_U(unit, 1472 "phy_8072_ability_remote_get: u=%d p=%d\n"), 1473 unit, port)); 1474 1475 if (NULL == ability) { 1476 return SOC_E_PARAM; 1477 } 1478 1479 mode = 0; 1480 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 1481 SOC_IF_ERROR_RETURN 1482 (READ_PHY8072_AN_REG(unit, pc, AN_LP_ABILITY_1_REG, &lp_abil)); 1483 mode |= (lp_abil & AN_ADVERT_1G) ? SOC_PA_SPEED_1000MB : 0; 1484 mode |= (lp_abil & AN_ADVERT_10G) ? SOC_PA_SPEED_10GB : 0; 1485 ability->speed_full_duplex = mode; 1486 1487 if (pc->phy_id1 == PHY_ID1_8073) { 1488 SOC_IF_ERROR_RETURN 1489 (READ_PHY8072_AN_REG(unit, pc, 0x832C, &lp_abil)); 1490 if (lp_abil & 0x1) { 1491 ability->speed_full_duplex |= SOC_PA_SPEED_2500MB; 1492 } 1493 } 1494 1495 SOC_IF_ERROR_RETURN 1496 (READ_PHY8072_AN_REG(unit, pc, AN_LP_ABILITY_0_REG, &lp_abil)); 1497 1498 ability->pause = 0; 1499 switch (lp_abil & (AN_ADVERT_PAUSE | AN_ADVERT_PAUSE_ASYM)) { 1500 case AN_ADVERT_PAUSE: 1501 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1502 break; 1503 case AN_ADVERT_PAUSE_ASYM: 1504 ability->pause = SOC_PA_PAUSE_TX; 1505 break; 1506 case AN_ADVERT_PAUSE | AN_ADVERT_PAUSE_ASYM: 1507 ability->pause = SOC_PA_PAUSE_RX; 1508 break; 1509 } 1510 1511 SOC_IF_ERROR_RETURN 1512 (phy_8072_speed_get(unit,port,&speed)); 1513 1514 if (speed == 1000) { /* add clause37 attributes */ 1515 SOC_IF_ERROR_RETURN 1516 (READ_PHY8072_AN_REG(unit, pc, 0xFFE5, &lp_abil_cl37)); 1517 ability->speed_full_duplex |= 1518 (lp_abil_cl37 & MII_ANA_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1519 1520 switch (lp_abil_cl37 & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 1521 case MII_ANP_C37_PAUSE: 1522 ability->pause |= SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1523 break; 1524 case MII_ANP_C37_ASYM_PAUSE: 1525 ability->pause |= SOC_PA_PAUSE_TX; 1526 break; 1527 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 1528 ability->pause |= SOC_PA_PAUSE_RX; 1529 break; 1530 } 1531 } 1532 ability->interface = SOC_PA_INTF_XGMII; 1533 ability->medium = SOC_PA_MEDIUM_FIBER; 1534 ability->loopback = SOC_PA_LB_PHY; 1535 SOC_IF_ERROR_RETURN 1536 (READ_PHY8072_AN_REG(unit, pc, AN_STATUS_REG, &lp_abil)); 1537 ability->flags = (lp_abil & AN_LP_AN_ABILITY) ? SOC_PA_AUTONEG : 0; 1538 1539 LOG_INFO(BSL_LS_SOC_PHY, 1540 (BSL_META_U(unit, 1541 "phy_8072_ability_remote_get: u=%d p=%d speed=0x%x pause=0x%x\n"), 1542 unit, port, ability->speed_full_duplex, ability->pause)); 1543 1544 return (SOC_E_NONE); 1545 } 1546 1547 /* 1548 * Function: 1549 * phy_8072_rom_wait 1550 * 1551 * Purpose: 1552 * Wait for data to be written to the SPI-ROM. 1553 * Input: 1554 * unit, port 1555 */ 1556 STATIC int 1557 phy_8072_rom_wait(int unit, int port) 1558 { 1559 uint16 rd_data; 1560 uint16 wr_data; 1561 int count; 1562 phy_ctrl_t *pc; 1563 soc_timeout_t to; 1564 int SPI_READY; 1565 1566 pc = EXT_PHY_SW_STATE(unit, port); 1567 1568 rd_data = 0; 1569 soc_timeout_init(&to, WR_TIMEOUT, 0); 1570 do { 1571 /* 1572 * Write SPI Control Register Read Command. 1573 */ 1574 count = 1; 1575 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 1576 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1577 wr_data = SPI_CTRL_1_L; 1578 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1579 if (rd_data & 0x0100) { 1580 break; 1581 } 1582 } while (!soc_timeout_check(&to)); 1583 if (!(rd_data & 0x0100)) { 1584 LOG_ERROR(BSL_LS_SOC_PHY, 1585 (BSL_META_U(unit, 1586 "phy 8072 : u = %d p = %d timeout 1\n"), 1587 unit, port)); 1588 SOC_IF_ERROR_RETURN(SOC_E_TIMEOUT); 1589 } 1590 1591 SPI_READY = 1; 1592 while (SPI_READY == 1) { 1593 /* 1594 * Set-up SPI Controller To Receive SPI EEPROM Status. 1595 */ 1596 count = 1; 1597 wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count); 1598 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1599 wr_data = SPI_CTRL_2_H; 1600 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1601 wr_data = 0x0100; 1602 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1603 /* 1604 * Fill-up SPI Transmit Fifo To check SPI Status. 1605 */ 1606 count = 2; 1607 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1608 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1609 /* 1610 * Write Tx Fifo Register Address. 1611 */ 1612 wr_data = SPI_TXFIFO; 1613 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1614 1615 /* 1616 * Write SPI Tx Fifo Control Word-1. 1617 */ 1618 wr_data = ((1 * 0x0100) | MSGTYPE_HRD); 1619 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1620 /* 1621 * Write SPI Tx Fifo Control Word-2. 1622 */ 1623 wr_data = RDSR_OPCODE; 1624 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1625 /* 1626 * Write SPI Control Register Write Command. 1627 */ 1628 count = 2; 1629 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1630 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1631 /* 1632 * Write SPI Control -1 Register Address. 1633 */ 1634 wr_data = SPI_CTRL_1_L; 1635 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1636 /* 1637 * Write SPI Control -1 Register Word-1. 1638 */ 1639 wr_data = 0x0101; 1640 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1641 /* 1642 * Write SPI Control -1 Register Word-2. 1643 */ 1644 wr_data = 0x0100; 1645 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1646 /* 1647 * Write SPI Control Register Write Command. 1648 */ 1649 count = 1; 1650 wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count); 1651 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1652 /* 1653 * Write SPI Control -1 Register Address. 1654 */ 1655 wr_data = SPI_CTRL_1_H; 1656 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1657 /* 1658 * Write SPI Control -1 Register Word-2. 1659 */ 1660 wr_data = 0x0103; 1661 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1662 /* 1663 * Wait For 64 bytes To be written. 1664 */ 1665 rd_data = 0x0000; 1666 soc_timeout_init(&to, WR_TIMEOUT, 0); 1667 do { 1668 count = 1; 1669 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 1670 SOC_IF_ERROR_RETURN(write_message 1671 (unit, pc, wr_data, &rd_data)); 1672 wr_data = SPI_CTRL_1_L; 1673 SOC_IF_ERROR_RETURN(write_message 1674 (unit, pc, wr_data, &rd_data)); 1675 if (rd_data & 0x0100) { 1676 break; 1677 } 1678 } while (!soc_timeout_check(&to)); 1679 if (!(rd_data & 0x0100)) { 1680 LOG_ERROR(BSL_LS_SOC_PHY, 1681 (BSL_META_U(unit, 1682 "phy 8072 : u = %d p = %d timeout 2\n"), 1683 unit, port)); 1684 SOC_IF_ERROR_RETURN(SOC_E_TIMEOUT); 1685 } 1686 /* 1687 * Write SPI Control Register Read Command. 1688 */ 1689 count = 1; 1690 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 1691 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1692 /* 1693 * Write SPI Control -1 Register Address. 1694 */ 1695 wr_data = SPI_RXFIFO; 1696 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1697 if ((rd_data & 0x1) == 0) { 1698 SPI_READY = 0; 1699 } 1700 } /* SPI_READY */ 1701 return SOC_E_NONE; 1702 } 1703 1704 /* 1705 * Function: 1706 * phy_8072_rom_write_enable_set 1707 * 1708 * Purpose: 1709 * Enable disable protection on SPI_EEPROM 1710 * 1711 * Input: 1712 * unit 1713 * port 1714 * enable 1715 * Output: 1716 * SOC_E_xxx 1717 * 1718 * Notes: 1719 * 25AA256 256Kbit Serial EEPROM 1720 * STATUS Register 1721 * +------------------------------------------+ 1722 * | WPEN | x | x | x | BP1 | BP0 | WEL | WIP | 1723 * +------------------------------------------+ 1724 * BP1 BP0 : Protected Blocks 1725 * 0 0 : Protect None 1726 * 1 1 : Protect All 1727 * 1728 * WEL : Write Latch Enable 1729 * 0 : Do not allow writes 1730 * 1 : Allow writes 1731 */ 1732 1733 STATIC int 1734 phy_8072_rom_write_enable_set(int unit, int port, int enable) 1735 { 1736 uint16 rd_data; 1737 uint16 wr_data; 1738 uint8 wrsr_data; 1739 int count; 1740 phy_ctrl_t *pc; 1741 1742 pc = EXT_PHY_SW_STATE(unit, port); 1743 1744 /* 1745 * Write SPI Control Register Write Command. 1746 */ 1747 count = 2; 1748 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1749 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1750 1751 /* 1752 * Write SPI Control -2 Register Address. 1753 */ 1754 wr_data = SPI_CTRL_2_L; 1755 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1756 1757 /* 1758 * Write SPI Control -2 Register Word-1. 1759 */ 1760 wr_data = 0x8200; 1761 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1762 1763 /* 1764 * Write SPI Control -2 Register Word-2. 1765 */ 1766 wr_data = 0x0100; 1767 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1768 1769 /* 1770 * Fill-up SPI Transmit Fifo With SPI EEPROM Messages. 1771 * Write SPI Control Register Write Command. 1772 */ 1773 count = 4; 1774 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1775 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1776 1777 /* 1778 * Write Tx Fifo Register Address. 1779 */ 1780 wr_data = SPI_TXFIFO; 1781 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1782 1783 /* 1784 * Write SPI Tx Fifo Control Word-1. 1785 */ 1786 wr_data = ((1 * 0x0100) | MSGTYPE_HWR); 1787 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1788 1789 /* 1790 * Write SPI Tx Fifo Control Word-2. 1791 */ 1792 wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE); 1793 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1794 1795 /* 1796 * Write SPI Tx Fifo Control Word-3. 1797 */ 1798 wr_data = ((WRSR_OPCODE * 0x100) | (0x2)); 1799 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1800 1801 /* 1802 * Write SPI Tx Fifo Control Word-4. 1803 */ 1804 wrsr_data = enable ? 0x2 : 0xc; 1805 wr_data = ((wrsr_data * 0x0100) | wrsr_data); 1806 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1807 1808 /* 1809 * Write SPI Control Register Write Command. 1810 */ 1811 count = 2; 1812 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1813 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1814 1815 /* 1816 * Write SPI Control -1 Register Address. 1817 */ 1818 wr_data = SPI_CTRL_1_L; 1819 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1820 1821 /* 1822 * Write SPI Control -1 Register Word-1. 1823 */ 1824 wr_data = 0x0101; 1825 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1826 1827 /* 1828 * Write SPI Control -1 Register Word-2. 1829 */ 1830 wr_data = 0x0003; 1831 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1832 1833 /* 1834 * Wait For WRSR Command To be written. 1835 */ 1836 SOC_IF_ERROR_RETURN(phy_8072_rom_wait(unit, port)); 1837 1838 return SOC_E_NONE; 1839 } 1840 1841 /* 1842 * Function: 1843 * phy_8072_firmware_set 1844 * Purpose: 1845 * program the given firmware into the SPI-ROM 1846 * Parameters: 1847 * unit - StrataSwitch unit #. 1848 * port - StrataSwitch port #. 1849 * offset - offset to the data stream 1850 * array - the given data 1851 * datalen- the data length 1852 * Returns: 1853 * SOC_E_NONE 1854 */ 1855 1856 STATIC int 1857 phy_8072_firmware_set(int unit, int port, int offset, uint8 *array,int datalen) 1858 { 1859 1860 uint16 rd_data; 1861 uint16 wr_data; 1862 int j; 1863 int i = 0; 1864 int count; 1865 int phy_8074; 1866 phy_ctrl_t *pc; 1867 uint8 spi_values[WR_BLOCK_SIZE]; 1868 1869 pc = EXT_PHY_SW_STATE(unit, port); 1870 1871 phy_8074 = FALSE; 1872 1873 if (pc->phy_id1 == PHY_ID1_8073) { 1874 uint16 data; 1875 1876 SOC_IF_ERROR_RETURN 1877 (READ_PHY8072_PMA_PMD_REG(unit,pc,0xC802,&data)); 1878 if ( data == 0x8074 ) { 1879 phy_8074 = TRUE; 1880 /* Enable the SPI */ 1881 SOC_IF_ERROR_RETURN 1882 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc843, 0x0000, 0x000f)); 1883 SOC_IF_ERROR_RETURN 1884 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc840, 0x0000, 0x000c)); 1885 } 1886 } 1887 1888 /* 1889 * ser_boot pin HIGH 1890 */ 1891 SOC_IF_ERROR_RETURN 1892 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xCA85, 0x1, 0x1)); 1893 /* 1894 * Read LASI Status registers To clear initial Failure status. 1895 */ 1896 SOC_IF_ERROR_RETURN 1897 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9003, &rd_data)); 1898 SOC_IF_ERROR_RETURN 1899 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9004, &rd_data)); 1900 SOC_IF_ERROR_RETURN 1901 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9005, &rd_data)); 1902 1903 /* 1904 * Enable the LASI For Message out. 1905 */ 1906 SOC_IF_ERROR_RETURN 1907 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0x9000, 0x0004)); 1908 /* 1909 * 0x9002, bit 2 Is Rx Alarm enabled For LASI. 1910 */ 1911 SOC_IF_ERROR_RETURN 1912 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0x9002, 0x0004)); 1913 /* 1914 * Read Any Residual Message out register. 1915 */ 1916 SOC_IF_ERROR_RETURN 1917 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0xCA13, &rd_data)); 1918 /* 1919 * Clear LASI Message Out Status. 1920 */ 1921 SOC_IF_ERROR_RETURN 1922 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9003, &rd_data)); 1923 1924 /* set SPI-ROM write enable */ 1925 SOC_IF_ERROR_RETURN(phy_8072_rom_write_enable_set(unit, port, 1)); 1926 1927 LOG_INFO(BSL_LS_SOC_PHY, 1928 (BSL_META_U(unit, 1929 "init0: u=%d p=%d\n"), 1930 unit, port)); 1931 1932 for (j = 0; j < datalen; j += WR_BLOCK_SIZE) { 1933 /* 1934 * Setup SPI Controller. 1935 */ 1936 count = 2; 1937 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1938 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1939 1940 /* Write SPI Control -2 Register Address.*/ 1941 wr_data = SPI_CTRL_2_L; 1942 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1943 1944 /* Write SPI Control -2 Register Word-1. */ 1945 wr_data = 0x8200; 1946 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1947 1948 /* Write SPI Control -2 Register Word-2. */ 1949 wr_data = 0x0100; 1950 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1951 1952 /* Fill-up SPI Transmit Fifo. 1953 * Write SPI Control Register Write Command. 1954 */ 1955 count = 4 + (WR_BLOCK_SIZE / 2); 1956 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 1957 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1958 1959 /* Write Tx Fifo Register Address. */ 1960 wr_data = SPI_TXFIFO; 1961 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1962 1963 /* Write SPI Tx Fifo Control Word-1. */ 1964 wr_data = ((1 * 0x0100) | MSGTYPE_HWR); 1965 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1966 1967 /* Write SPI Tx Fifo Control Word-2. */ 1968 wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE); 1969 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1970 1971 /* Write SPI Tx Fifo Control Word-3. */ 1972 wr_data = ((WR_OPCODE * 0x0100) | (0x3 + WR_BLOCK_SIZE)); 1973 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1974 1975 /* Write SPI Tx Fifo Control Word-4. */ 1976 wr_data = (((j & 0x00FF) * 0x0100) | ((j & 0xFF00) / 0x0100)); 1977 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 1978 1979 LOG_INFO(BSL_LS_SOC_PHY, 1980 (BSL_META_U(unit, 1981 "loop: u=%d p=%d,inxj: %d,inxi:%d\n"), 1982 unit, port,j,i)); 1983 1984 if (datalen < (j + WR_BLOCK_SIZE)) { /* last block */ 1985 sal_memset(spi_values,0,WR_BLOCK_SIZE); 1986 sal_memcpy(spi_values,&array[j],datalen - j); 1987 1988 for (i = 0; i < WR_BLOCK_SIZE; i += 2) { 1989 /* Write SPI Tx Fifo Data Word-4. */ 1990 wr_data = ((spi_values[i+1] * 0x0100) | spi_values[i]); 1991 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data)); 1992 } 1993 } else { 1994 for (i = 0; i < WR_BLOCK_SIZE; i += 2) { 1995 /* Write SPI Tx Fifo Data Word-4. */ 1996 wr_data = ((array[j+i+1] * 0x0100) | array[j+i]); 1997 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data)); 1998 } 1999 } 2000 2001 /* 2002 * Set-up SPI Controller To Transmit. 2003 * Write SPI Control Register Write Command. 2004 */ 2005 count = 2; 2006 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 2007 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2008 2009 wr_data = SPI_CTRL_1_L; 2010 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2011 2012 /* Write SPI Control -1 Register Word-1. */ 2013 wr_data = 0x0501; 2014 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2015 2016 /* Write SPI Control -1 Register Word-2. */ 2017 wr_data = 0x0003; 2018 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2019 2020 /* Wait For 64 bytes To be written. */ 2021 SOC_IF_ERROR_RETURN(phy_8072_rom_wait(unit, port)); 2022 } 2023 2024 /* clear SPI-ROM write enable */ 2025 SOC_IF_ERROR_RETURN(phy_8072_rom_write_enable_set(unit, port, 0)); 2026 2027 /* Disable SPI EEPROM. */ 2028 count = 2; 2029 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 2030 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2031 2032 /* Write SPI Control -2 Register Address. */ 2033 wr_data = SPI_CTRL_2_L; 2034 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2035 2036 /* Write SPI Control -2 Register Word-1. */ 2037 wr_data = 0x8200; 2038 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2039 2040 /* Write SPI Control -2 Register Word-2. */ 2041 wr_data = 0x0100; 2042 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2043 2044 2045 /* Fill-up SPI Transmit Fifo With SPI EEPROM Messages. */ 2046 count = 2; 2047 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 2048 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2049 2050 /* Write Tx Fifo Register Address. */ 2051 wr_data = SPI_TXFIFO; 2052 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2053 2054 /* Write SPI Tx Fifo Control Word-1. */ 2055 wr_data = ((0x1*0x0100) | MSGTYPE_HWR); 2056 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2057 2058 /* Write SPI Tx Fifo Control Word-2. */ 2059 wr_data = WRDI_OPCODE; 2060 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2061 2062 /* Write SPI Control Register Write Command. */ 2063 count = 2; 2064 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 2065 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2066 2067 /* Write SPI Control -1 Register Address. */ 2068 wr_data = SPI_CTRL_1_L; 2069 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2070 2071 /* Write SPI Control -1 Register Word-1. */ 2072 wr_data = 0x0101; 2073 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2074 2075 /* Write SPI Control -1 Register Word-2. */ 2076 wr_data = 0x0003; 2077 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 2078 2079 /* 2080 * ser_boot pin LOW 2081 */ 2082 SOC_IF_ERROR_RETURN 2083 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xCA85, 0x0, 0x1)); 2084 2085 if (phy_8074) { 2086 SOC_IF_ERROR_RETURN 2087 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc843, 0x000f, 0x000f)); 2088 SOC_IF_ERROR_RETURN 2089 (MODIFY_PHY8072_PMA_PMD_REG(unit, pc, 0xc840, 0x000c, 0x000c)); 2090 } 2091 2092 LOG_INFO(BSL_LS_SOC_PHY, 2093 (BSL_META_U(unit, 2094 "phy_8072_rom_program: u=%d p=%d done\n"), unit, port)); 2095 2096 return SOC_E_NONE; 2097 } 2098 2099 static int 2100 write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, uint16 *rddata) 2101 { 2102 2103 uint16 tmp_data = 0; 2104 soc_timeout_t to; 2105 2106 SOC_IF_ERROR_RETURN 2107 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data)); 2108 SOC_IF_ERROR_RETURN 2109 (WRITE_PHY8072_PMA_PMD_REG(unit, pc, 0xCA12, wrdata)); 2110 2111 soc_timeout_init(&to, WR_TIMEOUT, 0); 2112 do { 2113 SOC_IF_ERROR_RETURN 2114 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9005, &tmp_data)); 2115 if (tmp_data & 0x4) 2116 break; 2117 } while (!soc_timeout_check(&to)); 2118 if (!(tmp_data & 0x4)) { 2119 LOG_ERROR(BSL_LS_SOC_PHY, 2120 (BSL_META_U(unit, 2121 "write_message failed: wrdata %04x\n"), wrdata)); 2122 return SOC_E_FAIL; 2123 } 2124 2125 SOC_IF_ERROR_RETURN 2126 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data)); 2127 *rddata = tmp_data; 2128 SOC_IF_ERROR_RETURN 2129 (READ_PHY8072_PMA_PMD_REG(unit, pc, 0x9003, &tmp_data)); 2130 2131 return SOC_E_NONE; 2132 } 2133 2134 /* 2135 * Variable: 2136 * phy_8072_drv 2137 * Purpose: 2138 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 2139 */ 2140 2141 phy_driver_t phy_8072drv_xe = { 2142 "8072 10-Gigabit PHY Driver", 2143 phy_8072_init, /* Init */ 2144 phy_null_reset, /* Reset (dummy) */ 2145 phy_8072_link_get, /* Link get */ 2146 phy_8072_enable_set, /* Enable set */ 2147 phy_null_enable_get, /* Enable get */ 2148 phy_null_set, /* Duplex set */ 2149 phy_null_one_get, /* Duplex get */ 2150 phy_8072_speed_set, /* Speed set */ 2151 phy_8072_speed_get, /* Speed get */ 2152 phy_null_set, /* Master set */ 2153 phy_null_zero_get, /* Master get */ 2154 phy_8072_an_set, /* ANA set */ 2155 phy_8072_an_get, /* ANA get */ 2156 NULL, /* Local Advert set */ 2157 NULL, /* Local Advert get */ 2158 NULL, /* Remote Advert get */ 2159 phy_8072_lb_set, /* PHY loopback set */ 2160 phy_8072_lb_get, /* PHY loopback set */ 2161 phy_null_interface_set, /* IO Interface set */ 2162 phy_xehg_interface_get, /* IO Interface get */ 2163 NULL, /* pd_ability, deprecated */ 2164 phy_8072_linkup_evt, 2165 NULL, 2166 phy_null_mdix_set, 2167 phy_null_mdix_get, 2168 phy_null_mdix_status_get, 2169 NULL, 2170 NULL, 2171 phy_null_medium_get, 2172 NULL, /* phy_cable_diag */ 2173 NULL, /* phy_link_change */ 2174 phy_8072_control_set, /* phy_control_set */ 2175 phy_8072_control_get, /* phy_control_get */ 2176 NULL, /* phy_reg_read */ 2177 NULL, /* phy_reg_write */ 2178 NULL, /* phy_reg_modify */ 2179 NULL, /* phy_notify */ 2180 phy_8072_probe, /* pd_probe */ 2181 phy_8072_ability_advert_set, /* pd_ability_advert_set */ 2182 phy_8072_ability_advert_get, /* pd_ability_advert_get */ 2183 phy_8072_ability_remote_get, /* pd_ability_remote_get */ 2184 phy_8072_ability_local_get, /* pd_ability_local_get */ 2185 phy_8072_firmware_set 2186 }; 2187 2188 phy_driver_t phy_8074drv_xe = { 2189 "8072 10-Gigabit PHY Driver", 2190 phy_8072_init, /* Init */ 2191 phy_null_reset, /* Reset (dummy) */ 2192 phy_8072_link_get, /* Link get */ 2193 phy_8072_enable_set, /* Enable set */ 2194 phy_null_enable_get, /* Enable get */ 2195 phy_null_set, /* Duplex set */ 2196 phy_null_one_get, /* Duplex get */ 2197 phy_8072_speed_set, /* Speed set */ 2198 phy_8072_speed_get, /* Speed get */ 2199 phy_null_set, /* Master set */ 2200 phy_null_zero_get, /* Master get */ 2201 phy_8072_an_set, /* ANA set */ 2202 phy_8072_an_get, /* ANA get */ 2203 NULL, /* Local Advert set */ 2204 NULL, /* Local Advert get */ 2205 NULL, /* Remote Advert get */ 2206 phy_8072_lb_set, /* PHY loopback set */ 2207 phy_8072_lb_get, /* PHY loopback set */ 2208 phy_null_interface_set, /* IO Interface set */ 2209 phy_xehg_interface_get, /* IO Interface get */ 2210 NULL, /* pd_ability, deprecated */ 2211 phy_8072_linkup_evt, 2212 NULL, 2213 phy_null_mdix_set, 2214 phy_null_mdix_get, 2215 phy_null_mdix_status_get, 2216 NULL, 2217 NULL, 2218 phy_null_medium_get, 2219 NULL, /* phy_cable_diag */ 2220 NULL, /* phy_link_change */ 2221 phy_8072_control_set, /* phy_control_set */ 2222 phy_8072_control_get, /* phy_control_get */ 2223 NULL, /* phy_reg_read */ 2224 NULL, /* phy_reg_write */ 2225 NULL, /* phy_reg_modify */ 2226 NULL, /* phy_notify */ 2227 phy_8074_probe, /* pd_probe */ 2228 phy_8072_ability_advert_set, /* pd_ability_advert_set */ 2229 phy_8072_ability_advert_get, /* pd_ability_advert_get */ 2230 phy_8072_ability_remote_get, /* pd_ability_remote_get */ 2231 phy_8072_ability_local_get, /* pd_ability_local_get */ 2232 phy_8072_firmware_set 2233 }; 2234 2235 #else /* INCLUDE_PHY_8072 */ 2236 int _phy_8072_not_empty; 2237 #endif /* INCLUDE_PHY_8072 */