phy8706.c (144983B)
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: phy8706.c 9 * Purpose: Phys Driver support for Broadcom 8706/8726 Serial 10Gig 10 * transceiver with XAUI interface. 11 * Note: To use this PHY driver, add phy_8706=1 config setting. 12 * PHY probing doesn't detect 8706 because the device ID is 13 * the same as 8705. 14 */ 15 16 #include <sal/types.h> 17 #include <shared/bsl.h> 18 #include <soc/drv.h> 19 #include <soc/debug.h> 20 #include <soc/error.h> 21 #include <soc/phyreg.h> 22 23 #include <soc/phy.h> 24 #include <soc/phy/phyctrl.h> 25 #include <soc/phy/drv.h> 26 27 #include "phydefs.h" /* Must include before other phy related includes */ 28 29 #if defined(INCLUDE_PHY_8706) 30 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 31 #include "phyident.h" 32 #include "phyreg.h" 33 #include "phynull.h" 34 #include "phyxehg.h" 35 #include "phy8706.h" 36 37 #define BCM8727_MICROCODE_LOAD_WAR 38 39 #ifdef INCLUDE_MACSEC 40 #include <soc/macsecphy.h> 41 #endif 42 43 /* typedefs */ 44 45 typedef struct { 46 uint16 tx_pol_ln0; 47 uint16 tx_pol_ln1; 48 uint16 tx_pol_ln2; 49 uint16 tx_pol_ln3; 50 uint16 rx_pol_ln0; 51 uint16 rx_pol_ln1; 52 uint16 rx_pol_ln2; 53 uint16 rx_pol_ln3; 54 uint16 tx_ln_swap; 55 uint16 rx_ln_swap; 56 uint16 preemph; 57 uint16 inband_mdio; 58 } XGXS_CFG_t; 59 60 typedef struct { 61 uint16 xgxsblk0_misccontrol1; 62 uint16 rx_all_rx_control; 63 } PHY5942_CFG_t; 64 65 typedef struct { 66 int cached_down_link; 67 } PHY8706_DEV_DESC_t; 68 69 /* device field macros */ 70 #define CACHED_DOWN_LINK(_pc) (((PHY8706_DEV_DESC_t *)((_pc) + 1))->cached_down_link) 71 72 /* 73 * phy's revision info, device 1 74 * Revision reg 0x0003 reg 0xC806 75 * A 0x6034 0x0010 76 * B0 0x6035 0x0010 77 * B1 0x6035 0x0011 78 * C0 0x6035 0x0012 79 */ 80 81 #define PHY87X6_REV_A 0x6034 82 #define PHY87X6_REV_BC 0x6035 83 #define PHY_ID1_8727 0x6036 84 #define PHY_ID1_8747 0x6037 85 #define PHY87X6_REV_ID_REG 0xc806 86 87 #define PHY_8706_PCS_LOOPBACK 1 88 89 #define IS_8727_TYPE(phyid1) (((phyid1) == PHY_ID1_8727) || ((phyid1) == PHY_ID1_8747)) 90 91 #define PHY_IS_BCM5942(_pc) PHY_FLAGS_TST((_pc)->unit, (_pc)->port, \ 92 PHY_FLAGS_SECONDARY_SERDES) 93 94 #if 0 95 #define PHY_8706_PMA_PMD_LOOPBACK 1 96 #define PHY_8706_SYSTEM_LOOPBACK 1 97 #define PHY_8706_XAUI_LOOPBACK 1 98 #endif 99 100 /* 101 * SPI-ROM Program related defs 102 */ 103 #define SPI_CTRL_1_L 0xC000 104 #define SPI_CTRL_1_H 0xC002 105 #define SPI_CTRL_2_L 0xC400 106 #define SPI_CTRL_2_H 0xC402 107 #define SPI_TXFIFO 0xD000 108 #define SPI_RXFIFO 0xD400 109 #define WR_CPU_CTRL_REGS 0x11 110 #define RD_CPU_CTRL_REGS 0xEE 111 #define WR_CPU_CTRL_FIFO 0x66 112 /* 113 * SPI Controller Commands(Messages). 114 */ 115 #define MSGTYPE_HWR 0x40 116 #define MSGTYPE_HRD 0x80 117 #define WRSR_OPCODE 0x01 118 #define WR_OPCODE 0x02 119 #define WRDI_OPCODE 0x04 120 #define RDSR_OPCODE 0x05 121 #define WREN_OPCODE 0x06 122 #define WR_BLOCK_SIZE 0x40 123 #define TOTAL_WR_BYTE 0x4000 124 125 /* I2C related defines */ 126 #define PHY_8727_BSC_XFER_MAX 0x1F9 127 #define PHY_8727_BSC_WR_MAX 16 128 #define PHY_8727_WRITE_START_ADDR 0x8007 129 #define PHY_8727_READ_START_ADDR 0x8007 130 #define PHY_8727_WR_FREQ_400KHZ 0x0100 131 #define PHY_8727_2W_STAT 0x000C 132 #define PHY_8727_2W_STAT_IDLE 0x0000 133 #define PHY_8727_2W_STAT_COMPLETE 0x0004 134 #define PHY_8727_2W_STAT_IN_PRG 0x0008 135 #define PHY_8727_2W_STAT_FAIL 0x000C 136 #define PHY_8727_BSC_WRITE_OP 0x22 137 #define PHY_8727_BSC_READ_OP 0x2 138 #define PHY_8727_I2CDEV_WRITE 0x1 139 #define PHY_8727_I2CDEV_READ 0x0 140 #define PHY_8727_I2C_8BIT 0 141 #define PHY_8727_I2C_16BIT 1 142 #define PHY_8727_I2C_TEMP_RAM 0xE 143 #define PHY_8727_I2C_OP_TYPE(access_type,data_type) \ 144 ((access_type) | ((data_type) << 8)) 145 #define PHY_8727_I2C_ACCESS_TYPE(op_type) ((op_type) & 0xff) 146 #define PHY_8727_I2C_DATA_TYPE(op_type) (((op_type) >> 8) & 0xff) 147 #define PHY_8727_VERSION_C 7 148 #define PHY_8727_EDC_AUTO_CONFIG_MASK (1<<10) 149 #define PHY_8727_EDC_MODE_MASK 0xff 150 151 /* SFP EEPROM defines */ 152 #define EEPROM_I2C_ADDR 0x50 153 #define SFP_ID 0 154 #define SFP_TRCVER_CODE0 3 155 #define SFP_TRCVER_CODE3 6 156 #define SFP_TRCVER_CODE5 8 157 #define SFP_TYPE_SFP_PLUS 0x3 158 #define SFP_TRCVER_10G_ER (1<<7) 159 #define SFP_TRCVER_10G_LRM (1<<6) 160 #define SFP_TRCVER_10G_LR (1<<5) 161 #define SFP_TRCVER_10G_SR (1<<4) 162 #define SFP_TRCVER_PASSIVE_CABLE (1<<2) 163 #define SFP_TRCVER_ACTIVE_CABLE (1<<3) 164 #define SFP_TRCVER_1000BASE_T (1<<3) 165 #define SFP_TRCVER_1000BASE_CX (1<<2) 166 #define SFP_TRCVER_1000BASE_LX (1<<1) 167 #define SFP_TRCVER_1000BASE_SX (1<<0) 168 #define SFP_8431_COMPLIANCE (1<<0) 169 #define SFP_8431_LIMITED_COMPLIANCE (1<<2) 170 #define SFP_8431_APPENDIX_E_COMPLIANCE (1<<0) 171 172 #define NXT_PC(pc) ((phy_ctrl_t *)((pc)->driver_data)) 173 #define PHYDRV_CALL_NOARG(pc,name) \ 174 do { \ 175 if (pc->driver_data) { \ 176 int rv; \ 177 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE(pc->unit, pc->port); \ 178 EXT_PHY_SW_STATE(pc->unit,pc->port) = (phy_ctrl_t *)(pc->driver_data); \ 179 rv = name(((phy_ctrl_t *)(pc->driver_data))->pd,(pc)->unit,(pc)->port); \ 180 EXT_PHY_SW_STATE(pc->unit, pc->port) = tmp_pc; \ 181 if (SOC_FAILURE(rv)) { \ 182 return rv; \ 183 } \ 184 } \ 185 } while(0) 186 187 #define PHYDRV_CALL_ARG1(pc,name,arg0) \ 188 do { \ 189 if (pc->driver_data) { \ 190 int rv; \ 191 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE(pc->unit, pc->port); \ 192 EXT_PHY_SW_STATE(pc->unit, pc->port) = (phy_ctrl_t *)(pc->driver_data); \ 193 rv = name(((phy_ctrl_t *)(pc->driver_data))->pd,(pc)->unit, \ 194 (pc)->port,arg0); \ 195 EXT_PHY_SW_STATE(pc->unit, pc->port) = tmp_pc; \ 196 if (SOC_FAILURE(rv)) { \ 197 return rv; \ 198 } \ 199 } \ 200 } while(0) 201 202 #define PHYDRV_CALL_ARG2(pc,name,arg0,arg1) \ 203 do { \ 204 if (pc->driver_data) { \ 205 int rv; \ 206 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE(pc->unit, pc->port); \ 207 EXT_PHY_SW_STATE(pc->unit, pc->port) = (phy_ctrl_t *)(pc->driver_data); \ 208 rv=name(((phy_ctrl_t *)(pc->driver_data))->pd,(pc)->unit,(pc)->port,arg0, \ 209 arg1); \ 210 EXT_PHY_SW_STATE(pc->unit, pc->port) = tmp_pc; \ 211 if (SOC_FAILURE(rv)) { \ 212 return rv; \ 213 } \ 214 } \ 215 } while(0) 216 217 #define PHYDRV_CALL_ARG3(pc,name,arg0,arg1,arg2) \ 218 do { \ 219 if (pc->driver_data) { \ 220 int rv; \ 221 phy_ctrl_t * tmp_pc = EXT_PHY_SW_STATE(pc->unit, pc->port); \ 222 EXT_PHY_SW_STATE(pc->unit, pc->port) = (phy_ctrl_t *)(pc->driver_data); \ 223 rv=name(((phy_ctrl_t *)(pc->driver_data))->pd,(pc)->unit,(pc)->port,arg0, \ 224 arg1,arg2); \ 225 EXT_PHY_SW_STATE(pc->unit, pc->port) = tmp_pc; \ 226 if (SOC_FAILURE(rv)) { \ 227 return rv; \ 228 } \ 229 } \ 230 } while(0) 231 232 /* Local functions */ 233 STATIC int _phy_8727_firmware_ram_set(int unit, int port, int offset, 234 uint8 *array,int datalen); 235 STATIC int _phy_8747_firmware_ram_set(int unit, int port, int offset, 236 uint8 *array,int datalen); 237 STATIC int _phy_8706_speed_set(int unit, soc_port_t port, int speed); 238 239 STATIC int phy_8706_speed_get(int unit, soc_port_t port, int *speed); 240 241 /* External functions and variables */ 242 243 extern unsigned char phy8727c_ucode_bin[]; 244 extern unsigned int phy8727c_ucode_bin_len; 245 extern unsigned char phy8747_ucode_bin[]; 246 extern unsigned int phy8747_ucode_bin_len; 247 248 #define WR_TIMEOUT 1000000 249 static int write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, uint16 * rddata); 250 251 STATIC int _phy_8706_speed_get(int, soc_port_t, int *); 252 int phy_8727_i2cdev_read(int unit, soc_port_t port, int dev_addr, 253 int offset, int nbytes, uint8 *read_array); 254 255 STATIC int 256 _bcm8726_pmad_write_en(int unit, phy_ctrl_t *pc, int enable) 257 { 258 if ( pc->phy_id1 == PHY87X6_REV_BC) { 259 uint16 data; 260 SOC_IF_ERROR_RETURN 261 (READ_PHY8706_PMA_PMD_REG(unit, pc, PHY87X6_REV_ID_REG, &data)); 262 if ((data == 0x0011) || (data == 0x0012)) { 263 SOC_IF_ERROR_RETURN 264 (WRITE_PHY8706_AN_REG(unit, pc, 0x800d, enable ? 0x400d : 0x4009)); 265 LOG_INFO(BSL_LS_SOC_PHY, 266 (BSL_META_U(unit, 267 "_bcm8726_pmad_write_en: unit=%d port=%d\n"), unit, pc->port)); 268 } 269 } 270 return SOC_E_NONE; 271 } 272 273 /* 274 * Squelch enable/disable 275 * 1) 10G XAUI output squelching enable: 1.C842.12=1 AND 1.C842.11=0; 276 * 2) 1G XAUI output squelching enable: 1.C842.10=1 277 */ 278 STATIC int 279 _phy_8706_squelch_enable(int unit, soc_port_t port, int enable) 280 { 281 phy_ctrl_t *pc; 282 uint16 data16, mask16; 283 int speed; 284 285 pc = EXT_PHY_SW_STATE(unit, port); 286 287 if (PHY_IS_BCM5942(pc)) { 288 /* no squelch support in reverse mode - do nothing */ 289 return SOC_E_NONE; 290 } 291 292 if (!IS_8727_TYPE(pc->phy_id1)) { 293 /* no squelch support on non-8727/8728/8747 - do nothing */ 294 return SOC_E_NONE; 295 } 296 297 SOC_IF_ERROR_RETURN 298 (phy_8706_speed_get(unit, port, &speed)); 299 300 if (speed == 10000) { 301 mask16 = (1<<12); 302 data16 = enable ? mask16 : 0; 303 mask16 = ((1<<12) | (1<<11)); 304 SOC_IF_ERROR_RETURN 305 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xC842, data16, mask16)); 306 } else { 307 mask16 = (1<<10); 308 data16 = enable ? mask16 : 0; 309 SOC_IF_ERROR_RETURN 310 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xC842, data16, mask16)); 311 } 312 313 return SOC_E_NONE; 314 } 315 316 #ifndef BCM8727_MICROCODE_LOAD_WAR 317 318 STATIC int 319 _8727_rom_load(int unit, int port, phy_ctrl_t *pc) 320 { 321 SOC_IF_ERROR_RETURN 322 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x0001)); 323 sal_usleep(1000); 324 325 SOC_IF_ERROR_RETURN 326 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x008C)); 327 sal_usleep(1000); 328 SOC_IF_ERROR_RETURN 329 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca85, 0x0001)); 330 331 sal_usleep(1000); 332 SOC_IF_ERROR_RETURN 333 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x018A)); 334 SOC_IF_ERROR_RETURN 335 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x0188)); 336 337 /* Wait for atleast 100ms for code to download via SPI port*/ 338 sal_usleep(200000); 339 340 SOC_IF_ERROR_RETURN 341 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca85, 0x0000)); 342 343 sal_usleep(100000); 344 return SOC_E_NONE; 345 } 346 347 #else 348 349 STATIC int 350 _8727_rom_load_war(int unit, int port, phy_ctrl_t *pc) 351 { 352 int delta1=0, delta2=0; 353 uint16 status1, status2, rev, data16; 354 soc_timeout_t to; 355 int rv; 356 357 SOC_IF_ERROR_RETURN 358 (pc->read(unit, pc->phy_id, SOC_PHY_CLAUSE45_ADDR(0x1,0xc801), &rev)); 359 360 if ((rev == 0x2) || (rev == 0x3)) { 361 /* revA or revB */ 362 if (pc->phy_id & 0x1) { 363 /* We are in channel 2 */ 364 SOC_IF_ERROR_RETURN 365 (pc->read(unit, pc->phy_id-1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca1c), &status1)); 366 SOC_IF_ERROR_RETURN 367 (pc->read(unit, pc->phy_id, SOC_PHY_CLAUSE45_ADDR(0x1,0xca1c), &status2)); 368 LOG_INFO(BSL_LS_SOC_PHY, 369 (BSL_META_U(unit, 370 "Channel 2: PRTAD = %x status1 = %x Status2 = %x\n"), 371 pc->phy_id, status1, status2)); 372 if ((status1 == 0x600d) && (status2 == 0x600d)) { 373 return SOC_E_NONE; 374 } else { 375 delta2=0; 376 delta1=-1; 377 } 378 } else { 379 /* We are in channel 1 */ 380 SOC_IF_ERROR_RETURN 381 (pc->read(unit, pc->phy_id, SOC_PHY_CLAUSE45_ADDR(0x1,0xca1c), &status1)); 382 SOC_IF_ERROR_RETURN 383 (pc->read(unit, pc->phy_id+1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca1c), &status2)); 384 LOG_INFO(BSL_LS_SOC_PHY, 385 (BSL_META_U(unit, 386 "Channel 1: PRTAD = %x status1 = %x Status2 = %x\n"), 387 pc->phy_id, status1, status2)); 388 if ((status1 == 0x600d) && (status2 == 0x600d)) { 389 return SOC_E_NONE; 390 } else { 391 delta2=1; 392 delta1=0; 393 } 394 } 395 396 /* Reset the device */ 397 398 SOC_IF_ERROR_RETURN 399 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0x0), MII_CTRL_RESET)); 400 401 SOC_IF_ERROR_RETURN 402 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x3,0x0), MII_CTRL_RESET)); 403 404 SOC_IF_ERROR_RETURN 405 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x4,0x0), MII_CTRL_RESET)); 406 407 /* Wait for device to come out of reset */ 408 soc_timeout_init(&to, 10000, 0); 409 while (!soc_timeout_check(&to)) { 410 rv = pc->read(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x4,0x0), &data16); 411 if (((data16 & MII_CTRL_RESET) == 0) || 412 SOC_FAILURE(rv)) { 413 break; 414 } 415 } 416 if ((data16 & MII_CTRL_RESET) != 0) { 417 LOG_WARN(BSL_LS_SOC_PHY, 418 (BSL_META_U(unit, 419 "PHY8706/8726 reset failed: u=%d p=%d\n"), 420 unit, pc->port)); 421 } 422 sal_usleep(10000); 423 424 /* load microcode into channel 2 first */ 425 426 SOC_IF_ERROR_RETURN 427 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x0001)); 428 sal_usleep(1000); 429 430 SOC_IF_ERROR_RETURN 431 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x008C)); 432 sal_usleep(1000); 433 434 SOC_IF_ERROR_RETURN 435 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca85), 0x0001)); 436 437 sal_usleep(1000); 438 SOC_IF_ERROR_RETURN 439 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x018A)); 440 SOC_IF_ERROR_RETURN 441 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x0188)); 442 443 /* Wait for atleast 100ms for code to download via SPI port*/ 444 sal_usleep(200000); 445 446 SOC_IF_ERROR_RETURN 447 (pc->write(unit, pc->phy_id+delta2, SOC_PHY_CLAUSE45_ADDR(0x1,0xca85), 0x0000)); 448 449 sal_usleep(100000); 450 } 451 452 /* now into channel 1 if revA or revB, if not do regular microcode load as delta1=0 */ 453 454 /* Reset the device */ 455 456 SOC_IF_ERROR_RETURN 457 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0x0), MII_CTRL_RESET)); 458 459 SOC_IF_ERROR_RETURN 460 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x3,0x0), MII_CTRL_RESET)); 461 462 SOC_IF_ERROR_RETURN 463 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x4,0x0), MII_CTRL_RESET)); 464 465 /* Wait for device to come out of reset */ 466 soc_timeout_init(&to, 10000, 0); 467 while (!soc_timeout_check(&to)) { 468 rv = pc->read(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x4,0x0), &data16); 469 if (((data16 & MII_CTRL_RESET) == 0) || 470 SOC_FAILURE(rv)) { 471 break; 472 } 473 } 474 if ((data16 & MII_CTRL_RESET) != 0) { 475 LOG_WARN(BSL_LS_SOC_PHY, 476 (BSL_META_U(unit, 477 "PHY8706/8726 reset failed: u=%d p=%d\n"), 478 unit, pc->port)); 479 } 480 sal_usleep(10000); 481 482 SOC_IF_ERROR_RETURN 483 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x0001)); 484 sal_usleep(1000); 485 486 SOC_IF_ERROR_RETURN 487 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x008C)); 488 sal_usleep(1000); 489 490 SOC_IF_ERROR_RETURN 491 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca85), 0x0001)); 492 493 sal_usleep(1000); 494 SOC_IF_ERROR_RETURN 495 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x018A)); 496 SOC_IF_ERROR_RETURN 497 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca10), 0x0188)); 498 499 /* Wait for atleast 100ms for code to download via SPI port*/ 500 sal_usleep(200000); 501 502 SOC_IF_ERROR_RETURN 503 (pc->write(unit, pc->phy_id+delta1, SOC_PHY_CLAUSE45_ADDR(0x1,0xca85), 0x0000)); 504 505 sal_usleep(100000); 506 507 return SOC_E_NONE; 508 } 509 510 #endif 511 512 STATIC int 513 _8726_rom_load(int unit, int port, phy_ctrl_t *pc) 514 { 515 SOC_IF_ERROR_RETURN 516 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca85, 0x0001)); 517 sal_usleep(1000); 518 519 SOC_IF_ERROR_RETURN 520 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x0188)); 521 sal_usleep(1000); 522 SOC_IF_ERROR_RETURN 523 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x018A)); 524 sal_usleep(1000); 525 526 SOC_IF_ERROR_RETURN 527 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca1e, 0x73A0)); 528 sal_usleep(1000); 529 SOC_IF_ERROR_RETURN 530 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x0188)); 531 532 /* Wait for atleast 100ms for code to download via SPI port*/ 533 sal_usleep(200000); 534 535 SOC_IF_ERROR_RETURN 536 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca85, 0x0000)); 537 538 sal_usleep(1000); 539 return SOC_E_NONE; 540 } 541 542 STATIC int 543 _8747_rom_load(int unit, int port, phy_ctrl_t *pc) 544 { 545 uint16 phy_addr; 546 int i; 547 548 phy_addr = pc->phy_id & 0xfffc; 549 550 for(i = 0; i < 4; i++) { 551 /* Disable SPI for all ports, return value ignored on purpose */ 552 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc843), 0x000f); 553 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc840), 0x000C); 554 555 /* Set bit SPI Download (15), SER Boot (14) And SPI Port Enable (0) In C848, SPI_PORT_CTRL */ 556 pc->write(unit, phy_addr+i,SOC_PHY_CLAUSE45_ADDR(1, 0xc848), 0xC0F1); 557 } 558 559 /* Place Micro in reset */ 560 SOC_IF_ERROR_RETURN 561 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x018f)); 562 563 /* Enable SPI */ 564 SOC_IF_ERROR_RETURN 565 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xc843, 0x0000)); 566 SOC_IF_ERROR_RETURN 567 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xc840, 0x0000)); 568 569 /* Remove M8051 resets */ 570 SOC_IF_ERROR_RETURN 571 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca10, 0x0188)); 572 573 /* The rest is moved outside this routine. */ 574 575 return SOC_E_NONE; 576 } 577 578 #define NEW_NAME_ARRAY_SIZE 25 579 STATIC int 580 _8726_nxt_dev_probe(int unit, soc_port_t port) 581 { 582 phy_ctrl_t *pc; 583 phy_ctrl_t phy_ctrl; 584 soc_phy_info_t phy_info; 585 extern int _ext_phy_probe(int unit, soc_port_t port,soc_phy_info_t *pi, 586 phy_ctrl_t *ext_pc); 587 soc_phy_info_t *pi; 588 int offset = 0; 589 char new_name[NEW_NAME_ARRAY_SIZE]; 590 591 pc = EXT_PHY_SW_STATE(unit, port); 592 593 /* initialize the phy_ctrl for the next device connected to the xaui port */ 594 sal_memset(&phy_ctrl, 0, sizeof(phy_ctrl_t)); 595 phy_ctrl.unit = unit; 596 phy_ctrl.port = port; 597 phy_ctrl.speed_max = pc->speed_max; 598 phy_ctrl.read = pc->read; /* use same MDIO read routine as this device's */ 599 phy_ctrl.write = pc->write; /* use same MDIO write routine as this device's */ 600 601 /* get the mdio address of the next device */ 602 phy_ctrl.phy_id = soc_property_port_get(unit, port, 603 spn_PORT_PHY_ADDR1, 0xff); 604 605 if (phy_ctrl.phy_id == 0xff) { 606 return SOC_E_NOT_FOUND; 607 } 608 609 /* probe the next device at the given address */ 610 SOC_IF_ERROR_RETURN 611 (_ext_phy_probe(unit, port, &phy_info, &phy_ctrl)); 612 613 /* If we have probed BCM8706/8726/8727 then we won't allow 614 * to chain (physically its not possible) another 8706. The Probe depends 615 * on spn_PORT_PHY_ADDR1 to probe 2nd level PHYs. It could so 616 * happen that 8706/8726 could be chained with 8481. In such cases 617 * probing could end up in a loop. 618 */ 619 if ((phy_ctrl.pd == NULL) || ((phy_ctrl.phy_model == pc->phy_model) && 620 (phy_ctrl.phy_oui == pc->phy_oui))) { 621 pc->driver_data = NULL; 622 /* device not found */ 623 return SOC_E_NOT_FOUND; 624 } 625 626 LOG_INFO(BSL_LS_SOC_PHY, 627 (BSL_META_U(unit, 628 "8726_nxt_dev_probe: found phy device" 629 " u=%d p=%d id0=0x%x id1=0x%x\n"), 630 unit, port,phy_ctrl.phy_id0,phy_ctrl.phy_id1)); 631 632 /* set the chained flag */ 633 PHY_FLAGS_SET(phy_ctrl.unit, phy_ctrl.port, PHY_FLAGS_CHAINED); 634 635 /* Found device, allocate control structure */ 636 pc->driver_data = (void *)sal_alloc (sizeof (phy_ctrl_t) + phy_ctrl.size, phy_ctrl.pd->drv_name); 637 if (pc->driver_data == NULL) { 638 return SOC_E_MEMORY; 639 } 640 sal_memcpy(pc->driver_data, &phy_ctrl, sizeof(phy_ctrl_t)); 641 642 /* We need to append the (chanined) PHY's name to the parent */ 643 pi = &SOC_PHY_INFO(unit, pc->port); 644 offset = sal_strlen(pi->phy_name); 645 /* size of new_name is 25 which is large enough */ 646 /* coverity[secure_coding] */ 647 sal_strcpy(new_name, (pi->phy_name)); 648 /* coverity[secure_coding] */ 649 sal_strcpy(new_name+offset, "->"); 650 offset = sal_strlen(new_name); 651 if ((offset + sal_strlen(phy_info.phy_name)) < NEW_NAME_ARRAY_SIZE) { 652 /* coverity[secure_coding] */ 653 sal_strcpy(new_name + offset, phy_info.phy_name); 654 } else { 655 return SOC_E_MEMORY; 656 } 657 pi->phy_name = sal_strdup(new_name); 658 659 return SOC_E_NONE; 660 } 661 #if defined(NEW_NAME_ARRAY_SIZE) 662 #undef NEW_NAME_ARRAY_SIZE 663 #endif 664 665 /* Function: 666 * phy_8727_opt_lvl_set 667 * Purpose: 668 * Reads SOC property settings for bits whose polarity is 669 * affected by the OPINLVL and OPOUTLVL pins and flips 670 * bits as required. 671 * Parameters: 672 * unit - StrataSwitch unit #. 673 * port - StrataSwitch port #. 674 * Returns: 675 * SOC_E_NONE 676 */ 677 STATIC int 678 phy_8727_opt_lvl_set(int unit, soc_port_t port) 679 { 680 phy_ctrl_t *pc; 681 int rv; 682 uint16 data16, original_data16; 683 684 pc = EXT_PHY_SW_STATE(unit, port); 685 686 SOC_IF_ERROR_RETURN 687 (READ_PHY8706_IDENTIFIERr(unit, pc, &data16)); 688 689 690 LOG_INFO(BSL_LS_SOC_PHY, 691 (BSL_META_U(unit, 692 "8727: u=%d p=%d Initial value 0xc800 = 0x%x\n"), 693 unit, port, data16)); 694 695 original_data16 = data16; 696 697 rv = soc_property_port_get(unit, port, spn_FORCE_OPTTXENBLVL, -1); 698 switch (rv) { 699 case FALSE: 700 data16 &= ~(1 << 15); 701 break; 702 case TRUE: 703 data16 |= (1 << 15); 704 break; 705 default: 706 /* do nothing if property not set */ 707 break; 708 } 709 710 rv = soc_property_port_get(unit, port, spn_FORCE_OPTTXRSTLVL, -1); 711 switch (rv) { 712 case FALSE: 713 data16 &= ~(1 << 14); 714 break; 715 case TRUE: 716 data16 |= (1 << 14); 717 break; 718 default: 719 /* do nothing if property not set */ 720 break; 721 } 722 723 rv = soc_property_port_get(unit, port, spn_FORCE_OPTBIASFLTLVL, -1); 724 switch (rv) { 725 case FALSE: 726 data16 &= ~(1 << 13); 727 break; 728 case TRUE: 729 data16 |= (1 << 13); 730 break; 731 default: 732 /* do nothing if property not set */ 733 break; 734 } 735 736 rv = soc_property_port_get(unit, port, spn_FORCE_OPTTEMPFLTLVL, -1); 737 switch (rv) { 738 case FALSE: 739 data16 &= ~(1 << 12); 740 break; 741 case TRUE: 742 data16 |= (1 << 12); 743 break; 744 default: 745 /* do nothing if property not set */ 746 break; 747 } 748 749 rv = soc_property_port_get(unit, port, spn_FORCE_OPTPRFLTLVL, -1); 750 switch (rv) { 751 case FALSE: 752 data16 &= ~(1 << 11); 753 break; 754 case TRUE: 755 data16 |= (1 << 11); 756 break; 757 default: 758 /* do nothing if property not set */ 759 break; 760 } 761 762 rv = soc_property_port_get(unit, port, spn_FORCE_OPTTXFLLVL, -1); 763 switch (rv) { 764 case FALSE: 765 data16 &= ~(1 << 10); 766 break; 767 case TRUE: 768 data16 |= (1 << 10); 769 break; 770 default: 771 /* do nothing if property not set */ 772 break; 773 } 774 775 rv = soc_property_port_get(unit, port, spn_FORCE_OPTRXLOSLVL, -1); 776 switch (rv) { 777 case FALSE: 778 data16 &= ~(1 << 9); 779 break; 780 case TRUE: 781 data16 |= (1 << 9); 782 break; 783 default: 784 /* do nothing if property not set */ 785 break; 786 } 787 788 rv = soc_property_port_get(unit, port, spn_FORCE_OPTRXFLTLVL, -1); 789 switch (rv) { 790 case 0: 791 data16 &= ~(1 << 8); 792 break; 793 case 1: 794 data16 |= (1 << 8); 795 break; 796 default: 797 /* do nothing if property not set */ 798 break; 799 } 800 801 rv = soc_property_port_get(unit, port, spn_FORCE_OPTTXONLVL, -1); 802 switch (rv) { 803 case FALSE: 804 data16 &= ~(1 << 7); 805 break; 806 case TRUE: 807 data16 |= (1 << 7); 808 break; 809 default: 810 /* do nothing if property not set */ 811 break; 812 } 813 814 LOG_INFO(BSL_LS_SOC_PHY, 815 (BSL_META_U(unit, 816 "8727: u=%d p=%d Final value 0xc800 = 0x%x\n"), 817 unit, port, data16)); 818 if (data16 != original_data16) { 819 SOC_IF_ERROR_RETURN 820 (WRITE_PHY8706_IDENTIFIERr(unit, pc, data16)); 821 } 822 823 return SOC_E_NONE; 824 } 825 826 827 /* Function: 828 * phy_8706_init 829 * Purpose: 830 * Initialize 8706 phys 831 * Parameters: 832 * unit - StrataSwitch unit #. 833 * port - StrataSwitch port #. 834 * Returns: 835 * SOC_E_NONE 836 */ 837 838 STATIC int 839 phy_8706_init(int unit, soc_port_t port) 840 { 841 uint16 phyid1; 842 soc_timeout_t to; 843 int rv; 844 uint16 data16,ucode_ver; 845 phy_ctrl_t *pc; 846 uint32 phy_ext_rom_boot; 847 char *str; 848 int reg; 849 uint16 rev_num; 850 uint16 mask16; 851 uint16 tmp; 852 853 pc = EXT_PHY_SW_STATE(unit, port); 854 855 PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER | PHY_FLAGS_C45); 856 857 phy_ext_rom_boot = soc_property_port_get(unit, port, 858 spn_PHY_EXT_ROM_BOOT, 1); 859 SOC_IF_ERROR_RETURN 860 (READ_PHY8706_PMA_PMD_REG(unit, pc, MII_PHY_ID1_REG, &phyid1)); 861 862 #ifdef BCM8727_MICROCODE_LOAD_WAR 863 if ((phyid1 != PHY_ID1_8727) || (!phy_ext_rom_boot)) 864 #endif 865 { 866 /* Reset the device */ 867 SOC_IF_ERROR_RETURN 868 (MODIFY_PHY8706_PMA_PMD_CTRLr(unit, pc, 869 MII_CTRL_RESET, MII_CTRL_RESET)); 870 871 SOC_IF_ERROR_RETURN 872 (MODIFY_PHY8706_PCS_CTRLr(unit, pc, 873 MII_CTRL_RESET, MII_CTRL_RESET)); 874 875 SOC_IF_ERROR_RETURN 876 (MODIFY_PHY8706_PHYXS_CTRLr(unit, pc, 877 MII_CTRL_RESET, MII_CTRL_RESET)); 878 879 /* Wait for device to come out of reset */ 880 soc_timeout_init(&to, 10000, 0); 881 while (!soc_timeout_check(&to)) { 882 rv = READ_PHY8706_PHYXS_CTRLr(unit, pc, &data16); 883 if (((data16 & MII_CTRL_RESET) == 0) || 884 SOC_FAILURE(rv)) { 885 break; 886 } 887 } 888 if ((data16 & MII_CTRL_RESET) != 0) { 889 LOG_WARN(BSL_LS_SOC_PHY, 890 (BSL_META_U(unit, 891 "PHY8706/8726 reset failed: u=%d p=%d\n"), 892 unit, port)); 893 } 894 } 895 896 if (phy_ext_rom_boot) { 897 if (phyid1 == PHY_ID1_8727) { 898 #ifdef BCM8727_MICROCODE_LOAD_WAR 899 _8727_rom_load_war(unit, port,pc); 900 #else 901 _8727_rom_load(unit, port,pc); 902 #endif 903 } else if (phyid1 == PHY_ID1_8747) { 904 _8747_rom_load(unit, port,pc); 905 } else { 906 _8726_rom_load(unit, port,pc); 907 } 908 } else { 909 if (phyid1 == PHY_ID1_8727) { 910 SOC_IF_ERROR_RETURN 911 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xc801, &rev_num)); 912 913 if ((rev_num & 0xF) == PHY_8727_VERSION_C) { 914 rv = _phy_8727_firmware_ram_set(unit,port,0,phy8727c_ucode_bin, 915 phy8727c_ucode_bin_len); 916 if (SOC_FAILURE(rv)) { 917 LOG_WARN(BSL_LS_SOC_PHY, 918 (BSL_META_U(unit, 919 "8706: p=%d RAM load didn't complete\n"), port)); 920 } 921 } 922 } else if (phyid1 == PHY_ID1_8747) { 923 rv = _phy_8747_firmware_ram_set(unit,port,0,phy8747_ucode_bin, 924 phy8747_ucode_bin_len); 925 if (SOC_FAILURE(rv)) { 926 LOG_WARN(BSL_LS_SOC_PHY, 927 (BSL_META_U(unit, 928 "8706: p=%d RAM load didn't complete\n"), port)); 929 } 930 } 931 } 932 933 /* read the microcode revision */ 934 SOC_IF_ERROR_RETURN 935 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA1A,&ucode_ver)); 936 937 /* Make sure SPI-ROM load is complete */ 938 soc_timeout_init(&to, 600000, 0); 939 do { 940 if (phyid1 == PHY_ID1_8727) { 941 942 /* if microcode revision > 0xd101, then use the new method 943 * to check the completion of the SPI-ROM loading 944 */ 945 if (ucode_ver < 0xd101) { 946 rv = (READ_PHY8706_GENREG1r(unit, pc, &data16)); 947 if (data16 == 0x0AA0 || SOC_FAILURE(rv)) { 948 break; 949 } 950 } else { 951 rv = READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA1C,&data16); 952 if (data16 == 0x600D || SOC_FAILURE(rv)) { 953 break; 954 } 955 } 956 } else if (phyid1 == PHY_ID1_8747) { 957 rv = READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA1C,&data16); 958 if (data16 == 0x600D || SOC_FAILURE(rv)) { 959 break; 960 } 961 /* Read from 0xca1a done outside the loop */ 962 } else { 963 rv = (READ_PHY8706_GENREG1r(unit, pc, &data16)); 964 if ((data16 == 0x1234) || (data16 == 0x4321) || SOC_FAILURE(rv)) { 965 break; 966 } 967 } 968 } while (!soc_timeout_check(&to)); 969 970 if (phyid1 == PHY_ID1_8747) { 971 SOC_IF_ERROR_RETURN 972 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc843, 0x000f, 0x000f)); 973 SOC_IF_ERROR_RETURN 974 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc840, 0x000c, 0x000c)); 975 } 976 977 if (soc_timeout_check(&to) || SOC_FAILURE(rv)) { 978 if (phy_ext_rom_boot) { 979 LOG_WARN(BSL_LS_SOC_PHY, 980 (BSL_META_U(unit, 981 "8706: p=%d SPI-ROM load didn't complete (0x%x)\n"), 982 port,data16)); 983 } else { 984 LOG_WARN(BSL_LS_SOC_PHY, 985 (BSL_META_U(unit, 986 "8706: p=%d RAM boot didn't complete (0x%x)\n"), 987 port,data16)); 988 } 989 } else { 990 /* re-read the microcode revision */ 991 SOC_IF_ERROR_RETURN 992 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA1A,&ucode_ver)); 993 994 if (phy_ext_rom_boot) { 995 LOG_CLI((BSL_META_U(unit, 996 "8706: u=%d p=%d external rom boot complete f/w ver. " 997 "0x%x: init.\n"), unit, port,ucode_ver)); 998 } else { 999 LOG_CLI((BSL_META_U(unit, 1000 "8706: u=%d p=%d internal RAM boot complete f/w ver. " 1001 "0x%x: init.\n"), unit, port,ucode_ver)); 1002 } 1003 } 1004 if (PHY_IS_CHAINED(unit, port) && (phyid1 == PHY_ID1_8747) 1005 && (ucode_ver > 0x050d)) { 1006 SOC_IF_ERROR_RETURN 1007 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xc842, 0x1000)); 1008 } 1009 SOC_IF_ERROR_RETURN 1010 (_bcm8726_pmad_write_en(unit, pc, FALSE)); 1011 1012 /* For rev B: do not initialize any registers and use the default values 1013 * if the configuration variable is not set 1014 */ 1015 1016 /* Change XAUI TX Polarity */ 1017 1018 str = soc_property_port_get_str(unit, port, spn_PHY_TX_POLARITY_FLIP); 1019 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1020 1021 /* always use the configuration if available */ 1022 if (str != NULL) { 1023 rv = soc_property_port_get(unit, port, 1024 spn_PHY_TX_POLARITY_FLIP, 0); 1025 } else { /* rev A */ 1026 rv = 1; 1027 } 1028 1029 mask16 = PHY8706_TX_POLARITY_FLIP_MASK; 1030 if (rv) { 1031 data16 = mask16; 1032 1033 /* flip all lanes */ 1034 if (rv == 1) { 1035 SOC_IF_ERROR_RETURN 1036 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TXA_CTRL_REG, 1037 data16, mask16)); 1038 1039 } else { /* flip individual lanes */ 1040 if ((rv & 0x000F) == 0x000F) { 1041 SOC_IF_ERROR_RETURN 1042 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TX0_CTRL_REG, 1043 data16, mask16)); 1044 } 1045 if ((rv & 0x00F0) == 0x00F0) { 1046 SOC_IF_ERROR_RETURN 1047 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TX1_CTRL_REG, 1048 data16, mask16)); 1049 } 1050 if ((rv & 0x0F00) == 0x0F00) { 1051 SOC_IF_ERROR_RETURN 1052 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TX2_CTRL_REG, 1053 data16, mask16)); 1054 } 1055 if ((rv & 0xF000) == 0xF000) { 1056 SOC_IF_ERROR_RETURN 1057 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TX3_CTRL_REG, 1058 data16, mask16)); 1059 } 1060 } 1061 } else { 1062 data16 = 0; 1063 SOC_IF_ERROR_RETURN 1064 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_TXA_CTRL_REG, 1065 data16, mask16)); 1066 } 1067 } 1068 1069 /* Change XAUI RX Polarity */ 1070 1071 str = soc_property_port_get_str(unit, port, spn_PHY_RX_POLARITY_FLIP); 1072 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1073 1074 /* always use the configuration if available */ 1075 if (str != NULL) { 1076 rv = soc_property_port_get(unit, port, 1077 spn_PHY_RX_POLARITY_FLIP, 0); 1078 } else { /* rev A */ 1079 rv = 0; 1080 } 1081 1082 mask16 = PHY8706_RX_POLARITY_FLIP_MASK; 1083 if (rv) { 1084 data16 = mask16; 1085 1086 /* flip all lanes */ 1087 if (rv == 1) { 1088 SOC_IF_ERROR_RETURN 1089 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RXA_CTRL_REG, 1090 data16, mask16)); 1091 1092 } else { /* flip individual lanes */ 1093 if ((rv & 0x000F) == 0x000F) { 1094 SOC_IF_ERROR_RETURN 1095 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RX0_CTRL_REG, 1096 data16, mask16)); 1097 } 1098 if ((rv & 0x00F0) == 0x00F0) { 1099 SOC_IF_ERROR_RETURN 1100 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RX1_CTRL_REG, 1101 data16, mask16)); 1102 } 1103 if ((rv & 0x0F00) == 0x0F00) { 1104 SOC_IF_ERROR_RETURN 1105 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RX2_CTRL_REG, 1106 data16, mask16)); 1107 } 1108 if ((rv & 0xF000) == 0xF000) { 1109 SOC_IF_ERROR_RETURN 1110 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RX3_CTRL_REG, 1111 data16, mask16)); 1112 } 1113 } 1114 } else { 1115 data16 = 0; 1116 SOC_IF_ERROR_RETURN 1117 (MODIFY_PHY8706_XS_REG(unit, pc, PHY8706_RXA_CTRL_REG, 1118 data16, mask16)); 1119 } 1120 } 1121 1122 /* XAUI RX Lane Swap (Lane A, B, C, D changes to Lane D, C, B, A) */ 1123 1124 str = soc_property_port_get_str(unit, port, spn_PHY_XAUI_RX_LANE_SWAP); 1125 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1126 1127 /* always use the configuration if available */ 1128 if (str != NULL) { 1129 rv = soc_property_port_get(unit, port, 1130 spn_PHY_XAUI_RX_LANE_SWAP, 0); 1131 } else { /* rev A */ 1132 rv = 1; 1133 } 1134 1135 SOC_IF_ERROR_RETURN 1136 (READ_PHY8706_XS_REG(unit, pc, 0x8100, &data16)); 1137 1138 if (rv) { 1139 data16 |= (1 << 15); 1140 } else { 1141 data16 &= ~(1 << 15); 1142 } 1143 SOC_IF_ERROR_RETURN 1144 (WRITE_PHY8706_XS_REG(unit, pc, 0x8100, data16)); 1145 } 1146 1147 /* XAUI TX Lane Swap (Lane A, B, C, D changes to Lane D, C, B, A) */ 1148 1149 str = soc_property_port_get_str(unit, port, spn_PHY_XAUI_TX_LANE_SWAP); 1150 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1151 1152 /* always use the configuration if available */ 1153 if (str != NULL) { 1154 rv = soc_property_port_get(unit, port, 1155 spn_PHY_XAUI_TX_LANE_SWAP, 0); 1156 } else { /* rev A */ 1157 rv = 0; 1158 } 1159 1160 SOC_IF_ERROR_RETURN 1161 (READ_PHY8706_XS_REG(unit, pc, 0x8101, &data16)); 1162 if (rv) { 1163 data16 |= (1 << 15); 1164 } else { 1165 data16 &= ~(1 << 15); 1166 } 1167 SOC_IF_ERROR_RETURN 1168 (WRITE_PHY8706_XS_REG(unit, pc, 0x8101, data16)); 1169 } 1170 1171 /* Change PCS TX Polarity */ 1172 1173 str = soc_property_port_get_str(unit, port, spn_PHY_PCS_TX_POLARITY_FLIP); 1174 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1175 1176 /* always use the configuration if available */ 1177 if (str != NULL) { 1178 rv = soc_property_port_get(unit, port, 1179 spn_PHY_PCS_TX_POLARITY_FLIP, 0); 1180 } else { /* rev A */ 1181 rv = 0; 1182 } 1183 1184 if (IS_8727_TYPE(phyid1)) { 1185 reg = 0xcd08; 1186 } else { 1187 reg = 0xc808; 1188 } 1189 1190 SOC_IF_ERROR_RETURN 1191 (READ_PHY8706_PMA_PMD_REG(unit, pc, reg, &data16)); 1192 if (rv) { 1193 data16 |= (1 << 10); 1194 } else { 1195 data16 &= ~(1 << 10); 1196 } 1197 SOC_IF_ERROR_RETURN 1198 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, reg, data16)); 1199 } 1200 1201 /* Change PCS RX Polarity */ 1202 1203 str = soc_property_port_get_str(unit, port, spn_PHY_PCS_RX_POLARITY_FLIP); 1204 if ((phyid1 == PHY87X6_REV_A) || (str != NULL)) { 1205 1206 /* always use the configuration if available */ 1207 if (str != NULL) { 1208 rv = soc_property_port_get(unit, port, 1209 spn_PHY_PCS_RX_POLARITY_FLIP, 0); 1210 } else { /* rev A */ 1211 rv = 0; 1212 } 1213 1214 if (IS_8727_TYPE(phyid1)) { 1215 reg = 0xcd08; 1216 } else { 1217 reg = 0xc808; 1218 } 1219 1220 SOC_IF_ERROR_RETURN 1221 (READ_PHY8706_PMA_PMD_REG(unit, pc, reg, &data16)); 1222 1223 if (rv) { 1224 data16 |= (1 << 9); 1225 } else { 1226 data16 &= ~(1 << 9); 1227 } 1228 SOC_IF_ERROR_RETURN 1229 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, reg, data16)); 1230 } 1231 1232 1233 /* Make sure 8706 XAUI lanes are synchronized with the SOC XAUI */ 1234 soc_timeout_init(&to, 100000, 0); 1235 while (!soc_timeout_check(&to)) { 1236 rv = (READ_PHY8706_PHYXS_XGXS_LANE_STATr(unit, pc, &data16)); 1237 if (((data16 & 0x000f) == 0x000f) || SOC_FAILURE(rv)) { 1238 break; 1239 } 1240 } 1241 if ((data16 & 0x000f) != 0x000f) { 1242 LOG_INFO(BSL_LS_SOC_PHY, 1243 (BSL_META_U(unit, 1244 "8706: u=%d p=%d XAUI lane out of sync (0x%x)\n"), 1245 unit, port, (data16 & 0x000f))); 1246 } 1247 1248 /* default value for clause37 advertisement */ 1249 SOC_IF_ERROR_RETURN 1250 (WRITE_PHY8706_AN_REG(unit, pc, 0xFFE4, MII_ANA_C37_FD)); 1251 1252 if (IS_8727_TYPE(phyid1)) { 1253 /* The register 0x7.0x8329 has been moved to 0x7.0x8309 1254 since the microcode ver. D102. This version of microcode 1255 is obsolete now. 1256 */ 1257 SOC_IF_ERROR_RETURN 1258 (WRITE_PHY8706_AN_REG(unit, pc, 0x8309, 0)); 1259 1260 1261 /* P_DOWN/OPTXRST1 */ 1262 SOC_IF_ERROR_RETURN 1263 (READ_PHY8706_IDENTIFIERr(unit, pc, &tmp)); 1264 1265 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXENBLVL, FALSE)) { 1266 tmp |= 0x8000; /* Set OPTXENB_LVL */ 1267 } else { 1268 tmp &= ~0x8000; 1269 } 1270 1271 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXRSTLVL, TRUE)) { 1272 tmp |= 0x4000; /* Set OPTXRST_LVL */ 1273 } else { 1274 tmp &= ~0x4000; 1275 } 1276 1277 if (soc_property_port_get(unit, port, spn_FORCE_OPTBIASFLTLVL, TRUE)) { 1278 tmp |= 0x2000; /* Set OPBIASFLT_LVL */ 1279 } else { 1280 tmp &= ~0x2000; 1281 } 1282 1283 if (soc_property_port_get(unit, port, spn_FORCE_OPTTEMPFLTLVL, TRUE)) { 1284 tmp |= 0x1000; /* Set OPMPFLT_LVL */ 1285 } else { 1286 tmp &= ~0x1000; 1287 } 1288 1289 if (soc_property_port_get(unit, port, spn_FORCE_OPTPRFLTLVL, TRUE)) { 1290 tmp |= 0x0800; /* Set OPPRFLT_LVL */ 1291 } else { 1292 tmp &= ~0x0800; 1293 } 1294 1295 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXFLLVL, TRUE)) { 1296 tmp |= 0x0400; /* Set OPTXFLT_LVL */ 1297 } else { 1298 tmp &= ~0x0400; 1299 } 1300 1301 if (soc_property_port_get(unit, port, spn_FORCE_OPTRXLOSLVL, TRUE)) { 1302 tmp |= 0x0200; /* Set OPRXLOS_LVL */ 1303 } else { 1304 tmp &= ~0x0200; 1305 } 1306 1307 if (soc_property_port_get(unit, port, spn_FORCE_OPTRXFLTLVL, TRUE)) { 1308 tmp |= 0x0100; /* Set OPRXFLT_LVL */ 1309 } else { 1310 tmp &= ~0x0100; 1311 } 1312 1313 if (soc_property_port_get(unit, port, spn_FORCE_OPTTXONLVL, TRUE)) { 1314 tmp |= 0x0080; /* Set OPTXON_LVL */ 1315 } else { 1316 tmp &= ~0x0080; 1317 } 1318 1319 /* P_DOWN/OPTXRST1 */ 1320 SOC_IF_ERROR_RETURN 1321 (WRITE_PHY8706_IDENTIFIERr(unit, pc, tmp)); 1322 1323 } 1324 1325 /* fix for PHY-443 */ 1326 SOC_IF_ERROR_RETURN 1327 (MODIFY_PHY8706_XS_REG(unit, pc, 0x8111, 1 << 3, 1 << 3)); 1328 1329 /* Probe for external PHYs connected */ 1330 if ((phyid1 == PHY87X6_REV_BC) || IS_8727_TYPE(phyid1)) { 1331 rv = _8726_nxt_dev_probe(unit, port); 1332 if (SOC_SUCCESS(rv)) { 1333 1334 /* Initialize the next Device */ 1335 PHYDRV_CALL_NOARG(pc,PHY_INIT); 1336 } 1337 } 1338 1339 /* Enable Squelch */ 1340 SOC_IF_ERROR_RETURN(_phy_8706_squelch_enable(unit, port, TRUE)); 1341 1342 1343 return SOC_E_NONE; 1344 } 1345 1346 STATIC int 1347 _phy_8706_xgxs_cfg_save(int unit, soc_port_t port, XGXS_CFG_t *xgxs_cfg) 1348 { 1349 phy_ctrl_t *pc; 1350 pc = EXT_PHY_SW_STATE(unit, port); 1351 1352 SOC_IF_ERROR_RETURN 1353 (READ_PHY8706_XS_REG(unit, pc, PHY8706_TX0_CTRL_REG, 1354 &xgxs_cfg->tx_pol_ln0)); 1355 SOC_IF_ERROR_RETURN 1356 (READ_PHY8706_XS_REG(unit, pc, PHY8706_TX1_CTRL_REG, 1357 &xgxs_cfg->tx_pol_ln1)); 1358 SOC_IF_ERROR_RETURN 1359 (READ_PHY8706_XS_REG(unit, pc, PHY8706_TX2_CTRL_REG, 1360 &xgxs_cfg->tx_pol_ln2)); 1361 SOC_IF_ERROR_RETURN 1362 (READ_PHY8706_XS_REG(unit, pc, PHY8706_TX3_CTRL_REG, 1363 &xgxs_cfg->tx_pol_ln3)); 1364 SOC_IF_ERROR_RETURN 1365 (READ_PHY8706_XS_REG(unit, pc, PHY8706_RX0_CTRL_REG, 1366 &xgxs_cfg->rx_pol_ln0)); 1367 SOC_IF_ERROR_RETURN 1368 (READ_PHY8706_XS_REG(unit, pc, PHY8706_RX1_CTRL_REG, 1369 &xgxs_cfg->rx_pol_ln1)); 1370 SOC_IF_ERROR_RETURN 1371 (READ_PHY8706_XS_REG(unit, pc, PHY8706_RX2_CTRL_REG, 1372 &xgxs_cfg->rx_pol_ln2)); 1373 SOC_IF_ERROR_RETURN 1374 (READ_PHY8706_XS_REG(unit, pc, PHY8706_RX3_CTRL_REG, 1375 &xgxs_cfg->rx_pol_ln3)); 1376 SOC_IF_ERROR_RETURN 1377 (READ_PHY8706_XS_REG(unit, pc, 0x8100, 1378 &xgxs_cfg->rx_ln_swap)); 1379 SOC_IF_ERROR_RETURN 1380 (READ_PHY8706_XS_REG(unit, pc, 0x8101, 1381 &xgxs_cfg->tx_ln_swap)); 1382 SOC_IF_ERROR_RETURN 1383 (READ_PHY8706_TXA_ACTRL_3r(unit, pc, 1384 &xgxs_cfg->preemph)); 1385 SOC_IF_ERROR_RETURN 1386 (READ_PHY8706_XS_REG(unit, pc, 0x8111, 1387 &xgxs_cfg->inband_mdio)); 1388 return SOC_E_NONE; 1389 } 1390 1391 STATIC int 1392 _phy_8706_xgxs_cfg_restore(int unit, soc_port_t port, XGXS_CFG_t *xgxs_cfg) 1393 { 1394 phy_ctrl_t *pc; 1395 pc = EXT_PHY_SW_STATE(unit, port); 1396 SOC_IF_ERROR_RETURN 1397 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_TX0_CTRL_REG, 1398 xgxs_cfg->tx_pol_ln0)); 1399 SOC_IF_ERROR_RETURN 1400 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_TX1_CTRL_REG, 1401 xgxs_cfg->tx_pol_ln1)); 1402 SOC_IF_ERROR_RETURN 1403 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_TX2_CTRL_REG, 1404 xgxs_cfg->tx_pol_ln2)); 1405 SOC_IF_ERROR_RETURN 1406 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_TX3_CTRL_REG, 1407 xgxs_cfg->tx_pol_ln3)); 1408 SOC_IF_ERROR_RETURN 1409 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_RX0_CTRL_REG, 1410 xgxs_cfg->rx_pol_ln0)); 1411 SOC_IF_ERROR_RETURN 1412 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_RX1_CTRL_REG, 1413 xgxs_cfg->rx_pol_ln1)); 1414 SOC_IF_ERROR_RETURN 1415 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_RX2_CTRL_REG, 1416 xgxs_cfg->rx_pol_ln2)); 1417 SOC_IF_ERROR_RETURN 1418 (WRITE_PHY8706_XS_REG(unit, pc, PHY8706_RX3_CTRL_REG, 1419 xgxs_cfg->rx_pol_ln3)); 1420 SOC_IF_ERROR_RETURN 1421 (WRITE_PHY8706_XS_REG(unit, pc, 0x8100, 1422 xgxs_cfg->rx_ln_swap)); 1423 SOC_IF_ERROR_RETURN 1424 (WRITE_PHY8706_XS_REG(unit, pc, 0x8101, 1425 xgxs_cfg->tx_ln_swap)); 1426 SOC_IF_ERROR_RETURN 1427 (WRITE_PHY8706_TXA_ACTRL_3r(unit, pc, 1428 xgxs_cfg->preemph)); 1429 SOC_IF_ERROR_RETURN 1430 (WRITE_PHY8706_XS_REG(unit, pc, 0x8111, 1431 xgxs_cfg->inband_mdio)); 1432 return SOC_E_NONE; 1433 } 1434 1435 STATIC int 1436 _phy_5942_pd_status_save(int unit, soc_port_t port, PHY5942_CFG_t *phy_5942_cfg) 1437 { 1438 phy_ctrl_t *pc; 1439 pc = EXT_PHY_SW_STATE(unit, port); 1440 1441 SOC_IF_ERROR_RETURN 1442 (READ_PHY8706_PHYXS_XGXSBLK0_MISCCONTROL1r(unit, pc, 1443 &phy_5942_cfg->xgxsblk0_misccontrol1)); 1444 1445 SOC_IF_ERROR_RETURN 1446 (READ_PHY8706_PHYXS_RX_ALL_RX_CONTROLr(unit, pc, 1447 &phy_5942_cfg->rx_all_rx_control)); 1448 1449 return SOC_E_NONE; 1450 } 1451 1452 1453 1454 /* 1455 * Example configuration: 1456 * 1457 * phy_led_select_tx_control2_xe0=0x8765 1458 */ 1459 #define PHY_8706_TX_CONTROL_X_SET(_pc, _str,_data16, _idx, _reg_addr,_def, _mask) \ 1460 do { \ 1461 _str = soc_property_port_suffix_num_get_str((_pc)->unit, (_pc)->port, \ 1462 _idx, spn_PHY_LED_SELECT, "tx_control" ); \ 1463 if (_str != NULL) { \ 1464 _data16 = soc_property_port_suffix_num_get((_pc)->unit,(_pc)->port,\ 1465 _idx, spn_PHY_LED_SELECT, "tx_control", _def ); \ 1466 /* some bits are reserved */ \ 1467 SOC_IF_ERROR_RETURN \ 1468 (MODIFY_PHY8706_PMA_PMD_REG((_pc)->unit, (_pc), \ 1469 _reg_addr, _data16, _mask)); \ 1470 } \ 1471 } while(0); 1472 1473 1474 STATIC int 1475 _phy_5942_pd_status_restore(int unit, soc_port_t port, PHY5942_CFG_t *phy_5942_cfg) 1476 { 1477 uint16 data16; 1478 char *str; 1479 1480 phy_ctrl_t *pc; 1481 pc = EXT_PHY_SW_STATE(unit, port); 1482 1483 SOC_IF_ERROR_RETURN 1484 (WRITE_PHY8706_PHYXS_XGXSBLK0_MISCCONTROL1r(unit, pc, 1485 phy_5942_cfg->xgxsblk0_misccontrol1)); 1486 1487 SOC_IF_ERROR_RETURN 1488 (WRITE_PHY8706_PHYXS_RX_ALL_RX_CONTROLr(unit, pc, 1489 phy_5942_cfg->rx_all_rx_control)); 1490 1491 if (IS_8727_TYPE(pc->phy_id1)) { 1492 1493 SOC_IF_ERROR_RETURN 1494 (phy_8727_opt_lvl_set(unit, port)); 1495 1496 /* see if platform wants to change initialization value of TX Control 0 Register */ 1497 PHY_8706_TX_CONTROL_X_SET(pc, str, data16, 1498 0, 0xca01, 0x8800, 0xff00); 1499 1500 /* see if platform wants to change initialization value of TX Control 1 Register */ 1501 PHY_8706_TX_CONTROL_X_SET(pc, str, data16, 1502 1, 0xca02, 0xe000, 0xf800); 1503 1504 /* see if platform wants to change initialization value of TX Control 2 Register */ 1505 PHY_8706_TX_CONTROL_X_SET(pc, str, data16, 1506 2, 0xca05, 0x8000, 0x80f0); 1507 1508 } 1509 1510 return SOC_E_NONE; 1511 } 1512 1513 /* 1514 * Function: 1515 * phy_8706_an_get 1516 * Purpose: 1517 * Get the current auto-negotiation status (enabled/busy) 1518 * Parameters: 1519 * unit - StrataSwitch unit #. 1520 * port - StrataSwitch port #. 1521 * an - (OUT) if true, auto-negotiation is enabled. 1522 * an_done - (OUT) if true, auto-negotiation is complete. This 1523 * value is undefined if an == false. 1524 * Returns: 1525 * SOC_E_XXX 1526 */ 1527 1528 STATIC int 1529 _phy_8706_an_get(int unit, soc_port_t port, int *an, int *an_done) 1530 { 1531 phy_ctrl_t *pc; 1532 uint16 an_status; 1533 1534 pc = EXT_PHY_SW_STATE(unit, port); 1535 1536 SOC_IF_ERROR_RETURN 1537 (READ_PHY8706_AN_REG(unit, pc, 0xffe0, &an_status)); 1538 *an = (an_status & AN_ENABLE)? TRUE: FALSE; 1539 1540 SOC_IF_ERROR_RETURN 1541 (READ_PHY8706_AN_REG(unit, pc, 0xffe1, &an_status)); 1542 *an_done = (an_status & AN_DONE)? TRUE: FALSE; 1543 1544 return SOC_E_NONE; 1545 } 1546 1547 STATIC int 1548 phy_8706_an_get(int unit, soc_port_t port, int *an, int *an_done) 1549 { 1550 phy_ctrl_t *pc; 1551 1552 pc = EXT_PHY_SW_STATE(unit, port); 1553 1554 if (NXT_PC(pc)) { 1555 PHYDRV_CALL_ARG2(pc, PHY_AUTO_NEGOTIATE_GET, an, an_done); 1556 return SOC_E_NONE; 1557 } 1558 SOC_IF_ERROR_RETURN 1559 (_phy_8706_an_get(unit, port, an, an_done)); 1560 1561 return SOC_E_NONE; 1562 } 1563 1564 /* 1565 * Function: 1566 * phy_8726_an_set 1567 * Purpose: 1568 * Enable or disabled auto-negotiation for 8726 port 1569 * Parameters: 1570 * unit - StrataSwitch unit #. 1571 * port - StrataSwitch port #. 1572 * an - Boolean, if true, auto-negotiation is enabled 1573 * (and/or restarted). If false, autonegotiation is disabled. 1574 * Returns: 1575 * SOC_E_XXX 1576 */ 1577 STATIC int 1578 phy_8726_an_set(int unit, int port, int an) 1579 { 1580 phy_ctrl_t *pc; 1581 XGXS_CFG_t xgxs_cfg; 1582 1583 pc = EXT_PHY_SW_STATE(unit, port); 1584 1585 LOG_INFO(BSL_LS_SOC_PHY, 1586 (BSL_META_U(unit, 1587 "phy_8726_an_set: u=%d p=%d an=%d\n"), 1588 unit, port, an)); 1589 1590 /* for 8726 device, switching autoneg On/Off may reset XGXS(device 4). 1591 * save/restore the software configuration for XGXS device in this case. 1592 */ 1593 SOC_IF_ERROR_RETURN 1594 (_phy_8706_xgxs_cfg_save(unit,port, &xgxs_cfg)); 1595 1596 if (an) { 1597 SOC_IF_ERROR_RETURN 1598 (WRITE_PHY8706_AN_REG(unit, pc, 0x0011, 0x0020)); 1599 SOC_IF_ERROR_RETURN 1600 (WRITE_PHY8706_AN_REG(unit, pc, 0x8370, 0x040c)); 1601 SOC_IF_ERROR_RETURN 1602 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, 0x0040)); 1603 SOC_IF_ERROR_RETURN 1604 (MODIFY_PHY8706_AN_REG(unit, pc, 0xFFE4, 0x0020, 0x0020)); 1605 SOC_IF_ERROR_RETURN 1606 (WRITE_PHY8706_AN_REG(unit, pc, 0xFFE0, 0x1100)); 1607 SOC_IF_ERROR_RETURN 1608 (WRITE_PHY8706_AN_REG(unit, pc, 0x0000, 0x1000)); 1609 SOC_IF_ERROR_RETURN 1610 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca62, 0x0004)); 1611 SOC_IF_ERROR_RETURN 1612 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca62, 0x4004)); 1613 SOC_IF_ERROR_RETURN 1614 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca42, 0x0f00)); 1615 SOC_IF_ERROR_RETURN 1616 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xca42, 0x0e00)); 1617 SOC_IF_ERROR_RETURN 1618 (WRITE_PHY8706_AN_REG(unit, pc, 0x80f1, 0x9c40)); 1619 SOC_IF_ERROR_RETURN 1620 (WRITE_PHY8706_AN_REG(unit, pc, 0x80f1, 0x1c40)); 1621 SOC_IF_ERROR_RETURN 1622 (WRITE_PHY8706_AN_REG(unit, pc, 0x0000, 0x3200)); 1623 } else { 1624 SOC_IF_ERROR_RETURN 1625 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, 0x2040)); 1626 1627 /* disable Clause 37 AN */ 1628 SOC_IF_ERROR_RETURN 1629 (WRITE_PHY8706_AN_REG(unit, pc, 0xFFE0, 0)); 1630 1631 SOC_IF_ERROR_RETURN 1632 (WRITE_PHY8706_AN_REG(unit, pc, AN_CTRL_REG, 0x0)); 1633 } 1634 1635 SOC_IF_ERROR_RETURN 1636 (_phy_8706_xgxs_cfg_restore(unit,port, &xgxs_cfg)); 1637 1638 return SOC_E_NONE; 1639 } 1640 1641 /* 1642 * Function: 1643 * phy_8706_an_set 1644 * Purpose: 1645 * Enable or disabled auto-negotiation on the specified port. 1646 * Parameters: 1647 * unit - StrataSwitch unit #. 1648 * port - StrataSwitch port #. 1649 * an - Boolean, if true, auto-negotiation is enabled 1650 * (and/or restarted). If false, autonegotiation is disabled. 1651 * Returns: 1652 * SOC_E_XXX 1653 */ 1654 STATIC int 1655 phy_8706_an_set(int unit, soc_port_t port, int an) 1656 { 1657 phy_ctrl_t *pc; 1658 1659 pc = EXT_PHY_SW_STATE(unit, port); 1660 1661 LOG_INFO(BSL_LS_SOC_PHY, 1662 (BSL_META_U(unit, 1663 "phy_8706_an_set: u=%d p=%d an=%d\n"), 1664 unit, port, an)); 1665 1666 if (NXT_PC(pc)) { 1667 PHYDRV_CALL_ARG1(pc, PHY_AUTO_NEGOTIATE_SET, an); 1668 an = 0; 1669 } 1670 1671 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 1672 return phy_8726_an_set(unit, port ,an); 1673 } 1674 1675 if (an) { 1676 SOC_IF_ERROR_RETURN 1677 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, 0x0040)); 1678 1679 1680 /* Enable Clause 37 AN */ 1681 SOC_IF_ERROR_RETURN 1682 (WRITE_PHY8706_AN_REG(unit, pc, 0xFFE0, 0x1300)); 1683 1684 if (IS_8727_TYPE(pc->phy_id1)) { 1685 /* The register 0x7.0x8329 has been moved to 0x7.0x8309 1686 since the microcode ver. D102. This version of microcode 1687 is obsolete now. 1688 */ 1689 SOC_IF_ERROR_RETURN 1690 (WRITE_PHY8706_AN_REG(unit, pc, 0x8309, 0)); 1691 } 1692 } else { 1693 SOC_IF_ERROR_RETURN 1694 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, 0x2040)); 1695 1696 if (IS_8727_TYPE(pc->phy_id1)) { 1697 /* The register 0x7.0x8329 has been moved to 0x7.0x8309 1698 since the microcode ver. D102. This version of microcode 1699 is obsolete now. 1700 */ 1701 SOC_IF_ERROR_RETURN 1702 (WRITE_PHY8706_AN_REG(unit, pc, 0x8309, 0x0020)); 1703 } 1704 1705 /* disable Clause 37 AN */ 1706 SOC_IF_ERROR_RETURN 1707 (WRITE_PHY8706_AN_REG(unit, pc, 0xFFE0, 0)); 1708 1709 } 1710 1711 1712 return SOC_E_NONE; 1713 } 1714 1715 /* 1716 * Function: 1717 * phy_8706_ability_advert_get 1718 * Purpose: 1719 * Get the current advertisement for auto-negotiation. 1720 * Parameters: 1721 * unit - StrataSwitch unit #. 1722 * port - StrataSwitch port #. 1723 * mode - (OUT) Port mode mask indicating supported options/speeds. 1724 * Returns: 1725 * SOC_E_XXX 1726 * Notes: 1727 * The advertisement is retrieved for the ACTIVE medium. 1728 * No synchronization performed at this level. 1729 */ 1730 1731 STATIC int 1732 phy_8706_ability_advert_get(int unit, soc_port_t port, 1733 soc_port_ability_t *ability) 1734 { 1735 uint16 an_adv; 1736 soc_port_mode_t mode; 1737 phy_ctrl_t *pc; 1738 1739 if (NULL == ability) { 1740 return (SOC_E_PARAM); 1741 } 1742 pc = EXT_PHY_SW_STATE(unit, port); 1743 1744 if (NXT_PC(pc)) { 1745 PHYDRV_CALL_ARG1(pc,PHY_ABILITY_ADVERT_GET,ability); 1746 return SOC_E_NONE; 1747 } 1748 1749 /* Clause73 advert register 1 */ 1750 SOC_IF_ERROR_RETURN 1751 (READ_PHY8706_AN_REG(unit, pc, 0x11, &an_adv)); 1752 1753 mode = 0; 1754 mode |= (an_adv & 0x20) ? SOC_PA_SPEED_1000MB : 0; 1755 1756 /* check Full Duplex advertisement on Clause 37 */ 1757 SOC_IF_ERROR_RETURN 1758 (READ_PHY8706_AN_REG(unit, pc, 0xFFE4,&an_adv)); 1759 mode |= (an_adv & MII_ANA_C37_FD) ? SOC_PA_SPEED_1000MB : 0; 1760 1761 ability->speed_full_duplex = mode; 1762 ability->pause = 0; 1763 1764 switch (an_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) { 1765 case MII_ANA_C37_PAUSE: 1766 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1767 break; 1768 case MII_ANA_C37_ASYM_PAUSE: 1769 ability->pause = SOC_PA_PAUSE_TX; 1770 break; 1771 case MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE: 1772 ability->pause = SOC_PA_PAUSE_RX; 1773 break; 1774 } 1775 1776 LOG_INFO(BSL_LS_SOC_PHY, 1777 (BSL_META_U(unit, 1778 "phy_8706_ability_advert_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"), 1779 unit, port, ability->speed_full_duplex, ability->pause)); 1780 return SOC_E_NONE; 1781 } 1782 1783 /* 1784 * Function: 1785 * phy_8706_ability_remote_get 1786 * Purpose: 1787 * Get the device's complete abilities. 1788 * Parameters: 1789 * unit - StrataSwitch unit #. 1790 * port - StrataSwitch port #. 1791 * ability - return device's abilities. 1792 * Returns: 1793 * SOC_E_XXX 1794 */ 1795 1796 STATIC int 1797 phy_8706_ability_remote_get(int unit, soc_port_t port, 1798 soc_port_ability_t *ability) 1799 { 1800 phy_ctrl_t *pc; 1801 uint16 lp_abil; 1802 1803 if (NULL == ability) { 1804 return SOC_E_PARAM; 1805 } 1806 1807 pc = EXT_PHY_SW_STATE(unit, port); 1808 1809 if (NXT_PC(pc)) { 1810 PHYDRV_CALL_ARG1(pc,PHY_ABILITY_REMOTE_GET,ability); 1811 return SOC_E_NONE; 1812 } 1813 1814 SOC_IF_ERROR_RETURN 1815 (READ_PHY8706_AN_REG(unit, pc, 0xFFE5, &lp_abil)); 1816 ability->speed_full_duplex = (lp_abil & MII_ANA_C37_FD) ? 1817 SOC_PA_SPEED_1000MB : 0; 1818 1819 ability->pause = 0; 1820 switch (lp_abil & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) { 1821 case MII_ANP_C37_PAUSE: 1822 ability->pause = SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX; 1823 break; 1824 case MII_ANP_C37_ASYM_PAUSE: 1825 ability->pause = SOC_PA_PAUSE_TX; 1826 break; 1827 case MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE: 1828 ability->pause = SOC_PA_PAUSE_RX; 1829 break; 1830 } 1831 1832 SOC_IF_ERROR_RETURN 1833 (READ_PHY8706_AN_REG(unit, pc, AN_STATUS_REG, &lp_abil)); 1834 ability->flags = (lp_abil & 0x1) ? SOC_PA_AUTONEG : 0; 1835 1836 LOG_INFO(BSL_LS_SOC_PHY, 1837 (BSL_META_U(unit, 1838 "phy_8706_ability_remote_get: u=%d p=%d speed(FD)=0x%x pause=0x%x\n"), 1839 unit, port, ability->speed_full_duplex, ability->pause)); 1840 1841 return (SOC_E_NONE); 1842 } 1843 1844 /* 1845 * Function: 1846 * phy_8706_ability_advert_set 1847 * Purpose: 1848 * Set the current advertisement for auto-negotiation. 1849 * Parameters: 1850 * unit - StrataSwitch unit #. 1851 * port - StrataSwitch port #. 1852 * mode - Port mode mask indicating supported options/speeds. 1853 * Returns: 1854 * SOC_E_XXX 1855 * Notes: 1856 * The advertisement is set only for the ACTIVE medium. 1857 * No synchronization performed at this level. 1858 */ 1859 1860 STATIC int 1861 phy_8706_ability_advert_set(int unit, soc_port_t port, 1862 soc_port_ability_t *ability) 1863 { 1864 uint16 an_adv; 1865 phy_ctrl_t *pc; 1866 if (NULL == ability) { 1867 return (SOC_E_PARAM); 1868 } 1869 1870 pc = EXT_PHY_SW_STATE(unit, port); 1871 1872 if (NXT_PC(pc)) { 1873 PHYDRV_CALL_ARG1(pc,PHY_ABILITY_ADVERT_SET,ability); 1874 return SOC_E_NONE; 1875 } 1876 1877 /* 1878 * Set advertised duplex (only FD supported). 1879 */ 1880 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 0x20 : 0; 1881 1882 /* CL73 advert register 1, advertising 1G only */ 1883 SOC_IF_ERROR_RETURN 1884 (WRITE_PHY8706_AN_REG(unit, pc, 0x11, an_adv)); 1885 1886 an_adv = (ability->speed_full_duplex & SOC_PA_SPEED_1000MB) ? 1887 MII_ANA_C37_FD : 0; 1888 1889 switch (ability->pause & (SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX)) { 1890 case SOC_PA_PAUSE_TX: 1891 an_adv |= MII_ANA_C37_ASYM_PAUSE; 1892 break; 1893 case SOC_PA_PAUSE_RX: 1894 an_adv |= MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE; 1895 break; 1896 case SOC_PA_PAUSE_TX | SOC_PA_PAUSE_RX: 1897 an_adv |= MII_ANA_C37_PAUSE; 1898 break; 1899 } 1900 1901 /* write Clause37 advertisement */ 1902 SOC_IF_ERROR_RETURN 1903 (MODIFY_PHY8706_AN_REG(unit, pc, 0xFFE4, an_adv, 1904 MII_ANA_C37_ASYM_PAUSE | 1905 MII_ANA_C37_PAUSE | 1906 MII_ANA_C37_FD | 1907 MII_ANA_C37_HD )); 1908 1909 LOG_INFO(BSL_LS_SOC_PHY, 1910 (BSL_META_U(unit, 1911 "phy_8706_ability_advert_set: u=%d p=%d pause=0x%08x adv_reg1=0x%04x\n"), 1912 unit, port, ability->pause, an_adv)); 1913 return SOC_E_NONE; 1914 } 1915 1916 /* 1917 * Function: 1918 * phy_8706_ability_local_get 1919 * Purpose: 1920 * Get the device's complete abilities. 1921 * Parameters: 1922 * unit - StrataSwitch unit #. 1923 * port - StrataSwitch port #. 1924 * ability - return device's abilities. 1925 * Returns: 1926 * SOC_E_XXX 1927 */ 1928 1929 STATIC int 1930 phy_8706_ability_local_get(int unit, soc_port_t port, soc_port_ability_t *ability) 1931 { 1932 phy_ctrl_t *pc; 1933 pc = EXT_PHY_SW_STATE(unit, port); 1934 1935 1936 LOG_INFO(BSL_LS_SOC_PHY, 1937 (BSL_META_U(unit, 1938 "phy_8706_ability_local_get: u=%d p=%d\n"), 1939 unit, port)); 1940 1941 if (NULL == ability) { 1942 return SOC_E_PARAM; 1943 } 1944 1945 ability->speed_half_duplex = SOC_PA_ABILITY_NONE; 1946 ability->speed_full_duplex = SOC_PA_SPEED_1000MB; 1947 1948 switch(pc->speed_max) { 1949 case 10000: 1950 default: 1951 ability->speed_full_duplex |= SOC_PA_SPEED_10GB; 1952 break; 1953 } 1954 1955 ability->pause = SOC_PA_PAUSE | SOC_PA_PAUSE_ASYMM; 1956 ability->interface = SOC_PA_INTF_XGMII; 1957 ability->medium = SOC_PA_MEDIUM_FIBER; 1958 ability->loopback = SOC_PA_LB_PHY; 1959 ability->flags = SOC_PA_AUTONEG; 1960 1961 LOG_INFO(BSL_LS_SOC_PHY, 1962 (BSL_META_U(unit, 1963 "phy_8706_ability_local_get: u=%d p=%d speed=0x%x\n"), 1964 unit, port, ability->speed_full_duplex)); 1965 1966 return (SOC_E_NONE); 1967 } 1968 1969 /* 1970 * Function: 1971 * phy_8706_link_get 1972 * Purpose: 1973 * Get layer2 connection status. 1974 * Parameters: 1975 * unit - StrataSwitch unit #. 1976 * port - StrataSwitch port #. 1977 * link - address of memory to store link up/down state. 1978 * Returns: 1979 * SOC_E_NONE 1980 */ 1981 1982 STATIC int 1983 _phy_8706_link_get(int unit, soc_port_t port, int *link) 1984 { 1985 uint16 pma_mii_stat, pcs_mii_stat, pxs_mii_stat, link_stat; 1986 phy_ctrl_t *pc; 1987 int cur_speed = 0; 1988 int an = 0,an_done = 0; 1989 uint16 speed_val; 1990 1991 pc = EXT_PHY_SW_STATE(unit, port); 1992 1993 _phy_8706_an_get(unit,port,&an,&an_done); 1994 1995 /* return link false if in the middle of autoneg */ 1996 if (an == TRUE && an_done == FALSE) { 1997 *link = FALSE; 1998 return SOC_E_NONE; 1999 } 2000 2001 /* AN only supports 1G */ 2002 if (!an) { 2003 SOC_IF_ERROR_RETURN 2004 (READ_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 2005 if ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) != 2006 PMAD_CTRL2r_PMA_TYPE_1G_KX) { 2007 cur_speed = 10000; 2008 } 2009 } else { 2010 cur_speed = 1000; 2011 } 2012 2013 if (cur_speed == 10000) { /* check all 3 device's link status if 10G */ 2014 2015 /* Receive Link status */ 2016 SOC_IF_ERROR_RETURN 2017 (READ_PHY8706_PCS_STATr(unit, pc, &pcs_mii_stat)); 2018 2019 /* Transmit Link status */ 2020 SOC_IF_ERROR_RETURN 2021 (READ_PHY8706_PHYXS_STATr(unit, pc, &pxs_mii_stat)); 2022 2023 SOC_IF_ERROR_RETURN 2024 (READ_PHY8706_PMA_PMD_STATr(unit, pc, &pma_mii_stat)); 2025 2026 link_stat = pma_mii_stat & pcs_mii_stat & pxs_mii_stat; 2027 2028 *link = (link_stat == 0xffff) ? FALSE : 2029 (link_stat & MII_STAT_LA) ? TRUE : FALSE; 2030 } else { 2031 /* in 1G mode, the PMA/PMD and PCS status register's link bit always 2032 * show link down. 2033 */ 2034 SOC_IF_ERROR_RETURN 2035 (READ_PHY8706_AN_REG(unit, pc, AN_1G_STATUS_REG, &link_stat)); 2036 if ((link_stat != 0xffff) && (link_stat & AN_1G_LINKUP) && 2037 (!(link_stat & AN_1G_LINK_CHANGE)) ) { 2038 *link = TRUE; 2039 } else { 2040 *link = FALSE; 2041 } 2042 } 2043 2044 LOG_VERBOSE(BSL_LS_SOC_PHY, 2045 (BSL_META_U(unit, 2046 "_phy_8706_link_get: u=%d port%d: link:%s\n"), 2047 unit, port, *link ? "Up": "Down")); 2048 2049 return SOC_E_NONE; 2050 } 2051 2052 STATIC int 2053 _phy_5942_link_get(int unit, soc_port_t port, int *link) 2054 { 2055 phy_ctrl_t *pc; 2056 uint16 xgxsstatus1, status1000x1; 2057 2058 pc = EXT_PHY_SW_STATE(unit, port); 2059 2060 SOC_IF_ERROR_RETURN 2061 (READ_PHY8706_PHYXS_GP_STATUS_XGXSSTATUS1r(unit, pc, &xgxsstatus1)); 2062 2063 SOC_IF_ERROR_RETURN 2064 (READ_PHY8706_PHYXS_GP_STATUS_STATUS1000X1r(unit, pc, &status1000x1)); 2065 2066 if (xgxsstatus1 == 0xffff) { 2067 *link = 0; 2068 } else { 2069 *link = ((xgxsstatus1 & (1U << 9)) | (status1000x1 & (1U << 1))) ? 1 : 0; 2070 } 2071 2072 LOG_VERBOSE(BSL_LS_SOC_PHY, 2073 (BSL_META_U(unit, 2074 "_phy_5942_link_get: u=%d port%d: link:%s\n"), 2075 unit, port, *link ? "Up": "Down")); 2076 2077 return SOC_E_NONE; 2078 } 2079 2080 2081 STATIC int 2082 phy_8706_link_get(int unit, soc_port_t port, int *link) 2083 { 2084 phy_ctrl_t *pc; 2085 2086 pc = EXT_PHY_SW_STATE(unit, port); 2087 2088 if (link == NULL) { 2089 return SOC_E_NONE; 2090 } 2091 2092 if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) { 2093 *link = FALSE; 2094 return SOC_E_NONE; 2095 } 2096 2097 if (PHY_IS_BCM5942(pc)) { 2098 SOC_IF_ERROR_RETURN 2099 (_phy_5942_link_get(unit, port, link)); 2100 } else { 2101 int down_link; 2102 if (NXT_PC(pc)) { 2103 PHYDRV_CALL_ARG1(pc, PHY_LINK_GET, &down_link); 2104 /* assumes that the above routine returns a latched link status */ 2105 2106 if (down_link && (down_link != CACHED_DOWN_LINK(pc))) { 2107 int down_speed; 2108 PHYDRV_CALL_ARG1(pc, PHY_SPEED_GET, &down_speed); 2109 SOC_IF_ERROR_RETURN 2110 (_phy_8706_speed_set(unit, port, down_speed)); 2111 } 2112 CACHED_DOWN_LINK(pc) = down_link; 2113 if ( !down_link ) { 2114 *link = FALSE; 2115 return SOC_E_NONE; 2116 } 2117 } 2118 2119 SOC_IF_ERROR_RETURN 2120 (_phy_8706_link_get(unit, port, link)); 2121 } 2122 2123 return SOC_E_NONE; 2124 2125 } 2126 2127 2128 /* 2129 * Function: 2130 * phy_8706_enable_set 2131 * Purpose: 2132 * Enable/Disable phy 2133 * Parameters: 2134 * unit - StrataSwitch unit #. 2135 * port - StrataSwitch port #. 2136 * enable - on/off state to set 2137 * Returns: 2138 * SOC_E_NONE 2139 */ 2140 2141 STATIC int 2142 _phy_8706_enable_set(int unit, soc_port_t port, int enable) 2143 { 2144 phy_ctrl_t *pc; 2145 2146 pc = EXT_PHY_SW_STATE(unit, port); 2147 2148 SOC_IF_ERROR_RETURN 2149 (MODIFY_PHY8706_PMA_PMD_TX_DISABLEr(unit, pc, enable ? 0 : (1U << 0), (1U << 0))); 2150 2151 SOC_IF_ERROR_RETURN 2152 (MODIFY_PHY8706_PMAD_OPTICAL_CFG_REGr(unit, pc, enable ? 0 : (1 << 12), (1 << 12))); 2153 SOC_IF_ERROR_RETURN 2154 (MODIFY_PHY8706_PMAD_OPTICAL_CFG_REGr(unit, pc, enable ? 0 : (1 << 4), (1 << 4))); 2155 2156 if (NXT_PC(pc)) { 2157 PHYDRV_CALL_ARG1(pc,PHY_ENABLE_SET,enable); 2158 } 2159 2160 return (SOC_E_NONE); 2161 } 2162 2163 STATIC int 2164 _phy_5942_enable_set(int unit, soc_port_t port, int enable) 2165 { 2166 phy_ctrl_t *pc; 2167 2168 pc = EXT_PHY_SW_STATE(unit, port); 2169 2170 /* disable the Tx */ 2171 SOC_IF_ERROR_RETURN 2172 (MODIFY_PHY8706_PHYXS_XGXSBLK0_MISCCONTROL1r(unit, pc, 2173 enable? 0:XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK, 2174 XGXSBLK0_MISCCONTROL1_GLOBAL_PMD_TX_DISABLE_MASK)); 2175 2176 /* disable the Rx */ 2177 SOC_IF_ERROR_RETURN 2178 (MODIFY_PHY8706_PHYXS_RX_ALL_RX_CONTROLr(unit, pc, 2179 enable? 0:DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK, 2180 DSC_2_0_DSC_CTRL0_RXSEQSTART_MASK)); 2181 2182 return SOC_E_NONE; 2183 } 2184 2185 STATIC int 2186 phy_8706_enable_set(int unit, soc_port_t port, int enable) 2187 { 2188 phy_ctrl_t *pc; 2189 2190 pc = EXT_PHY_SW_STATE(unit, port); 2191 2192 if (enable) { 2193 PHY_FLAGS_CLR(unit, port, PHY_FLAGS_DISABLE); 2194 } else { 2195 PHY_FLAGS_SET(unit, port, PHY_FLAGS_DISABLE); 2196 } 2197 2198 if (PHY_IS_BCM5942(pc)) { 2199 SOC_IF_ERROR_RETURN 2200 (_phy_5942_enable_set(unit, port, enable)); 2201 } else { 2202 SOC_IF_ERROR_RETURN 2203 (_phy_8706_enable_set(unit, port, enable)); 2204 } 2205 2206 if (enable) { 2207 sal_usleep(50); 2208 SOC_IF_ERROR_RETURN(_phy_8706_squelch_enable(unit, port, TRUE)); 2209 } 2210 2211 return SOC_E_NONE; 2212 2213 } 2214 2215 2216 /* 2217 * Function: 2218 * phy_8706_lb_set 2219 * Purpose: 2220 * Put 8706 in PHY PCS/PMA/PMD loopback 2221 * Parameters: 2222 * unit - StrataSwitch unit #. 2223 * port - StrataSwitch port #. 2224 * enable - binary value for on/off (1/0) 2225 * Returns: 2226 * SOC_E_NONE 2227 */ 2228 2229 STATIC int 2230 _phy_8706_lb_set(int unit, soc_port_t port, int enable) 2231 { 2232 phy_ctrl_t *pc; 2233 uint16 tmp; 2234 int speed; 2235 2236 pc = EXT_PHY_SW_STATE(unit, port); 2237 2238 if (NXT_PC(pc)) { 2239 PHYDRV_CALL_ARG1(pc,PHY_LOOPBACK_SET,enable); 2240 return SOC_E_NONE; 2241 } 2242 2243 2244 /* loopback may not supported in the passthru mode on this phy. 2245 * So loopback from internal phy 2246 */ 2247 2248 SOC_IF_ERROR_RETURN 2249 (_phy_8706_speed_get(unit,port,&speed)); 2250 2251 if (speed < 10000) { 2252 phy_ctrl_t *int_pc; /* PHY software state */ 2253 int rv; 2254 2255 int_pc = INT_PHY_SW_STATE(unit, port); 2256 2257 if (NULL != int_pc) { 2258 rv = (PHY_LOOPBACK_SET(int_pc->pd, unit, port, enable)); 2259 } else { 2260 rv = SOC_E_INTERNAL; 2261 } 2262 return rv; 2263 } 2264 2265 #if defined(PHY_8706_PCS_LOOPBACK) 2266 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2267 /* power down PCS RX clock */ 2268 SOC_IF_ERROR_RETURN 2269 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc808, (1<<13), (1<<13))); 2270 } 2271 2272 /* lock detect bypass */ 2273 if (IS_8727_TYPE(pc->phy_id1)) { 2274 2275 tmp = enable ? (1<<14) : 0; 2276 2277 SOC_IF_ERROR_RETURN 2278 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCA7B, tmp, (1<<14))); 2279 } 2280 2281 tmp = enable ? MII_CTRL_LE : 0; 2282 2283 SOC_IF_ERROR_RETURN 2284 (MODIFY_PHY8706_PCS_CTRLr(unit, pc, tmp, MII_CTRL_LE)); 2285 2286 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2287 /* turn on PCS RX clock */ 2288 SOC_IF_ERROR_RETURN 2289 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc808, 0 , (1<<13))); 2290 } 2291 #endif /* PHY_8706_PCS_LOOPBACK */ 2292 2293 #if defined(PHY_8706_PMA_PMD_LOOPBACK) 2294 tmp = enable ? MII_CTRL_PMA_LOOPBACK : 0; 2295 2296 SOC_IF_ERROR_RETURN 2297 (_bcm8726_pmad_write_en(unit,pc, TRUE)); 2298 SOC_IF_ERROR_RETURN 2299 (MODIFY_PHY8706_PMA_PMD_CTRLr(unit, pc, 2300 tmp, MII_CTRL_PMA_LOOPBACK)); 2301 SOC_IF_ERROR_RETURN 2302 (_bcm8726_pmad_write_en(unit, pc, FALSE)); 2303 #endif /* PHY_8706_PMA_PMD_LOOPBACK */ 2304 2305 #if defined(PHY_8706_SYSTEM_LOOPBACK) 2306 2307 tmp = enable? XGXS_MODE_SYSTEM_LOOPBACK | XGXS_CTRL_RLOOP 2308 :XGXS_MODE_NORMAL; 2309 SOC_IF_ERROR_RETURN 2310 (MODIFY_PHY8706_XS_REG(unit,pc,XGXS_MODE_CTRLr, 2311 tmp, 2312 XGXS_MODE_MASK | XGXS_CTRL_RLOOP)); 2313 2314 #endif /* PHY_8706_SYSTEM_LOOPBACK */ 2315 2316 #if defined(PHY_8706_XAUI_LOOPBACK) 2317 SOC_IF_ERROR_RETURN 2318 (READ_PHY8706_XS_REG(unit, pc, 0x8000, &tmp)); 2319 tmp &= ~(0xf << 8); 2320 tmp |= ((enable) ? 6 : 1) << 8; 2321 SOC_IF_ERROR_RETURN 2322 (WRITE_PHY8706_XS_REG(unit, pc, 0x8000, tmp)); 2323 2324 tmp = (enable) ? (0x00f0) : (0x0000); 2325 SOC_IF_ERROR_RETURN 2326 (WRITE_PHY8706_XS_REG(unit, pc, 0x8017, tmp)); 2327 #endif /* PHY_8706_XAUI_LOOPBACK */ 2328 2329 return SOC_E_NONE; 2330 } 2331 2332 STATIC int 2333 _phy_5942_lb_set(int unit, soc_port_t port, int enable) 2334 { 2335 phy_ctrl_t *pc; 2336 2337 pc = EXT_PHY_SW_STATE(unit, port); 2338 2339 SOC_IF_ERROR_RETURN 2340 (MODIFY_PHY8706_XS_REG(unit, pc, 0, enable ? (1U << 14) : 0, (1U << 14))); 2341 2342 return SOC_E_NONE; 2343 } 2344 2345 STATIC int 2346 phy_8706_lb_set(int unit, soc_port_t port, int enable) 2347 { 2348 phy_ctrl_t *pc; 2349 2350 pc = EXT_PHY_SW_STATE(unit, port); 2351 2352 /* Disable(Enable) Squelch when we Enable(Disable) loopback */ 2353 SOC_IF_ERROR_RETURN 2354 (_phy_8706_squelch_enable(unit, port, enable ? FALSE : TRUE)); 2355 2356 if (PHY_IS_BCM5942(pc)) { 2357 SOC_IF_ERROR_RETURN 2358 (_phy_5942_lb_set(unit, port, enable)); 2359 } else { 2360 SOC_IF_ERROR_RETURN 2361 (_phy_8706_lb_set(unit, port, enable)); 2362 } 2363 2364 return SOC_E_NONE; 2365 2366 } 2367 2368 /* 2369 * Function: 2370 * phy_8706_lb_get 2371 * Purpose: 2372 * Get 8706 PHY loopback state 2373 * Parameters: 2374 * unit - StrataSwitch unit #. 2375 * port - StrataSwitch port #. 2376 * enable - address of location to store binary value for on/off (1/0) 2377 * Returns: 2378 * SOC_E_NONE 2379 */ 2380 2381 STATIC int 2382 _phy_8706_lb_get(int unit, soc_port_t port, int *enable) 2383 { 2384 uint16 tmp; 2385 phy_ctrl_t *pc; 2386 int speed; 2387 2388 pc = EXT_PHY_SW_STATE(unit, port); 2389 if (NXT_PC(pc)) { 2390 PHYDRV_CALL_ARG1(pc,PHY_LOOPBACK_GET,enable); 2391 return SOC_E_NONE; 2392 } 2393 2394 2395 SOC_IF_ERROR_RETURN 2396 (_phy_8706_speed_get(unit,port,&speed)); 2397 2398 if (speed < 10000) { 2399 phy_ctrl_t *int_pc; /* PHY software state */ 2400 int rv; 2401 2402 int_pc = INT_PHY_SW_STATE(unit, port); 2403 2404 if (NULL != int_pc) { 2405 rv = (PHY_LOOPBACK_GET(int_pc->pd, unit, port, enable)); 2406 } else { 2407 rv = SOC_E_INTERNAL; 2408 } 2409 return rv; 2410 } 2411 2412 #if defined(PHY_8706_PCS_LOOPBACK) 2413 SOC_IF_ERROR_RETURN 2414 (READ_PHY8706_PCS_CTRLr(unit, pc, &tmp)); 2415 2416 /* ctrl != 0xffff check is to handle removable PHY daughter cards */ 2417 *enable = ((tmp != 0xffff) && (tmp & MII_CTRL_LE)) ? TRUE : FALSE; 2418 #endif /* PHY_8706_PCS_LOOPBACK */ 2419 2420 #if defined(PHY_8706_PMA_PMD_LOOPBACK) 2421 SOC_IF_ERROR_RETURN 2422 (READ_PHY8706_PMA_PMD_CTRLr(unit, pc, &tmp)); 2423 2424 /* ctrl != 0xffff check is to handle removable PHY daughter cards */ 2425 *enable = ((tmp != 0xffff) && (tmp & MII_CTRL_PMA_LOOPBACK)) ? TRUE : FALSE; 2426 #endif /* PHY_8706_PMA_PMD_LOOPBACK */ 2427 2428 #if defined(PHY_8706_SYSTEM_LOOPBACK) 2429 SOC_IF_ERROR_RETURN 2430 (READ_PHY8706_XS_REG(unit,pc,XGXS_MODE_CTRLr,&tmp)); 2431 /* ctrl == 0xffff check is to handle removable PHY daughter cards */ 2432 *enable = ((tmp == 0xffff) || (tmp & XGXS_MODE_MASK))? FALSE:TRUE; 2433 2434 #endif /* PHY_8706_SYSTEM_LOOPBACK */ 2435 2436 #if defined(PHY_8706_XAUI_LOOPBACK) 2437 SOC_IF_ERROR_RETURN 2438 (READ_PHY8706_XS_REG(unit, pc, 0x8000, &tmp)); 2439 /* ctrl != 0xffff check is to handle removable PHY daughter cards */ 2440 *enable = ((tmp != 0xffff) && ((tmp & (0xf << 8)) == (6 << 8))); 2441 #endif /* PHY_8706_XAUI_LOOPBACK */ 2442 2443 LOG_INFO(BSL_LS_SOC_PHY, 2444 (BSL_META_U(unit, 2445 "phy_8706_lb_get: u=%d port%d: loopback:%s\n"), 2446 unit, port, *enable ? "Enabled": "Disabled")); 2447 2448 return SOC_E_NONE; 2449 } 2450 2451 STATIC int 2452 _phy_5942_lb_get(int unit, soc_port_t port, int *enable) 2453 { 2454 phy_ctrl_t *pc; 2455 uint16 tmp; 2456 2457 pc = EXT_PHY_SW_STATE(unit, port); 2458 2459 SOC_IF_ERROR_RETURN 2460 (READ_PHY8706_XS_REG(unit, pc, 0, &tmp)); 2461 2462 *enable = tmp & (1U << 14) ? TRUE : FALSE; 2463 2464 return SOC_E_NONE; 2465 } 2466 2467 STATIC int 2468 phy_8706_lb_get(int unit, soc_port_t port, int *enable) 2469 { 2470 phy_ctrl_t *pc; 2471 2472 pc = EXT_PHY_SW_STATE(unit, port); 2473 2474 if (PHY_IS_BCM5942(pc)) { 2475 SOC_IF_ERROR_RETURN 2476 (_phy_5942_lb_get(unit, port, enable)); 2477 } else { 2478 SOC_IF_ERROR_RETURN 2479 (_phy_8706_lb_get(unit, port, enable)); 2480 } 2481 2482 return SOC_E_NONE; 2483 2484 } 2485 2486 STATIC int phy_8706_linkup(int unit, soc_port_t port) 2487 { 2488 phy_ctrl_t *pc; 2489 2490 pc = EXT_PHY_SW_STATE(unit, port); 2491 2492 if (NXT_PC(pc)) { 2493 PHYDRV_CALL_NOARG(pc, PHY_LINKUP_EVT); 2494 } 2495 2496 return SOC_E_NONE; 2497 } 2498 2499 STATIC int 2500 _phy_8706_bit_order_msb2lsb(uint16 data, int len) 2501 { 2502 int i; 2503 uint16 new_data = 0; 2504 2505 for (i = len - 1; i >= 0; i--) { 2506 if (data & (1 << (len - 1 - i))) { 2507 new_data += (1 << i); 2508 } 2509 } 2510 return new_data; 2511 } 2512 2513 2514 STATIC int 2515 _phy_8706_control_tx_driver_set(int unit, soc_port_t port, 2516 soc_phy_control_t type, uint32 value) 2517 { 2518 uint16 data; /* Temporary holder of reg value to be written */ 2519 uint16 mask; /* Bit mask of reg value to be updated */ 2520 phy_ctrl_t *pc; /* PHY software state */ 2521 2522 pc = EXT_PHY_SW_STATE(unit, port); 2523 2524 /* Dozen SerDes */ 2525 switch(type) { 2526 case SOC_PHY_CONTROL_PREEMPHASIS: 2527 data = (uint16)(value & 0xf); 2528 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2529 data = _phy_8706_bit_order_msb2lsb(data,4); 2530 } 2531 data = data << 12; 2532 mask = 0xf000; 2533 break; 2534 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2535 data = (uint16)(value & 0xf); 2536 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2537 data = _phy_8706_bit_order_msb2lsb(data,4); 2538 } 2539 data = data << 8; 2540 mask = 0x0f00; 2541 break; 2542 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2543 data = (uint16)(value & 0xf); 2544 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2545 data = _phy_8706_bit_order_msb2lsb(data,4); 2546 } 2547 data = data << 4; 2548 mask = 0x00f0; 2549 break; 2550 default: 2551 /* should never get here */ 2552 return SOC_E_PARAM; 2553 } 2554 SOC_IF_ERROR_RETURN 2555 (MODIFY_PHY8706_TXA_ACTRL_3r(unit, pc, data, mask)); 2556 2557 return SOC_E_NONE; 2558 } 2559 2560 STATIC int 2561 _phy_8706_control_tx_driver_get(int unit, soc_port_t port, 2562 soc_phy_control_t type, uint32 *value) 2563 { 2564 uint16 data16; /* Temporary holder of a reg value */ 2565 phy_ctrl_t *pc; /* PHY software state */ 2566 2567 pc = EXT_PHY_SW_STATE(unit, port); 2568 2569 data16 = 0; 2570 SOC_IF_ERROR_RETURN 2571 (READ_PHY8706_TXA_ACTRL_3r(unit, pc, &data16)); 2572 switch(type) { 2573 case SOC_PHY_CONTROL_PREEMPHASIS: 2574 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2575 *value = _phy_8706_bit_order_msb2lsb((data16 & 0xf000) >> 12,4); 2576 } else { 2577 *value = (data16 & 0xf000) >> 12; 2578 } 2579 break; 2580 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2581 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2582 *value = _phy_8706_bit_order_msb2lsb((data16 & 0x0f00) >> 8,4); 2583 } else { 2584 *value = (data16 & 0x0f00) >> 8; 2585 } 2586 break; 2587 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2588 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 2589 *value = _phy_8706_bit_order_msb2lsb((data16 & 0x00f0) >> 4,4); 2590 } else { 2591 *value = (data16 & 0x00f0) >> 4; 2592 } 2593 break; 2594 default: 2595 /* should never get here */ 2596 return SOC_E_PARAM; 2597 } 2598 2599 return SOC_E_NONE; 2600 } 2601 2602 2603 STATIC int 2604 _phy_8706_edc_mode_select(int unit, soc_port_t port, int *mode) 2605 { 2606 int edc_mode; 2607 uint8 eeprom[128]; 2608 2609 /* read module's eeprom */ 2610 SOC_IF_ERROR_RETURN 2611 (phy_8727_i2cdev_read(unit,port,EEPROM_I2C_ADDR,0,128,eeprom)); 2612 2613 /* checks whether the module is either SFP or SFP+, addr0=(03h). */ 2614 if (eeprom[SFP_ID] == SFP_TYPE_SFP_PLUS) { 2615 if (eeprom[SFP_TRCVER_CODE0] & SFP_TRCVER_10G_LRM) { 2616 /* set edc mode 22 */ 2617 edc_mode = 0x22; 2618 } else if (eeprom[SFP_TRCVER_CODE0] & (SFP_TRCVER_10G_ER | 2619 SFP_TRCVER_10G_LR | SFP_TRCVER_10G_SR)) { 2620 /* set edc mode 44 */ 2621 edc_mode = 0x44; 2622 } else { 2623 /* go check for CX1 cable */ 2624 if ((eeprom[SFP_TRCVER_CODE5] & SFP_TRCVER_PASSIVE_CABLE) && 2625 (eeprom[60] & SFP_8431_COMPLIANCE)) { 2626 /* set mode to 55 */ 2627 edc_mode = 0x55; 2628 } else if ((eeprom[SFP_TRCVER_CODE5] & SFP_TRCVER_PASSIVE_CABLE) && 2629 !(eeprom[60] & SFP_8431_COMPLIANCE) && 2630 (eeprom[12] > 99)) { 2631 /* set EDC 55 */ 2632 edc_mode = 0x55; 2633 } else if ((eeprom[SFP_TRCVER_CODE5] & SFP_TRCVER_ACTIVE_CABLE) && 2634 (eeprom[60] & SFP_8431_LIMITED_COMPLIANCE)) { 2635 /* set EDC 44 */ 2636 edc_mode = 0x44; 2637 } else if ((eeprom[SFP_TRCVER_CODE5] & SFP_TRCVER_ACTIVE_CABLE) && 2638 (eeprom[60] & SFP_8431_APPENDIX_E_COMPLIANCE)) { 2639 /* set EDC 55 */ 2640 edc_mode = 0x55; 2641 } else { 2642 /* check for 1G module */ 2643 if (eeprom[SFP_TRCVER_CODE3] & (SFP_TRCVER_1000BASE_T | 2644 SFP_TRCVER_1000BASE_CX | SFP_TRCVER_1000BASE_LX | 2645 SFP_TRCVER_1000BASE_SX)) { 2646 /* set mode 11 */ 2647 edc_mode = 0x11; 2648 } else { 2649 /* set mode to 55 */ 2650 edc_mode = 0x55; 2651 } 2652 } 2653 } 2654 } else { 2655 /* set EDC mode 55 (CX1 passive) */ 2656 edc_mode = 0x55; 2657 } 2658 *mode = edc_mode; 2659 return SOC_E_NONE; 2660 } 2661 2662 STATIC int 2663 _phy_8706_control_edc_mode_set(int unit, soc_port_t port, uint32 value) 2664 { 2665 uint16 data16; 2666 uint16 mask16; 2667 phy_ctrl_t *pc; /* PHY software state */ 2668 2669 pc = EXT_PHY_SW_STATE(unit, port); 2670 2671 /* EDC mode programming sequence*/ 2672 mask16 = 1 << 9; 2673 2674 /* induce LOS condition: toggle register bit 0xc800.9 */ 2675 SOC_IF_ERROR_RETURN 2676 (READ_PHY8706_PMA_PMD_REG(unit,pc, 0xC800,&data16)); 2677 /* only change toggled bit 9 */ 2678 SOC_IF_ERROR_RETURN 2679 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xC800,~data16,mask16)); 2680 2681 /* program EDC mode */ 2682 SOC_IF_ERROR_RETURN 2683 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xCA1A,(uint16)value, 2684 PHY_8727_EDC_MODE_MASK)); 2685 2686 /* remove LOS condition: restore back original value of bit 0xc800.9 */ 2687 SOC_IF_ERROR_RETURN 2688 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xC800,data16,mask16)); 2689 2690 return SOC_E_NONE; 2691 } 2692 2693 STATIC int 2694 _phy_8706_control_edc_mode_get(int unit, soc_port_t port, uint32 *value) 2695 { 2696 uint16 data16; 2697 phy_ctrl_t *pc; /* PHY software state */ 2698 2699 pc = EXT_PHY_SW_STATE(unit, port); 2700 2701 /* program EDC mode */ 2702 SOC_IF_ERROR_RETURN 2703 (READ_PHY8706_PMA_PMD_REG(unit,pc, 0xCA1A,&data16)); 2704 2705 *value = data16 & PHY_8727_EDC_MODE_MASK; 2706 return SOC_E_NONE; 2707 } 2708 2709 STATIC int 2710 _phy_8706_control_edc_config(int unit, soc_port_t port, uint32 value) 2711 { 2712 uint16 data16; 2713 uint16 mask16; 2714 phy_ctrl_t *pc; /* PHY software state */ 2715 int edc_mode = 0; 2716 2717 pc = EXT_PHY_SW_STATE(unit, port); 2718 2719 2720 mask16 = PHY_8727_EDC_AUTO_CONFIG_MASK; 2721 if (value == SOC_PHY_CONTROL_EDC_CONFIG_NONE) { 2722 2723 /* disable hardware EDC auto config */ 2724 data16 = 0; 2725 SOC_IF_ERROR_RETURN 2726 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xC82B,data16,mask16)); 2727 return SOC_E_NONE; 2728 2729 } else if (value == SOC_PHY_CONTROL_EDC_CONFIG_HARDWARE) { 2730 2731 /* enable hardware EDC auto configuration */ 2732 data16 = mask16; 2733 SOC_IF_ERROR_RETURN 2734 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xC82B,data16,mask16)); 2735 return SOC_E_NONE; 2736 2737 } else if (value == SOC_PHY_CONTROL_EDC_CONFIG_SOFTWARE) { 2738 2739 /* disable auto config, perform software EDC config */ 2740 data16 = 0; 2741 SOC_IF_ERROR_RETURN 2742 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, 0xC82B,data16,mask16)); 2743 2744 /* figure out the proper EDC mode based on module's type */ 2745 SOC_IF_ERROR_RETURN 2746 (_phy_8706_edc_mode_select(unit,port,&edc_mode)); 2747 2748 SOC_IF_ERROR_RETURN 2749 (_phy_8706_control_edc_mode_set(unit,port,edc_mode)); 2750 return SOC_E_NONE; 2751 2752 } else { 2753 return SOC_E_PARAM; 2754 } 2755 } 2756 2757 STATIC int 2758 _phy_8706_control_edc_config_get(int unit, soc_port_t port, uint32 *value) 2759 { 2760 uint16 data16; 2761 phy_ctrl_t *pc; /* PHY software state */ 2762 2763 pc = EXT_PHY_SW_STATE(unit, port); 2764 SOC_IF_ERROR_RETURN 2765 (READ_PHY8706_PMA_PMD_REG(unit,pc, 0xC82B,&data16)); 2766 if (data16 & PHY_8727_EDC_AUTO_CONFIG_MASK) { 2767 *value = SOC_PHY_CONTROL_EDC_CONFIG_HARDWARE; 2768 } else { 2769 *value = SOC_PHY_CONTROL_EDC_CONFIG_NONE; 2770 } 2771 return SOC_E_NONE; 2772 } 2773 STATIC int 2774 _phy_8706_control_linkdown_transmit_set(int unit, soc_port_t port, 2775 uint32 value) 2776 { 2777 uint16 data; 2778 uint16 speed, speed_val; 2779 phy_ctrl_t *pc; 2780 2781 pc = EXT_PHY_SW_STATE(unit, port); 2782 SOC_IF_ERROR_RETURN 2783 (READ_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 2784 speed = ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) == 2785 PMAD_CTRL2r_PMA_TYPE_1G_KX) ? 1000 : 10000; 2786 2787 2788 if (speed == 10000) { 2789 /* link partner will not receive due to fault detection */ 2790 return SOC_E_UNAVAIL; 2791 } 2792 2793 if (value) { 2794 SOC_IF_ERROR_RETURN 2795 (PHY8706_REG_READ(unit, pc, 2796 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_PHYXS, 2797 0x8301), 2798 &data)); 2799 data |= 0x0020; 2800 SOC_IF_ERROR_RETURN 2801 (PHY8706_REG_WRITE(unit, pc, 2802 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_PHYXS, 2803 0x8301), 2804 data)); 2805 2806 SOC_IF_ERROR_RETURN 2807 (PHY8706_REG_READ(unit, pc, 2808 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_AN, 2809 0x8301), 2810 &data)); 2811 data |= 0x0020; 2812 SOC_IF_ERROR_RETURN 2813 (PHY8706_REG_WRITE(unit, pc, 2814 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_AN, 2815 0x8301), 2816 data)); 2817 } else { 2818 2819 SOC_IF_ERROR_RETURN 2820 (PHY8706_REG_READ(unit, pc, 2821 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_PHYXS, 2822 0x8301), 2823 &data)); 2824 data &= ~0x0020; 2825 SOC_IF_ERROR_RETURN 2826 (PHY8706_REG_WRITE(unit, pc, 2827 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_PHYXS, 2828 0x8301), 2829 data)); 2830 2831 SOC_IF_ERROR_RETURN 2832 (PHY8706_REG_READ(unit, pc, 2833 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_AN, 2834 0x8301), 2835 &data)); 2836 data &= ~0x0020; 2837 SOC_IF_ERROR_RETURN 2838 (PHY8706_REG_WRITE(unit, pc, 2839 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_AN, 2840 0x8301), 2841 data)); 2842 2843 } 2844 2845 return SOC_E_NONE; 2846 } 2847 2848 STATIC int 2849 _phy_8706_control_linkdown_transmit_get(int unit, soc_port_t port, 2850 uint32 *value) 2851 { 2852 uint16 data; 2853 uint16 speed, speed_val; 2854 phy_ctrl_t *pc; 2855 2856 pc = EXT_PHY_SW_STATE(unit, port); 2857 SOC_IF_ERROR_RETURN 2858 (READ_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 2859 speed = ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) == 2860 PMAD_CTRL2r_PMA_TYPE_1G_KX) ? 1000 : 10000; 2861 2862 if (speed == 10000) { 2863 /* 10G transmits regardless of link */ 2864 return SOC_E_UNAVAIL; 2865 } 2866 2867 SOC_IF_ERROR_RETURN 2868 (PHY8706_REG_READ(unit, pc, 2869 SOC_PHY_CLAUSE45_ADDR(PHY8706_C45_DEV_PHYXS, 2870 0x8301), 2871 &data)); 2872 *value = (data & 0x0020) ? 1 : 0; 2873 2874 return SOC_E_NONE; 2875 } 2876 2877 2878 /* 2879 * Function: 2880 * phy_8706_control_set 2881 * Purpose: 2882 * Configure PHY device specific control fucntion. 2883 * Parameters: 2884 * unit - StrataSwitch unit #. 2885 * port - StrataSwitch port #. 2886 * type - Control to update 2887 * value - New setting for the control 2888 * Returns: 2889 * SOC_E_NONE 2890 */ 2891 STATIC int 2892 phy_8706_control_set(int unit, soc_port_t port, 2893 soc_phy_control_t type, uint32 value) 2894 { 2895 int rv; 2896 phy_ctrl_t *pc; 2897 2898 pc = EXT_PHY_SW_STATE(unit, port); 2899 2900 if (NXT_PC(pc)) { 2901 PHYDRV_CALL_ARG2(pc, PHY_CONTROL_SET, type, value); 2902 return SOC_E_NONE; 2903 } 2904 2905 PHY_CONTROL_TYPE_CHECK(type); 2906 2907 rv = SOC_E_UNAVAIL; 2908 switch(type) { 2909 case SOC_PHY_CONTROL_PREEMPHASIS: 2910 /* fall through */ 2911 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2912 /* fall through */ 2913 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2914 rv = _phy_8706_control_tx_driver_set(unit, port, type, value); 2915 break; 2916 case SOC_PHY_CONTROL_EDC_CONFIG: 2917 rv = _phy_8706_control_edc_config(unit,port,value); 2918 break; 2919 case SOC_PHY_CONTROL_EDC_MODE: 2920 rv = _phy_8706_control_edc_mode_set(unit,port,value); 2921 break; 2922 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 2923 rv = _phy_8706_control_linkdown_transmit_set(unit, port, value); 2924 break; 2925 case SOC_PHY_CONTROL_CLOCK_ENABLE: 2926 SOC_IF_ERROR_RETURN 2927 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCA23, value ? (0x1 << 10) : 0, (0x1 << 10))); 2928 rv = SOC_E_NONE; 2929 break; 2930 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 2931 if (pc->phy_id1 == PHY_ID1_8747) { 2932 uint16 freq; 2933 switch (value) { 2934 case 125000: 2935 freq = 0x1; 2936 break; 2937 case 195312: 2938 freq = 0x2; 2939 break; 2940 case 156250: 2941 freq = 0x3; 2942 break; 2943 default: 2944 freq = 0x0; 2945 break; 2946 } 2947 SOC_IF_ERROR_RETURN 2948 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCACE, (freq << 14), (0x3 << 14))); 2949 rv = SOC_E_NONE; 2950 } else { 2951 rv = SOC_E_UNAVAIL; 2952 } 2953 break; 2954 default: 2955 rv = SOC_E_UNAVAIL; 2956 break; 2957 } 2958 return rv; 2959 } 2960 /* 2961 * Function: 2962 * phy_8706_control_get 2963 * Purpose: 2964 * Get current control settign of the PHY. 2965 * Parameters: 2966 * unit - StrataSwitch unit #. 2967 * port - StrataSwitch port #. 2968 * type - Control to update 2969 * value - (OUT)Current setting for the control 2970 * Returns: 2971 * SOC_E_NONE 2972 */ 2973 STATIC int 2974 phy_8706_control_get(int unit, soc_port_t port, 2975 soc_phy_control_t type, uint32 *value) 2976 { 2977 int rv; 2978 phy_ctrl_t *pc; 2979 uint16 temp16; 2980 2981 pc = EXT_PHY_SW_STATE(unit, port); 2982 2983 if (NXT_PC(pc)) { 2984 PHYDRV_CALL_ARG2(pc, PHY_CONTROL_GET, type, value); 2985 return SOC_E_NONE; 2986 } 2987 2988 PHY_CONTROL_TYPE_CHECK(type); 2989 2990 rv = SOC_E_UNAVAIL; 2991 switch(type) { 2992 case SOC_PHY_CONTROL_PREEMPHASIS: 2993 /* fall through */ 2994 case SOC_PHY_CONTROL_DRIVER_CURRENT: 2995 /* fall through */ 2996 case SOC_PHY_CONTROL_PRE_DRIVER_CURRENT: 2997 rv = _phy_8706_control_tx_driver_get(unit, port, type, value); 2998 break; 2999 case SOC_PHY_CONTROL_EDC_MODE: 3000 rv = _phy_8706_control_edc_mode_get(unit,port,value); 3001 break; 3002 case SOC_PHY_CONTROL_EDC_CONFIG: 3003 rv = _phy_8706_control_edc_config_get(unit,port,value); 3004 break; 3005 case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT: 3006 rv = _phy_8706_control_linkdown_transmit_get(unit, port, value); 3007 break; 3008 case SOC_PHY_CONTROL_CLOCK_ENABLE: 3009 SOC_IF_ERROR_RETURN 3010 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA23, &temp16)); 3011 *value = temp16 & (0x1<<10) ? TRUE : FALSE; 3012 rv = SOC_E_NONE; 3013 break; 3014 case SOC_PHY_CONTROL_CLOCK_FREQUENCY: 3015 if (pc->phy_id1 == PHY_ID1_8747) { 3016 SOC_IF_ERROR_RETURN 3017 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCACE, &temp16)); 3018 switch ((temp16 >> 14) & 0x3) { 3019 case 0x1: 3020 *value = 125000; 3021 break; 3022 case 0x2: 3023 *value = 195312; 3024 break; 3025 case 0x3: 3026 *value = 156250; 3027 break; 3028 default: 3029 *value = 0x0; 3030 break; 3031 } 3032 rv = SOC_E_NONE; 3033 } else { 3034 rv = SOC_E_UNAVAIL; 3035 } 3036 break; 3037 default: 3038 rv = SOC_E_UNAVAIL; 3039 break; 3040 } 3041 3042 return rv; 3043 } 3044 3045 3046 /* 3047 * Function: 3048 * phy_8706_speed_set 3049 * Purpose: 3050 * Set PHY speed 3051 * Parameters: 3052 * unit - StrataSwitch unit #. 3053 * port - StrataSwitch port #. 3054 * speed - link speed in Mbps 3055 * Returns: 3056 * SOC_E_NONE 3057 */ 3058 3059 STATIC int 3060 _phy_8706_speed_set(int unit, soc_port_t port, int speed) 3061 { 3062 phy_ctrl_t *pc; 3063 phy_ctrl_t *int_pc; 3064 XGXS_CFG_t xgxs_cfg; 3065 PHY5942_CFG_t phy5942_cfg; 3066 int rv = SOC_E_NONE; 3067 int type; 3068 3069 COMPILER_REFERENCE(unit); 3070 COMPILER_REFERENCE(port); 3071 3072 LOG_INFO(BSL_LS_SOC_PHY, 3073 (BSL_META_U(unit, 3074 "phy_8706_speed_set: u=%d p=%d speed=%d\n"), 3075 unit, port,speed)); 3076 3077 if (!(speed == 10000 || speed == 1000 || speed == 2500)) { 3078 return SOC_E_PARAM; 3079 } 3080 3081 pc = EXT_PHY_SW_STATE(unit, port); 3082 int_pc = INT_PHY_SW_STATE(unit, port); 3083 3084 /* for 8726 device, speed change will reset XGXS(device 4). 3085 * save/restore the software configuration for XGXS device 3086 */ 3087 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 3088 SOC_IF_ERROR_RETURN 3089 (_phy_8706_xgxs_cfg_save(unit,port, &xgxs_cfg)); 3090 } 3091 if (PHY_IS_BCM5942(pc)) { 3092 SOC_IF_ERROR_RETURN 3093 (_phy_5942_pd_status_save(unit,port, &phy5942_cfg)); 3094 } 3095 3096 if (speed == 10000) { 3097 if (IS_8727_TYPE(pc->phy_id1)) { 3098 type = PMAD_CTRL2r_PMA_TYPE_10G_LRM; 3099 } else { 3100 type = PMAD_CTRL2r_PMA_TYPE_10G_KR; 3101 } 3102 SOC_IF_ERROR_RETURN 3103 (_bcm8726_pmad_write_en(unit, pc, TRUE)); 3104 SOC_IF_ERROR_RETURN 3105 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc, MII_CTRL_REG, 3106 MII_CTRL_SS_LSB,MII_CTRL_SS_LSB)); 3107 3108 SOC_IF_ERROR_RETURN 3109 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, 3110 type,PMAD_CTRL2r_PMA_TYPE_MASK)); 3111 SOC_IF_ERROR_RETURN 3112 (_bcm8726_pmad_write_en(unit, pc, FALSE)); 3113 3114 SOC_IF_ERROR_RETURN 3115 (WRITE_PHY8706_AN_REG(unit, pc, AN_CTRL_REG, 3116 AN_ENABLE | 3117 AN_RESTART)); 3118 3119 sal_usleep(40000); 3120 SOC_IF_ERROR_RETURN 3121 (WRITE_PHY8706_AN_REG(unit,pc, AN_CTRL_REG, 0x0)); 3122 3123 } else { 3124 SOC_IF_ERROR_RETURN 3125 (_bcm8726_pmad_write_en(unit, pc, TRUE)); 3126 SOC_IF_ERROR_RETURN 3127 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, 3128 PMAD_CTRL2r_PMA_TYPE_1G_KX,PMAD_CTRL2r_PMA_TYPE_MASK)); 3129 3130 SOC_IF_ERROR_RETURN 3131 (MODIFY_PHY8706_PMA_PMD_REG(unit,pc,MII_CTRL_REG, 3132 0,MII_CTRL_SS_LSB)); 3133 SOC_IF_ERROR_RETURN 3134 (_bcm8726_pmad_write_en(unit, pc, FALSE)); 3135 } 3136 3137 if (pc->phy_id1 == PHY87X6_REV_A || pc->phy_id1 == PHY87X6_REV_BC) { 3138 SOC_IF_ERROR_RETURN 3139 (_phy_8706_xgxs_cfg_restore(unit,port, &xgxs_cfg)); 3140 } 3141 if (PHY_IS_BCM5942(pc)) { 3142 sal_usleep(40000); 3143 SOC_IF_ERROR_RETURN 3144 (_phy_5942_pd_status_restore(unit,port, &phy5942_cfg)); 3145 } 3146 3147 /* need to set the internal phy's speed accordingly */ 3148 3149 if (NULL != int_pc) { 3150 if (PHY_IS_BCM5942(pc)) { 3151 SOC_IF_ERROR_RETURN 3152 (PHY_INTERFACE_SET(int_pc->pd, unit, port, SOC_PORT_IF_SFI)); 3153 SOC_IF_ERROR_RETURN 3154 (PHY_AUTO_NEGOTIATE_SET (int_pc->pd, unit, port, 0)); 3155 } 3156 rv = PHY_SPEED_SET(int_pc->pd, unit, port, speed); 3157 } 3158 3159 #if 0 3160 if (NXT_PC(pc)) { 3161 PHYDRV_CALL_ARG1(pc,PHY_SPEED_SET,speed); 3162 } 3163 #endif 3164 3165 /* Enable Squelch */ 3166 SOC_IF_ERROR_RETURN(_phy_8706_squelch_enable(unit, port, TRUE)); 3167 3168 return rv; 3169 } 3170 3171 STATIC int 3172 phy_8706_speed_set(int unit, soc_port_t port, int speed) 3173 { 3174 phy_ctrl_t *pc; 3175 3176 pc = EXT_PHY_SW_STATE(unit, port); 3177 3178 SOC_IF_ERROR_RETURN 3179 (_phy_8706_speed_set (unit, port, speed)); 3180 if (NXT_PC(pc)) { 3181 PHYDRV_CALL_ARG1(pc,PHY_SPEED_SET,speed); 3182 } 3183 3184 return SOC_E_NONE; 3185 } 3186 3187 /* 3188 * Function: 3189 * phy_8706_speed_get 3190 * Purpose: 3191 * Get PHY speed 3192 * Parameters: 3193 * unit - StrataSwitch unit #. 3194 * port - StrataSwitch port #. 3195 * speed - current link speed in Mbps 3196 * Returns: 3197 * SOC_E_NONE 3198 */ 3199 3200 STATIC int 3201 _phy_8706_speed_get(int unit, soc_port_t port, int *speed) 3202 { 3203 phy_ctrl_t *pc; 3204 uint16 speed_val; 3205 int an = 0; 3206 int an_done = 0; 3207 3208 pc = EXT_PHY_SW_STATE(unit, port); 3209 3210 if (NXT_PC(pc)) { 3211 PHYDRV_CALL_ARG1(pc,PHY_SPEED_GET,speed); 3212 return SOC_E_NONE; 3213 } 3214 3215 _phy_8706_an_get(unit,port,&an,&an_done); 3216 3217 *speed = 10000; 3218 if (an) { /* autoneg is enabled */ 3219 if (an_done) { 3220 *speed = 1000; /* can only do 1G autoneg */ 3221 } 3222 } else { /* autoneg is not enabled, forced speed */ 3223 3224 SOC_IF_ERROR_RETURN 3225 (READ_PHY8706_PMA_PMD_REG(unit,pc,PMAD_CTRL2_REG, &speed_val)); 3226 if ((speed_val & PMAD_CTRL2r_PMA_TYPE_MASK) == 3227 PMAD_CTRL2r_PMA_TYPE_1G_KX) { 3228 *speed = 1000; 3229 } else { 3230 *speed = 10000; 3231 } 3232 } 3233 return SOC_E_NONE; 3234 } 3235 3236 STATIC int 3237 phy_8706_speed_get(int unit, soc_port_t port, int *speed) 3238 { 3239 phy_ctrl_t *pc; 3240 3241 pc = EXT_PHY_SW_STATE(unit, port); 3242 3243 if (NXT_PC(pc)) { 3244 PHYDRV_CALL_ARG1(pc,PHY_SPEED_GET,speed); 3245 return SOC_E_NONE; 3246 } 3247 SOC_IF_ERROR_RETURN 3248 (_phy_8706_speed_get(unit, port, speed)); 3249 3250 return SOC_E_NONE; 3251 } 3252 /* 3253 * Function: 3254 * _phy_8747_firmware_ram_set 3255 * Purpose: 3256 * write the given firmware to the internal RAM 3257 * Parameters: 3258 * unit - StrataSwitch unit #. 3259 * port - StrataSwitch port #. 3260 * offset - offset to the data stream 3261 * array - the given data 3262 * datalen- the data length 3263 * Returns: 3264 * SOC_E_NONE 3265 */ 3266 3267 STATIC int 3268 _phy_8747_firmware_ram_set(int unit, int port, int offset, uint8 *array,int datalen) 3269 { 3270 int j; 3271 phy_ctrl_t *pc; 3272 uint16 data16; 3273 uint16 mask16; 3274 3275 if (array == NULL) { 3276 return SOC_E_PARAM; 3277 } 3278 3279 pc = EXT_PHY_SW_STATE(unit, port); 3280 3281 /* Programme SPA Control Register to Boot from MDIO 3282 * bit 15, 0 MDIO for serial boot. bit 14, 1 serial boot, 3283 * bit 13, 0, clear download done which is set by uC 3284 */ 3285 mask16 = (1 << 13) | (1 << 14) | (1 << 15); 3286 data16 = 1 << 14; 3287 SOC_IF_ERROR_RETURN 3288 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, PHY8706_PMAD_SPA_CTRL_REG, 3289 data16,mask16)); 3290 3291 /* Reset, to download code from MDIO */ 3292 SOC_IF_ERROR_RETURN 3293 (READ_PHY8706_PMA_PMD_CTRLr(unit, pc, &data16)); 3294 3295 data16 |= 0x8000; 3296 3297 SOC_IF_ERROR_RETURN 3298 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, data16)); 3299 3300 sal_usleep(3000); /* Wait for 3ms */ 3301 3302 /* Write Starting Address, where the Code will reside in SRAM */ 3303 data16 = 0xC000; 3304 SOC_IF_ERROR_RETURN 3305 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 3306 PHY8706_PMAD_M8051_MSGIN_REG, data16)); 3307 sal_udelay(20); /* Wait for 15us */ 3308 3309 /* Write SPI SRAM Count Size */ 3310 data16 = (datalen)/2; 3311 SOC_IF_ERROR_RETURN 3312 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 3313 PHY8706_PMAD_M8051_MSGIN_REG, data16)); 3314 sal_udelay(20); /* Wait for 15us */ 3315 3316 /* Fill in the SPI RAM */ 3317 for (j = 0; j < datalen/2; j++) { 3318 data16 = (array[2*j] << 8) | array[2*j+1]; 3319 SOC_IF_ERROR_RETURN 3320 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 3321 PHY8706_PMAD_M8051_MSGIN_REG, data16)); 3322 3323 /* Make sure the word is read by the Micro */ 3324 sal_udelay(20); /* Wait for 15us */ 3325 } 3326 3327 /* Read Hand-Shake message (Done) from Micro */ 3328 SOC_IF_ERROR_RETURN 3329 (READ_PHY8706_PMA_PMD_REG(unit, pc, 3330 PHY8706_PMAD_M8051_MSGOUT_REG, &data16)); 3331 3332 if (data16 != 0x4321) { 3333 /* Download failure */ 3334 LOG_CLI((BSL_META_U(unit, 3335 "_phy8706_mdio_firmware_download fail,p=%d done msg 0x%x\n"), 3336 port,data16)); 3337 return SOC_E_FAIL; 3338 } 3339 3340 /* Clear LASI status */ 3341 SOC_IF_ERROR_RETURN 3342 (READ_PHY8706_PMA_PMD_REG(unit, pc, 3343 PHY8706_PMAD_RX_ALARM_STAT_REG, &data16)); 3344 3345 /* Wait for LASI to be asserted when M8051 writes checksum to MSG_OUTr */ 3346 sal_udelay(400); /* Wait for 300us */ 3347 3348 /* read message out reg */ 3349 SOC_IF_ERROR_RETURN 3350 (READ_PHY8706_PMA_PMD_REG(unit, pc, 3351 PHY8706_PMAD_M8051_MSGOUT_REG, &data16)); 3352 3353 LOG_INFO(BSL_LS_SOC_PHY, 3354 (BSL_META_U(unit, 3355 "_phy8706_mdio_firmware_download: p=%d msgout 0x%x\n"), 3356 port,data16)); 3357 3358 /* clear LASI */ 3359 SOC_IF_ERROR_RETURN 3360 (READ_PHY8706_PMA_PMD_REG(unit, pc, 3361 PHY8706_PMAD_RX_ALARM_STAT_REG, &data16)); 3362 3363 SOC_IF_ERROR_RETURN 3364 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA1C, &data16)); 3365 3366 /* check if checksum is correct */ 3367 if (data16 != 0x600D) { 3368 /* Bad CHECKSUM */ 3369 LOG_CLI((BSL_META_U(unit, 3370 "_phy8706_mdio_firmware_download, bad cksum: " 3371 "p=%d, cksum=0x%x\n"), 3372 port,data16)); 3373 return SOC_E_FAIL; 3374 } 3375 3376 return SOC_E_NONE; 3377 } 3378 3379 /* 3380 * Function: 3381 * _phy_8727_firmware_ram_set 3382 * Purpose: 3383 * write the given firmware to the internal RAM 3384 * Parameters: 3385 * unit - StrataSwitch unit #. 3386 * port - StrataSwitch port #. 3387 * offset - offset to the data stream 3388 * array - the given data 3389 * datalen- the data length 3390 * Returns: 3391 * SOC_E_NONE 3392 */ 3393 3394 STATIC int 3395 _phy_8727_firmware_ram_set(int unit, int port, int offset, uint8 *array,int datalen) 3396 { 3397 int j; 3398 soc_timeout_t to; 3399 int rv; 3400 phy_ctrl_t *pc; 3401 uint16 data16 = 0; 3402 3403 if (array == NULL) { 3404 return SOC_E_PARAM; 3405 } 3406 3407 rv = SOC_E_NONE; 3408 pc = EXT_PHY_SW_STATE(unit, port); 3409 3410 /* Reset, to download code from MDIO */ 3411 SOC_IF_ERROR_RETURN 3412 (READ_PHY8706_PMA_PMD_CTRLr(unit, pc, &data16)); 3413 3414 data16 |= 0x8000; 3415 3416 SOC_IF_ERROR_RETURN 3417 (WRITE_PHY8706_PMA_PMD_CTRLr(unit, pc, data16)); 3418 3419 sal_usleep(500000); /* Wait for 500ms */ 3420 3421 SOC_IF_ERROR_RETURN 3422 (phy_8727_opt_lvl_set(unit, port)); 3423 3424 /* Read Hand-Shake message from Micro */ 3425 SOC_IF_ERROR_RETURN 3426 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3427 if (data16 != 0x101) { 3428 LOG_WARN(BSL_LS_SOC_PHY, 3429 (BSL_META_U(unit, 3430 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3431 port,data16,0x101)); 3432 return SOC_E_FAIL; 3433 } 3434 3435 /* writes 0x5555 */ 3436 SOC_IF_ERROR_RETURN 3437 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, 0x5555)); 3438 sal_udelay(20); /* Wait for 15us */ 3439 3440 /* Read Hand-Shake message from Micro */ 3441 SOC_IF_ERROR_RETURN 3442 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3443 if (data16 != 0xabcd) { 3444 LOG_WARN(BSL_LS_SOC_PHY, 3445 (BSL_META_U(unit, 3446 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3447 port,data16,0xabcd)); 3448 return SOC_E_FAIL; 3449 } 3450 3451 /* Write Starting Address, where the Code will reside in SRAM */ 3452 data16 = 0xC000; 3453 SOC_IF_ERROR_RETURN 3454 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, data16)); 3455 sal_udelay(20); /* Wait for 15us */ 3456 3457 /* Read Hand-Shake message from Micro */ 3458 SOC_IF_ERROR_RETURN 3459 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3460 if (data16 != 0xadd) { 3461 LOG_WARN(BSL_LS_SOC_PHY, 3462 (BSL_META_U(unit, 3463 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3464 port,data16,0xadd)); 3465 return SOC_E_FAIL; 3466 } 3467 3468 /* Write SPI SRAM Count Size */ 3469 data16 = (datalen)/2; 3470 SOC_IF_ERROR_RETURN 3471 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, data16)); 3472 sal_udelay(20); /* Wait for 15us */ 3473 3474 /* Read Hand-Shake message from Micro */ 3475 SOC_IF_ERROR_RETURN 3476 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3477 if (data16 != 0xab00) { 3478 LOG_WARN(BSL_LS_SOC_PHY, 3479 (BSL_META_U(unit, 3480 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3481 port,data16,0xab00)); 3482 return SOC_E_FAIL; 3483 } 3484 3485 /* Fill in the SPI RAM */ 3486 for (j = 0; j < datalen/2; j++) { 3487 data16 = array[2*j] | (array[2*j+1] << 8); 3488 SOC_IF_ERROR_RETURN 3489 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, data16)); 3490 3491 /* Make sure the word is read by the Micro */ 3492 sal_udelay(20); /* Wait for 15us */ 3493 } 3494 3495 /* Read Hand-Shake message (Done) from Micro */ 3496 SOC_IF_ERROR_RETURN 3497 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3498 3499 if (data16 != 0x4321) { 3500 /* Download failure */ 3501 LOG_WARN(BSL_LS_SOC_PHY, 3502 (BSL_META_U(unit, 3503 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3504 port,data16,0x4321)); 3505 return SOC_E_FAIL; 3506 } 3507 3508 /* Clear LASI status */ 3509 SOC_IF_ERROR_RETURN 3510 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &data16)); 3511 3512 /* Wait for LASI to be asserted when M8051 writes checksum to MSG_OUTr */ 3513 sal_udelay(400); /* Wait for 300us */ 3514 3515 /* check if checksum is correct */ 3516 SOC_IF_ERROR_RETURN 3517 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &data16)); 3518 3519 /* Need to check if checksum is correct */ 3520 if (data16 != 0x300) { 3521 /* Bad CHECKSUM */ 3522 LOG_WARN(BSL_LS_SOC_PHY, 3523 (BSL_META_U(unit, 3524 "firmware_ram_set: p=%d wrong msgout value (0x%x) vs 0x%x\n"), 3525 port,data16,0x300)); 3526 return SOC_E_FAIL; 3527 } 3528 3529 /* clear LASI */ 3530 SOC_IF_ERROR_RETURN 3531 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &data16)); 3532 3533 /* update SPI boot control bit, next time micro boots from SPI RAM */ 3534 SOC_IF_ERROR_RETURN 3535 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCA85, 0x1, 0x1)); 3536 3537 /* Apply soft reset to Micro and make sure SPI is not downloaded */ 3538 SOC_IF_ERROR_RETURN 3539 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA10, 0x00C4)); 3540 3541 /* remove soft reset */ 3542 SOC_IF_ERROR_RETURN 3543 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA10, 0x00C0)); 3544 3545 /* Wait for device to come out of reset */ 3546 soc_timeout_init(&to, 10000, 0); 3547 while (!soc_timeout_check(&to)) { 3548 rv = READ_PHY8706_PMA_PMD_REG(unit, pc, 0xca13, &data16); 3549 if ((data16 == 0x202) || SOC_FAILURE(rv)) { 3550 break; 3551 } 3552 } 3553 if (data16 != 0x202) { 3554 rv = SOC_E_TIMEOUT; 3555 LOG_WARN(BSL_LS_SOC_PHY, 3556 (BSL_META_U(unit, 3557 "firmware_ram_set fail: p=%d msgout 0x%x vs 0x%x\n"), 3558 port,data16,0x202)); 3559 } 3560 return rv; 3561 } 3562 3563 /* 3564 * Function: * phy_8706_rom_wait 3565 * 3566 * Purpose: 3567 * Wait for data to be written to the SPI-ROM. 3568 * Input: 3569 * unit, port 3570 */ 3571 STATIC int 3572 phy_8706_rom_wait(int unit, int port) 3573 { 3574 uint16 rd_data; 3575 uint16 wr_data; 3576 int count; 3577 phy_ctrl_t *pc; 3578 soc_timeout_t to; 3579 int SPI_READY; 3580 3581 pc = EXT_PHY_SW_STATE(unit, port); 3582 3583 rd_data = 0; 3584 soc_timeout_init(&to, WR_TIMEOUT, 0); 3585 do { 3586 /* Write SPI Control Register Read Command. */ 3587 count = 1; 3588 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 3589 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3590 wr_data = SPI_CTRL_1_L; 3591 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3592 if (rd_data & 0x0100) { 3593 break; 3594 } 3595 } while (!soc_timeout_check(&to)); 3596 if (!(rd_data & 0x0100)) { 3597 LOG_ERROR(BSL_LS_SOC_PHY, 3598 (BSL_META_U(unit, 3599 "phy_8706_rom_program: u = %d p = %d " 3600 "timeout 1\n"), unit, port)); 3601 return SOC_E_TIMEOUT; 3602 } 3603 3604 SPI_READY = 1; 3605 while (SPI_READY == 1) { 3606 /* Set-up SPI Controller To Receive SPI EEPROM Status. */ 3607 count = 1; 3608 wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count); 3609 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3610 wr_data = SPI_CTRL_2_H; 3611 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3612 wr_data = 0x0100; 3613 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3614 /* Fill-up SPI Transmit Fifo To check SPI Status. */ 3615 count = 2; 3616 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3617 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3618 /* Write Tx Fifo Register Address. */ 3619 wr_data = SPI_TXFIFO; 3620 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3621 3622 /* Write SPI Tx Fifo Control Word-1. */ 3623 wr_data = ((1 * 0x0100) | MSGTYPE_HRD); 3624 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3625 /* Write SPI Tx Fifo Control Word-2. */ 3626 wr_data = RDSR_OPCODE; 3627 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3628 /* Write SPI Control Register Write Command. */ 3629 count = 2; 3630 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3631 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3632 /* Write SPI Control -1 Register Address. */ 3633 wr_data = SPI_CTRL_1_L; 3634 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3635 /* Write SPI Control -1 Register Word-1. */ 3636 wr_data = 0x0101; 3637 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3638 /* Write SPI Control -1 Register Word-2. */ 3639 wr_data = 0x0100; 3640 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3641 /* Write SPI Control Register Write Command. */ 3642 count = 1; 3643 wr_data = ((WR_CPU_CTRL_REGS * 0x0100) | count); 3644 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3645 /* Write SPI Control -1 Register Address. */ 3646 wr_data = SPI_CTRL_1_H; 3647 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3648 /* Write SPI Control -1 Register Word-2. */ 3649 wr_data = 0x0103; 3650 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3651 /* Wait For 64 bytes To be written. */ 3652 rd_data = 0x0000; 3653 soc_timeout_init(&to, WR_TIMEOUT, 0); 3654 do { 3655 count = 1; 3656 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 3657 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3658 wr_data = SPI_CTRL_1_L; 3659 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3660 if (rd_data & 0x0100) { 3661 break; 3662 } 3663 } while (!soc_timeout_check(&to)); 3664 if (!(rd_data & 0x0100)) { 3665 LOG_ERROR(BSL_LS_SOC_PHY, 3666 (BSL_META_U(unit, 3667 "phy_8706_rom_program: u = %d p = %d " 3668 "timeout 2\n"), unit, port)); 3669 return SOC_E_TIMEOUT; 3670 } 3671 /* Write SPI Control Register Read Command. */ 3672 count = 1; 3673 wr_data = ((RD_CPU_CTRL_REGS * 0x0100) | count); 3674 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3675 /* Write SPI Control -1 Register Address. */ 3676 wr_data = SPI_RXFIFO; 3677 3678 SOC_IF_ERROR_RETURN 3679 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, wr_data)); 3680 SOC_IF_ERROR_RETURN 3681 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &rd_data)); 3682 3683 /* Clear LASI Message Out Status. */ 3684 SOC_IF_ERROR_RETURN 3685 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &wr_data)); 3686 3687 if ((rd_data & 0x1) == 0) { 3688 SPI_READY = 0; 3689 } 3690 } /* SPI_READY */ 3691 return SOC_E_NONE; 3692 } 3693 3694 3695 /* 3696 * Function: 3697 * phy_8706_rom_write_enable_set 3698 * 3699 * Purpose: 3700 * Enable disable protection on SPI_EEPROM 3701 * 3702 * Input: 3703 * unit 3704 * port 3705 * enable 3706 * Output: 3707 * SOC_E_xxx 3708 * 3709 * Notes: 3710 * 25AA256 256Kbit Serial EEPROM 3711 * STATUS Register 3712 * +------------------------------------------+ 3713 * | WPEN | x | x | x | BP1 | BP0 | WEL | WIP | 3714 * +------------------------------------------+ 3715 * BP1 BP0 : Protected Blocks 3716 * 0 0 : Protect None 3717 * 1 1 : Protect All 3718 * 3719 * WEL : Write Latch Enable 3720 * 0 : Do not allow writes 3721 * 1 : Allow writes 3722 */ 3723 3724 STATIC int 3725 phy_8706_rom_write_enable_set(int unit, int port, int enable) 3726 { 3727 uint16 rd_data; 3728 uint16 wr_data; 3729 uint8 wrsr_data; 3730 int count; 3731 phy_ctrl_t *pc; 3732 3733 pc = EXT_PHY_SW_STATE(unit, port); 3734 3735 /* 3736 * Write SPI Control Register Write Command. 3737 */ 3738 count = 2; 3739 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3740 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3741 3742 /* 3743 * Write SPI Control -2 Register Address. 3744 */ 3745 wr_data = SPI_CTRL_2_L; 3746 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3747 3748 /* 3749 * Write SPI Control -2 Register Word-1. 3750 */ 3751 wr_data = 0x8200; 3752 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3753 3754 /* 3755 * Write SPI Control -2 Register Word-2. 3756 */ 3757 wr_data = 0x0100; 3758 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3759 3760 /* 3761 * Fill-up SPI Transmit Fifo With SPI EEPROM Messages. 3762 * Write SPI Control Register Write Command. 3763 */ 3764 count = 4; 3765 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3766 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3767 3768 /* 3769 * Write Tx Fifo Register Address. 3770 */ 3771 wr_data = SPI_TXFIFO; 3772 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3773 3774 /* 3775 * Write SPI Tx Fifo Control Word-1. 3776 */ 3777 wr_data = ((1 * 0x0100) | MSGTYPE_HWR); 3778 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3779 3780 /* 3781 * Write SPI Tx Fifo Control Word-2. 3782 */ 3783 wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE); 3784 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3785 3786 /* 3787 * Write SPI Tx Fifo Control Word-3. 3788 */ 3789 wr_data = ((WRSR_OPCODE * 0x100) | (0x2)); 3790 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3791 3792 /* 3793 * Write SPI Tx Fifo Control Word-4. 3794 */ 3795 wrsr_data = enable ? 0x2 : 0xc; 3796 wr_data = ((wrsr_data * 0x0100) | wrsr_data); 3797 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3798 3799 /* 3800 * Write SPI Control Register Write Command. 3801 */ 3802 count = 2; 3803 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3804 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3805 3806 /* 3807 * Write SPI Control -1 Register Address. 3808 */ 3809 wr_data = SPI_CTRL_1_L; 3810 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3811 3812 /* 3813 * Write SPI Control -1 Register Word-1. 3814 */ 3815 wr_data = 0x0101; 3816 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3817 3818 /* 3819 * Write SPI Control -1 Register Word-2. 3820 */ 3821 wr_data = 0x0003; 3822 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3823 3824 /* 3825 * Wait For WRSR Command To be written. 3826 */ 3827 SOC_IF_ERROR_RETURN(phy_8706_rom_wait(unit, port)); 3828 3829 return SOC_E_NONE; 3830 } 3831 /* 3832 * Function: 3833 * phy_8706_firmware_set 3834 * Purpose: 3835 * program the given firmware into the SPI-ROM 3836 * Parameters: 3837 * unit - StrataSwitch unit #. 3838 * port - StrataSwitch port #. 3839 * offset - offset to the data stream 3840 * array - the given data 3841 * datalen- the data length 3842 * Returns: 3843 * SOC_E_NONE 3844 */ 3845 3846 STATIC int 3847 phy_8706_firmware_set(int unit, int port, int offset, uint8 *array,int datalen) 3848 { 3849 3850 uint16 rd_data; 3851 uint16 wr_data; 3852 uint16 tx_disable_reg; 3853 int j; 3854 int i = 0; 3855 int count; 3856 phy_ctrl_t *pc; 3857 uint8 spi_values[WR_BLOCK_SIZE]; 3858 #ifdef BCM8727_MICROCODE_LOAD_WAR 3859 uint16 rev; 3860 uint16 phyid1; 3861 #endif 3862 3863 pc = EXT_PHY_SW_STATE(unit, port); 3864 3865 /* save the PMAD TX disable reg. */ 3866 SOC_IF_ERROR_RETURN 3867 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9, &tx_disable_reg)); 3868 3869 /* disable TX and bring the link down if it's up */ 3870 SOC_IF_ERROR_RETURN 3871 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x9, 0x1)); 3872 3873 if (pc->phy_id1 == PHY_ID1_8747) { 3874 SOC_IF_ERROR_RETURN 3875 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc843, 0x0000, 0x000f)); 3876 SOC_IF_ERROR_RETURN 3877 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc840, 0x0000, 0x000c)); 3878 } 3879 3880 /* 3881 * Read LASI Status registers To clear initial Failure status. 3882 */ 3883 SOC_IF_ERROR_RETURN 3884 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &rd_data)); 3885 SOC_IF_ERROR_RETURN 3886 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9004, &rd_data)); 3887 SOC_IF_ERROR_RETURN 3888 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9005, &rd_data)); 3889 3890 /* 3891 * Enable the LASI For Message out. 3892 */ 3893 if (IS_8727_TYPE(pc->phy_id1)) { 3894 SOC_IF_ERROR_RETURN 3895 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x9000, 0x0004)); 3896 } else { 3897 SOC_IF_ERROR_RETURN 3898 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x9000, 0x0400)); 3899 } 3900 /* 3901 * 0x9002, bit 2 Is Rx Alarm enabled For LASI. 3902 */ 3903 SOC_IF_ERROR_RETURN 3904 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x9002, 0x0004)); 3905 /* 3906 * Read Any Residual Message out register. 3907 */ 3908 SOC_IF_ERROR_RETURN 3909 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &rd_data)); 3910 /* 3911 * Clear LASI Message Out Status. 3912 */ 3913 SOC_IF_ERROR_RETURN 3914 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &rd_data)); 3915 3916 /* 3917 * ser_boot pin HIGH 3918 */ 3919 SOC_IF_ERROR_RETURN 3920 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCA85, 0x1, 0x1)); 3921 3922 /* set SPI-ROM write enable */ 3923 SOC_IF_ERROR_RETURN(phy_8706_rom_write_enable_set(unit, port, 1)); 3924 3925 LOG_INFO(BSL_LS_SOC_PHY, 3926 (BSL_META_U(unit, 3927 "init0: u=%d p=%d\n"), 3928 unit, port)); 3929 3930 for (j = 0; j < datalen; j += WR_BLOCK_SIZE) { 3931 /* 3932 * Setup SPI Controller. 3933 */ 3934 count = 2; 3935 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3936 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3937 3938 /* Write SPI Control -2 Register Address.*/ 3939 wr_data = SPI_CTRL_2_L; 3940 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3941 3942 /* Write SPI Control -2 Register Word-1. */ 3943 wr_data = 0x8200; 3944 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3945 3946 /* Write SPI Control -2 Register Word-2. */ 3947 wr_data = 0x0100; 3948 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3949 3950 /* Fill-up SPI Transmit Fifo. 3951 * Write SPI Control Register Write Command. 3952 */ 3953 count = 4 + (WR_BLOCK_SIZE / 2); 3954 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 3955 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3956 3957 /* Write Tx Fifo Register Address. */ 3958 wr_data = SPI_TXFIFO; 3959 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3960 3961 /* Write SPI Tx Fifo Control Word-1. */ 3962 wr_data = ((1 * 0x0100) | MSGTYPE_HWR); 3963 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3964 3965 /* Write SPI Tx Fifo Control Word-2. */ 3966 wr_data = ((MSGTYPE_HWR * 0x0100) | WREN_OPCODE); 3967 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3968 3969 /* Write SPI Tx Fifo Control Word-3. */ 3970 wr_data = ((WR_OPCODE * 0x0100) | (0x3 + WR_BLOCK_SIZE)); 3971 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3972 3973 /* Write SPI Tx Fifo Control Word-4. */ 3974 wr_data = (((j & 0x00FF) * 0x0100) | ((j & 0xFF00) / 0x0100)); 3975 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 3976 3977 LOG_INFO(BSL_LS_SOC_PHY, 3978 (BSL_META_U(unit, 3979 "loop: u=%d p=%d,inxj: %d,inxi:%d\n"), 3980 unit, port,j,i)); 3981 3982 if (datalen < (j + WR_BLOCK_SIZE)) { /* last block */ 3983 sal_memset(spi_values,0,WR_BLOCK_SIZE); 3984 sal_memcpy(spi_values,&array[j],datalen - j); 3985 3986 for (i = 0; i < WR_BLOCK_SIZE; i += 2) { 3987 /* Write SPI Tx Fifo Data Word-4. */ 3988 wr_data = ((spi_values[i+1] * 0x0100) | spi_values[i]); 3989 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data)); 3990 } 3991 } else { 3992 for (i = 0; i < WR_BLOCK_SIZE; i += 2) { 3993 /* Write SPI Tx Fifo Data Word-4. */ 3994 wr_data = ((array[j+i+1] * 0x0100) | array[j+i]); 3995 SOC_IF_ERROR_RETURN(write_message(unit, pc,wr_data, &rd_data)); 3996 } 3997 } 3998 3999 /* 4000 * Set-up SPI Controller To Transmit. 4001 * Write SPI Control Register Write Command. 4002 */ 4003 count = 2; 4004 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 4005 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4006 4007 wr_data = SPI_CTRL_1_L; 4008 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4009 4010 /* Write SPI Control -1 Register Word-1. */ 4011 wr_data = 0x0501; 4012 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4013 4014 /* Write SPI Control -1 Register Word-2. */ 4015 wr_data = 0x0003; 4016 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4017 4018 /* Wait For 64 bytes To be written. */ 4019 SOC_IF_ERROR_RETURN(phy_8706_rom_wait(unit,port)); 4020 4021 } /* SPI_WRITE */ 4022 4023 /* clear SPI-ROM write enable */ 4024 SOC_IF_ERROR_RETURN(phy_8706_rom_write_enable_set(unit, port, 0)); 4025 4026 /* Disable SPI EEPROM. */ 4027 count = 2; 4028 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 4029 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4030 4031 /* Write SPI Control -2 Register Address. */ 4032 wr_data = SPI_CTRL_2_L; 4033 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4034 4035 /* Write SPI Control -2 Register Word-1. */ 4036 wr_data = 0x8200; 4037 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4038 4039 /* Write SPI Control -2 Register Word-2. */ 4040 wr_data = 0x0100; 4041 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4042 4043 4044 /* Fill-up SPI Transmit Fifo With SPI EEPROM Messages. */ 4045 count = 2; 4046 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 4047 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4048 4049 /* Write Tx Fifo Register Address. */ 4050 wr_data = SPI_TXFIFO; 4051 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4052 4053 /* Write SPI Tx Fifo Control Word-1. */ 4054 wr_data = ((0x1*0x0100) | MSGTYPE_HWR); 4055 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4056 4057 /* Write SPI Tx Fifo Control Word-2. */ 4058 wr_data = WRDI_OPCODE; 4059 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4060 4061 /* Write SPI Control Register Write Command. */ 4062 count = 2; 4063 wr_data = ((WR_CPU_CTRL_FIFO * 0x0100) | count); 4064 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4065 4066 /* Write SPI Control -1 Register Address. */ 4067 wr_data = SPI_CTRL_1_L; 4068 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4069 4070 /* Write SPI Control -1 Register Word-1. */ 4071 wr_data = 0x0101; 4072 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4073 4074 /* Write SPI Control -1 Register Word-2. */ 4075 wr_data = 0x0003; 4076 SOC_IF_ERROR_RETURN(write_message(unit, pc, wr_data, &rd_data)); 4077 4078 /* 4079 * ser_boot pin LOW 4080 */ 4081 SOC_IF_ERROR_RETURN 4082 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xCA85, 0x0, 0x1)); 4083 4084 if (pc->phy_id1 == PHY_ID1_8747) { 4085 SOC_IF_ERROR_RETURN 4086 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc843, 0x000f, 0x000f)); 4087 SOC_IF_ERROR_RETURN 4088 (MODIFY_PHY8706_PMA_PMD_REG(unit, pc, 0xc840, 0x000c, 0x000c)); 4089 } 4090 4091 /* restore the PMAD TX disable reg. */ 4092 SOC_IF_ERROR_RETURN 4093 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x9, tx_disable_reg)); 4094 4095 LOG_INFO(BSL_LS_SOC_PHY, 4096 (BSL_META_U(unit, 4097 "phy_8706_rom_program: u=%d p=%d done\n"), unit, port)); 4098 4099 #ifdef BCM8727_MICROCODE_LOAD_WAR 4100 /* 4101 * After firmware in ROM is changed, enforce the microcode load 4102 * status in the device as 0xbaad (!=0x600d) so that firmware written 4103 * to ROM by this firmware_set is loaded to the device during port_init. 4104 * else _8727_rom_load_war( ) will not load the firmware to device and 4105 * device will run with previous firmware. 4106 */ 4107 SOC_IF_ERROR_RETURN 4108 (READ_PHY8706_PMA_PMD_REG(unit, pc, MII_PHY_ID1_REG, &phyid1)); 4109 if (phyid1 == PHY_ID1_8727) { 4110 SOC_IF_ERROR_RETURN 4111 (pc->read(unit, pc->phy_id, SOC_PHY_CLAUSE45_ADDR(0x1,0xc801), &rev)); 4112 if ((rev == 0x2) || (rev == 0x3)) { 4113 SOC_IF_ERROR_RETURN 4114 (pc->write(unit, pc->phy_id, SOC_PHY_CLAUSE45_ADDR(0x1,0xca1c), 0xBAAD)); 4115 } 4116 } 4117 #endif 4118 return SOC_E_NONE; 4119 } 4120 4121 static int 4122 write_message(int unit, phy_ctrl_t *pc, uint16 wrdata, uint16 *rddata) 4123 { 4124 4125 uint16 tmp_data = 0; 4126 soc_timeout_t to; 4127 4128 SOC_IF_ERROR_RETURN 4129 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data)); 4130 /* Clear any lingering LASI Message Out Status. */ 4131 SOC_IF_ERROR_RETURN 4132 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &tmp_data)); 4133 SOC_IF_ERROR_RETURN 4134 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0xCA12, wrdata)); 4135 4136 soc_timeout_init(&to, WR_TIMEOUT, 0); 4137 do { 4138 SOC_IF_ERROR_RETURN 4139 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9005, &tmp_data)); 4140 if (tmp_data & 0x4) 4141 break; 4142 } while (!soc_timeout_check(&to)); 4143 if (!(tmp_data & 0x4)) { 4144 LOG_ERROR(BSL_LS_SOC_PHY, 4145 (BSL_META_U(unit, 4146 "write_message failed: wrdata %04x\n"), wrdata)); 4147 return SOC_E_FAIL; 4148 } 4149 4150 SOC_IF_ERROR_RETURN 4151 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xCA13, &tmp_data)); 4152 *rddata = tmp_data; 4153 SOC_IF_ERROR_RETURN 4154 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x9003, &tmp_data)); 4155 4156 return SOC_E_NONE; 4157 } 4158 4159 STATIC int 4160 _phy_8727_bsc_rw(int unit, soc_port_t port, int dev_addr, int opr, 4161 int addr, int count, void *data_array,uint32 ram_start) 4162 { 4163 phy_ctrl_t *pc; 4164 soc_timeout_t to; 4165 uint16 data16; 4166 int i; 4167 sal_usecs_t start; 4168 sal_usecs_t end; 4169 int access_type; 4170 int data_type; 4171 4172 LOG_INFO(BSL_LS_SOC_PHY, 4173 (BSL_META_U(unit, 4174 "phy_8727_bsc_read: u=%d p=%d addr=%04x\n"), 4175 unit, port, addr)); 4176 4177 if (!data_array) { 4178 return SOC_E_PARAM; 4179 } 4180 4181 if (count > PHY_8727_BSC_XFER_MAX) { 4182 return SOC_E_PARAM; 4183 } 4184 4185 pc = EXT_PHY_SW_STATE(unit, port); 4186 data_type = PHY_8727_I2C_DATA_TYPE(opr); 4187 access_type = PHY_8727_I2C_ACCESS_TYPE(opr); 4188 4189 if (access_type == PHY_8727_I2CDEV_WRITE) { 4190 for (i = 0; i < count; i++) { 4191 if (data_type == PHY_8727_I2C_8BIT) { 4192 SOC_IF_ERROR_RETURN 4193 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, ram_start + i, 4194 ((uint8 *)data_array)[i])); 4195 } else { /* 16 bit */ 4196 SOC_IF_ERROR_RETURN 4197 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, ram_start + i, 4198 ((uint16 *)data_array)[i])); 4199 } 4200 } 4201 } 4202 4203 SOC_IF_ERROR_RETURN 4204 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x8000, 0x8000)); 4205 data16 = ram_start; 4206 SOC_IF_ERROR_RETURN 4207 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x8004, data16)); 4208 SOC_IF_ERROR_RETURN 4209 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x8003, addr)); 4210 SOC_IF_ERROR_RETURN 4211 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x8002, count)); 4212 4213 data16 = 1; 4214 data16 |= (dev_addr<<9); 4215 if (access_type == PHY_8727_I2CDEV_WRITE) { 4216 data16 |= PHY_8727_WR_FREQ_400KHZ; 4217 } 4218 4219 SOC_IF_ERROR_RETURN 4220 (WRITE_PHY8706_PMA_PMD_REG(unit,pc,0x8005,data16)); 4221 4222 if (access_type == PHY_8727_I2CDEV_WRITE) { 4223 data16 = 0x8000 | PHY_8727_BSC_WRITE_OP; 4224 } else { 4225 data16 = 0x8000 | PHY_8727_BSC_READ_OP; 4226 } 4227 4228 if (data_type == PHY_8727_I2C_16BIT) { 4229 data16 |= (1 << 12); 4230 } 4231 4232 SOC_IF_ERROR_RETURN 4233 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, 0x8000, data16)); 4234 4235 start = sal_time_usecs(); 4236 soc_timeout_init(&to, 1000000, 0); 4237 while (!soc_timeout_check(&to)) { 4238 SOC_IF_ERROR_RETURN 4239 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x8000, &data16)); 4240 if (((data16 & PHY_8727_2W_STAT) == PHY_8727_2W_STAT_COMPLETE)) { 4241 break; 4242 } 4243 } 4244 end = sal_time_usecs(); 4245 4246 /* need some delays */ 4247 sal_usleep(10000); 4248 4249 LOG_INFO(BSL_LS_SOC_PHY, 4250 (BSL_META_U(unit, 4251 "BSC command status %d time=%d\n"), 4252 (data16 & PHY_8727_2W_STAT), SAL_USECS_SUB(end, start))); 4253 4254 if (access_type == PHY_8727_I2CDEV_WRITE) { 4255 return SOC_E_NONE; 4256 } 4257 4258 if ((data16 & PHY_8727_2W_STAT) == PHY_8727_2W_STAT_COMPLETE) { 4259 for (i = 0; i < count; i++) { 4260 SOC_IF_ERROR_RETURN 4261 (READ_PHY8706_PMA_PMD_REG(unit, pc, (ram_start+i), &data16)); 4262 if (data_type == PHY_8727_I2C_16BIT) { 4263 ((uint16 *)data_array)[i] = data16; 4264 LOG_INFO(BSL_LS_SOC_PHY, 4265 (BSL_META_U(unit, 4266 "%04x "), data16)); 4267 } else { 4268 ((uint8 *)data_array)[i] = (uint8)data16; 4269 LOG_INFO(BSL_LS_SOC_PHY, 4270 (BSL_META_U(unit, 4271 "%02x "), data16)); 4272 } 4273 } 4274 } 4275 return SOC_E_NONE; 4276 } 4277 4278 /* 4279 * Read a slave device such as NVRAM/EEPROM connected to the 8727's I2C 4280 * interface. This function will be mainly used for diagnostic or workaround 4281 * purpose. 4282 * Note: 4283 * The size of read_array buffer must be greater than or equal to the 4284 * parameter nbytes. 4285 * usage example: 4286 * Retrieve the first 100 byte data of the non-volatile storage device with 4287 * I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0, 4288 * port 2. 4289 * uint8 data8[100]; 4290 * phy_8727_i2cdev_read(0,2,0x50,0,100,data8); 4291 */ 4292 int 4293 phy_8727_i2cdev_read(int unit, 4294 soc_port_t port, 4295 int dev_addr, /* 7 bit I2C bus device address */ 4296 int offset, /* starting data address to read */ 4297 int nbytes, /* number of bytes to read */ 4298 uint8 *read_array) /* buffer to hold retrieved data */ 4299 { 4300 return _phy_8727_bsc_rw(unit, port, dev_addr,PHY_8727_I2CDEV_READ, 4301 offset, nbytes, (void *)read_array,PHY_8727_READ_START_ADDR); 4302 4303 } 4304 4305 /* 4306 * Write to a slave device such as NVRAM/EEPROM connected to the 8727's I2C 4307 * interface. This function will be mainly used for diagnostic or workaround 4308 * purpose. 4309 * Note: 4310 * The size of write_array buffer should be equal to the parameter nbytes. 4311 * The EEPROM may limit the maximun write size to 16 bytes 4312 * usage example: 4313 * Write to first 100 byte space of the non-volatile storage device with 4314 * I2C bus device address 0x50(default SPF eeprom I2C address) on unit 0, 4315 * port 2, with written data specified in array data8. 4316 * uint8 data8[100]; 4317 * *** initialize the data8 array with written data *** 4318 * 4319 * phy_8727_i2cdev_write(0,2,0x50,0,100,data8); 4320 */ 4321 4322 int 4323 phy_8727_i2cdev_write(int unit, 4324 soc_port_t port, 4325 int dev_addr, /* I2C bus device address */ 4326 int offset, /* starting data address to write to */ 4327 int nbytes, /* number of bytes to write */ 4328 uint8 *write_array) /* buffer to hold written data */ 4329 { 4330 int j; 4331 int rv = SOC_E_NONE; 4332 4333 for (j = 0; j < (nbytes/PHY_8727_BSC_WR_MAX); j++) { 4334 rv = _phy_8727_bsc_rw(unit, port, dev_addr,PHY_8727_I2CDEV_WRITE, 4335 offset + j * PHY_8727_BSC_WR_MAX, PHY_8727_BSC_WR_MAX, 4336 (void *)(write_array + j * PHY_8727_BSC_WR_MAX), 4337 PHY_8727_WRITE_START_ADDR); 4338 if (rv != SOC_E_NONE) { 4339 return rv; 4340 } 4341 sal_usleep(20000); 4342 } 4343 if (nbytes%PHY_8727_BSC_WR_MAX) { 4344 rv = _phy_8727_bsc_rw(unit, port, dev_addr,PHY_8727_I2CDEV_WRITE, 4345 offset + j * PHY_8727_BSC_WR_MAX, nbytes%PHY_8727_BSC_WR_MAX, 4346 (void *)(write_array + j * PHY_8727_BSC_WR_MAX), 4347 PHY_8727_WRITE_START_ADDR); 4348 } 4349 return rv; 4350 } 4351 4352 /* 4353 * Function: 4354 * phy_8706_reg_read 4355 * Purpose: 4356 * Routine to read PHY register 4357 * Parameters: 4358 * uint - BCM unit number 4359 * port - port number 4360 * flags - Flags which specify the register type 4361 * phy_reg_addr - Encoded register address 4362 * phy_data - (OUT) Value read from PHY register 4363 * Note: 4364 * This register read function is not thread safe. Higher level 4365 * function that calls this function must obtain a per port lock 4366 * to avoid overriding register page mapping between threads. 4367 */ 4368 STATIC int 4369 phy_8706_reg_read(int unit, soc_port_t port, uint32 flags, 4370 uint32 phy_reg_addr, uint32 *phy_data) 4371 { 4372 uint16 data16; 4373 uint16 regdata; 4374 phy_ctrl_t *pc; /* PHY software state */ 4375 int rv = SOC_E_NONE; 4376 int rd_cnt; 4377 uint16 phyid1; 4378 uint16 rev_num; 4379 4380 pc = EXT_PHY_SW_STATE(unit, port); 4381 SOC_IF_ERROR_RETURN 4382 (READ_PHY8706_PMA_PMD_REG(unit, pc, MII_PHY_ID1_REG, &phyid1)); 4383 4384 if (flags & (SOC_PHY_I2C_DATA8 | SOC_PHY_I2C_DATA16)) { 4385 if (!IS_8727_TYPE(phyid1)) { 4386 return SOC_E_UNAVAIL; 4387 } 4388 } 4389 4390 /* 8727 errata indicates 1 byte read is not working for B version. 4391 * The workaround is to read two bytes and return back one byte. 4392 */ 4393 SOC_IF_ERROR_RETURN 4394 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xc801, &rev_num)); 4395 4396 rd_cnt = ((rev_num & 0xF) < PHY_8727_VERSION_C)? 2: 1; 4397 4398 if (flags & SOC_PHY_I2C_DATA8) { 4399 4400 /* read two bytes and return the first byte */ 4401 SOC_IF_ERROR_RETURN 4402 (phy_8727_i2cdev_read(unit, port, 4403 SOC_PHY_I2C_DEVAD(phy_reg_addr), 4404 SOC_PHY_I2C_REGAD(phy_reg_addr), 4405 rd_cnt, 4406 (uint8 *)&data16)); 4407 *phy_data = *((uint8 *)&data16); 4408 4409 } else if (flags & SOC_PHY_I2C_DATA16) { 4410 /* This operation is generally targeted to access 16-bit device, 4411 * such as PHY IC inside the SFP. However there is no 16-bit 4412 * scratch register space on the device. Use 1.800e 4413 * for this operation. 4414 */ 4415 SOC_IF_ERROR_RETURN 4416 (READ_PHY8706_PMA_PMD_REG(unit, pc, PHY_8727_I2C_TEMP_RAM, 4417 ®data)); 4418 4419 rv = _phy_8727_bsc_rw(unit, port, 4420 SOC_PHY_I2C_DEVAD(phy_reg_addr), 4421 PHY_8727_I2C_OP_TYPE(PHY_8727_I2CDEV_READ,PHY_8727_I2C_16BIT), 4422 SOC_PHY_I2C_REGAD(phy_reg_addr),1, 4423 (void *)&data16,PHY_8727_I2C_TEMP_RAM); 4424 4425 *phy_data = data16; 4426 4427 /* restore the ram register value */ 4428 SOC_IF_ERROR_RETURN 4429 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, PHY_8727_I2C_TEMP_RAM, 4430 regdata)); 4431 } else { 4432 SOC_IF_ERROR_RETURN 4433 (READ_PHY_REG(unit, pc, phy_reg_addr, &data16)); 4434 *phy_data = data16; 4435 } 4436 4437 return rv; 4438 } 4439 4440 /* 4441 * Function: 4442 * phy_8706_reg_write 4443 * Purpose: 4444 * Routine to write PHY register 4445 * Parameters: 4446 * uint - BCM unit number 4447 * port - port number 4448 * flags - Flags which specify the register type 4449 * phy_reg_addr - Encoded register address 4450 * phy_data - Value write to PHY register 4451 * Note: 4452 * This register read function is not thread safe. Higher level 4453 * function that calls this function must obtain a per port lock 4454 * to avoid overriding register page mapping between threads. 4455 */ 4456 STATIC int 4457 phy_8706_reg_write(int unit, soc_port_t port, uint32 flags, 4458 uint32 phy_reg_addr, uint32 phy_data) 4459 { 4460 uint8 data8[4]; 4461 uint16 data16[2]; 4462 uint16 regdata[2]; 4463 phy_ctrl_t *pc; /* PHY software state */ 4464 int rv = SOC_E_NONE; 4465 uint16 phyid1; 4466 uint16 rev_num; 4467 int wr_cnt; 4468 4469 pc = EXT_PHY_SW_STATE(unit, port); 4470 4471 /* This feature is only supported on 8727 for now*/ 4472 SOC_IF_ERROR_RETURN 4473 (READ_PHY8706_PMA_PMD_REG(unit, pc, MII_PHY_ID1_REG, &phyid1)); 4474 4475 if (flags & (SOC_PHY_I2C_DATA8 | SOC_PHY_I2C_DATA16)) { 4476 if (!IS_8727_TYPE(phyid1)) { 4477 return SOC_E_UNAVAIL; 4478 } 4479 } 4480 4481 /* check which revision to implement rev. specific workaround */ 4482 /* 8727 errata indicates 1 byte/word write is not working for B version. 4483 * The workaround is to send two bytes/words write command and actually 4484 * only one gets written. 4485 */ 4486 SOC_IF_ERROR_RETURN 4487 (READ_PHY8706_PMA_PMD_REG(unit, pc, 0xc801, &rev_num)); 4488 4489 wr_cnt = ((rev_num & 0xF) < PHY_8727_VERSION_C)? 2: 1; 4490 4491 if (flags & SOC_PHY_I2C_DATA8) { 4492 data8[0] = (uint8)phy_data; 4493 SOC_IF_ERROR_RETURN 4494 (phy_8727_i2cdev_write(unit, port, 4495 SOC_PHY_I2C_DEVAD(phy_reg_addr), 4496 SOC_PHY_I2C_REGAD(phy_reg_addr), 4497 wr_cnt, 4498 data8)); 4499 } else if (flags & SOC_PHY_I2C_DATA16) { 4500 /* This operation is generally targeted to access 16-bit device, 4501 * such as PHY IC inside the SFP. However there is no 16-bit 4502 * scratch register space on the device. Use 1.800e 4503 * for this operation. 4504 */ 4505 /* save the temp ram register */ 4506 SOC_IF_ERROR_RETURN 4507 (READ_PHY8706_PMA_PMD_REG(unit, pc, PHY_8727_I2C_TEMP_RAM, 4508 ®data[0])); 4509 data16[0] = phy_data; 4510 rv = _phy_8727_bsc_rw(unit, port, 4511 SOC_PHY_I2C_DEVAD(phy_reg_addr), 4512 PHY_8727_I2C_OP_TYPE(PHY_8727_I2CDEV_WRITE,PHY_8727_I2C_16BIT), 4513 SOC_PHY_I2C_REGAD(phy_reg_addr),wr_cnt, 4514 (void *)data16,PHY_8727_I2C_TEMP_RAM); 4515 4516 /* restore the ram register value */ 4517 SOC_IF_ERROR_RETURN 4518 (WRITE_PHY8706_PMA_PMD_REG(unit, pc, PHY_8727_I2C_TEMP_RAM, 4519 regdata[0])); 4520 } else { 4521 SOC_IF_ERROR_RETURN 4522 (WRITE_PHY_REG(unit, pc, phy_reg_addr, (uint16)phy_data)); 4523 } 4524 4525 return rv; 4526 } 4527 4528 /* 4529 * Function: 4530 * phy_8706_probe 4531 * Purpose: 4532 * Complement the generic phy probe routine to identify this phy when its 4533 * phy id0 and id1 is same as some other phy's. 4534 * Parameters: 4535 * unit - StrataSwitch unit #. 4536 * pc - phy ctrl descriptor. 4537 * Returns: 4538 * SOC_E_NONE,SOC_E_NOT_FOUND and SOC_E_<error> 4539 */ 4540 STATIC int 4541 phy_8706_probe(int unit, phy_ctrl_t *pc) 4542 { 4543 uint16 id0, id1; 4544 soc_phy_info_t *pi; 4545 4546 if (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x2, &id0) < 0) { 4547 return SOC_E_NOT_FOUND; 4548 } 4549 if (READ_PHY8706_PMA_PMD_REG(unit, pc, 0x3, &id1) < 0) { 4550 return SOC_E_NOT_FOUND; 4551 } 4552 4553 pi = &SOC_PHY_INFO(unit, pc->port); 4554 4555 switch (PHY_MODEL(id0, id1)) { 4556 4557 case PHY_BCM8747_MODEL: 4558 if (soc_property_port_suffix_num_get(unit, pc->port, 8706, 4559 spn_PORT_PHY_MODE_REVERSE, "phy", 0 )) { 4560 pi->phy_name = "BCM5942"; 4561 PHY_FLAGS_SET(pc->unit, pc->port, PHY_FLAGS_SECONDARY_SERDES); 4562 } 4563 break; 4564 4565 default: 4566 break; 4567 4568 } 4569 pc->size = sizeof(PHY8706_DEV_DESC_t); 4570 return SOC_E_NONE; 4571 } 4572 4573 /* 4574 * Function: 4575 * phy_8706_medium_get 4576 * Purpose: 4577 * Routine to get valid medium 4578 * Parameters: 4579 * unit - StrataSwitch unit #. 4580 * port - StrataSwitch port #. 4581 * medium - (OUT) SOC_PORT_MEDIUM_FIBER 4582 * Returns: 4583 * SOC_E_XXX 4584 */ 4585 4586 STATIC int 4587 phy_8706_medium_get(int unit, soc_port_t port, soc_port_medium_t *medium) 4588 { 4589 int rv; 4590 4591 COMPILER_REFERENCE(unit); 4592 COMPILER_REFERENCE(port); 4593 if (medium != NULL) { 4594 *medium = SOC_PORT_MEDIUM_FIBER; 4595 rv = SOC_E_NONE; 4596 } else { 4597 rv = SOC_E_PARAM; 4598 } 4599 4600 return rv; 4601 } 4602 4603 /* 4604 * Variable: 4605 * phy_8706_drv 4606 * Purpose: 4607 * Phy Driver for 10G (XAUI x 4) Serdes PHY. 4608 */ 4609 4610 phy_driver_t phy_8706drv_xe = { 4611 "8706 10-Gigabit PHY Driver", 4612 phy_8706_init, /* Init */ 4613 phy_null_reset, /* Reset (dummy) */ 4614 phy_8706_link_get, /* Link get */ 4615 phy_8706_enable_set, /* Enable set */ 4616 phy_null_enable_get, /* Enable get */ 4617 phy_null_set, /* Duplex set */ 4618 phy_null_one_get, /* Duplex get */ 4619 phy_8706_speed_set, /* Speed set */ 4620 phy_8706_speed_get, /* Speed get */ 4621 phy_null_set, /* Master set */ 4622 phy_null_zero_get, /* Master get */ 4623 phy_8706_an_set, /* ANA set */ 4624 phy_8706_an_get, /* ANA get */ 4625 NULL, /* Local Advert set */ 4626 NULL, /* Local Advert get */ 4627 phy_null_mode_get, /* Remote Advert get */ 4628 phy_8706_lb_set, /* PHY loopback set */ 4629 phy_8706_lb_get, /* PHY loopback set */ 4630 phy_null_interface_set, /* IO Interface set */ 4631 phy_xehg_interface_get, /* IO Interface get */ 4632 NULL, /* PHY abilities mask */ 4633 phy_8706_linkup, 4634 NULL, 4635 phy_null_mdix_set, 4636 phy_null_mdix_get, 4637 phy_null_mdix_status_get, 4638 NULL, 4639 NULL, 4640 phy_8706_medium_get, /* phy medium */ 4641 NULL, /* phy_cable_diag */ 4642 NULL, /* phy_link_change */ 4643 phy_8706_control_set, /* phy_control_set */ 4644 phy_8706_control_get, /* phy_control_get */ 4645 phy_8706_reg_read, /* phy_reg_read */ 4646 phy_8706_reg_write, /* phy_reg_write */ 4647 NULL, /* phy_reg_modify */ 4648 NULL, /* phy_notify */ 4649 phy_8706_probe, /* pd_probe */ 4650 phy_8706_ability_advert_set, /* pd_ability_advert_set */ 4651 phy_8706_ability_advert_get, /* pd_ability_advert_get */ 4652 phy_8706_ability_remote_get, /* pd_ability_remote_get */ 4653 phy_8706_ability_local_get, /* pd_ability_local_get */ 4654 phy_8706_firmware_set /* pd_firmware_set */ 4655 }; 4656 4657 #else /* INCLUDE_PHY_8706 */ 4658 int _phy_8706_not_empty; 4659 #endif /* INCLUDE_PHY_8706 */ 4660