serdesassumed.c (27811B)
1 /* 2 * 3 * This license is set out in https://raw.githubusercontent.com/Broadcom-Network-Switching-Software/OpenBCM/master/Legal/LICENSE file. 4 * 5 * Copyright 2007-2019 Broadcom Inc. All rights reserved. 6 * 7 * File: serdes.c 8 * Purpose: 9 * Requires: 10 */ 11 12 #include <sal/types.h> 13 #include <sal/core/spl.h> 14 15 #include <soc/drv.h> 16 #include <soc/debug.h> 17 #include <soc/error.h> 18 #include <soc/phyreg.h> 19 #include <shared/bsl.h> 20 #include <soc/phy.h> 21 #include <soc/phy/phyctrl.h> 22 #include <soc/phy/drv.h> 23 24 #include "phydefs.h" /* Must include before other phy related includes */ 25 26 #if defined(_INCLUDE_SERDES_ASSUMED) 27 #include "phyconfig.h" /* Must be the first phy include after phydefs.h */ 28 #include "phyident.h" 29 #include "phynull.h" 30 #include "serdesassumed.h" 31 32 /************************************************************************ 33 * * 34 * SERDES Support * 35 */ 36 37 #define SERDES_STABLE_TIME 2 /* # seconds to stablize */ 38 39 /* 40 * Variable: 41 * serdes_state 42 * Purpose: 43 * The serdes devices flap LINKOK/SYNCOK around in the wind 44 * for a long time as links are being negotiated etc. For this 45 * reason states for the GE ports that use the SERDES driver 46 * keeps state around. Those states marked as (timed) are required 47 * to maintain their current state (or move forward) for 48 * SERDES_STABLE_TIME. State transitions are: 49 * 50 * | serReset| serDOWN | serSYNCOK | serAN | serUP 51 *------------+---------+-----------+-----------+-----------+-------- 52 * SYNCOK=0 | | | | | 53 * AN-Enable=0| serDOWN | serDOWN | serDOWN | serDOWN | serRESET 54 * AN-Cmplt=0 | (timed) | | | | 55 *------------+---------+-----------+-----------+-----------+-------- 56 * SYNCOK=1 | | | | | 57 * AN-Enable=0| serDOWN | serSYNKOK | serUP | serDOWN | serUP 58 * AN-Cmplt=0 | (timed) | (timed) | (timed) | | 59 *------------+---------+-----------+-----------+-----------+-------- 60 * SYNCOK=1 | | | | | 61 * AN-Enable=1| serDOWN | serSYNKOK | serAN | serAN |serRESET 62 * AN-Cmplt=0 | (timed) | (timed) | (timed) | | 63 *------------+---------+-----------+-----------+-----------+-------- 64 * SYNCOK=1 | | | | | 65 * AN-Enable=1| serDOWN | serSYNKOK | serUP | serUP | serUP 66 * AN-Cmplt=1 | (timed) | (timed) | (timed) | | 67 *------------+---------+-----------+----------+------------+-------- 68 */ 69 typedef struct { 70 enum { 71 serDISABLED, /* Port is disabled */ 72 serRESET, 73 serDOWN, 74 serSYNCOK, /* SYNOK detected */ 75 serAN, /* Autonegotiation in progress */ 76 serUP /* Running */ 77 } ser_state; 78 sal_time_t ser_time; /* First LINKOK time */ 79 } serdes_state_t; 80 81 STATIC serdes_state_t *serdes_state[SOC_MAX_NUM_DEVICES]; 82 83 #define SERDES_ALLOC(_u) do { \ 84 serdes_state[_u] = sal_alloc(SOC_MAX_NUM_PORTS * \ 85 sizeof(serdes_state_t), \ 86 "serdes_state"); \ 87 sal_memset(serdes_state[_u], 0, SOC_MAX_NUM_PORTS * \ 88 sizeof(serdes_state_t)); \ 89 } while (0) 90 #define SERDES_IS_ALLOC(_u) (serdes_state[_u]) 91 92 #define SERDES(_u, _p) (serdes_state[(_u)][(_p)]) 93 #define SERDES_STABLE(_u, _p) \ 94 ((sal_time() - SERDES((_u), (_p)).ser_time) >= SERDES_STABLE_TIME) 95 96 #if defined(BROADCOM_DEBUG) 97 98 STATIC char *serdes_state_desc[] = { 99 "serDISABLED", "serRESET", "serDOWN", "serSYNCOK", "serAN", "serUP"}; 100 101 #define SERDES_TRANSITION(_u, _p, _s, _r) \ 102 LOG_VERBOSE(BSL_LS_SOC_LINK, \ 103 (BSL_META_U((_u), \ 104 "Unit %d Port %s Serdes State %s --> %s (%s)\n"), \ 105 (_u), SOC_PORT_NAME(_u, _p), \ 106 serdes_state_desc[SERDES((_u), (_p)).ser_state], \ 107 serdes_state_desc[(_s)], (_r))); \ 108 SERDES((_u), (_p)).ser_state = (_s); \ 109 SERDES((_u), (_p)).ser_time = sal_time() 110 111 #define SERDES_RESET(_u, _p, _s) \ 112 LOG_VERBOSE(BSL_LS_SOC_LINK, \ 113 (BSL_META_U((_u), \ 114 "Unit %d Port %s Serdes RESET (%s)\n"), \ 115 (_u), SOC_PORT_NAME(_u, _p), (_s))); \ 116 _phy_serdesassumed_reset((_u), (_p), FALSE) 117 118 #else /* !defined(BROADCOM_DEBUG) */ 119 120 #define SERDES_TRANSITION(_u, _p, _s, _r) \ 121 SERDES((_u), (_p)).ser_state = (_s); \ 122 SERDES((_u), (_p)).ser_time = sal_time() 123 124 #define SERDES_RESET(_u, _p, _s) _phy_serdesassumed_reset((_u), (_p), FALSE) 125 126 #endif /* BROADCOM_DEBUG */ 127 128 /* 129 * Function: 130 * _phy_serdesassumed_reset 131 * Purpose: 132 * Reset SERDES state machines. 133 * Parameters: 134 * unit - StrataSwitch unit #. 135 * port - StrataSwitch port #. 136 * enable - TRUE, enable port, FALSE, disable port 137 * Returns: 138 * SOC_E_XXXX 139 * Notes: 140 * If the port is in disabled state, nothing is done. 141 */ 142 143 STATIC int 144 _phy_serdesassumed_reset(int unit, soc_port_t port, int enable) 145 { 146 uint64 gpcsc; 147 int isdisabled; 148 149 if (!SERDES_IS_ALLOC(unit)) { 150 isdisabled = 1; 151 } else { 152 isdisabled = SERDES(unit, port).ser_state == serDISABLED; 153 } 154 if (enable || !isdisabled) { 155 if (!SERDES_IS_ALLOC(unit)) { 156 SERDES_ALLOC(unit); 157 } 158 /* 159 * Attempt to make sure the other end notices that we have dropped 160 * the link. 161 */ 162 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 163 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 1); 164 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 1); 165 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 166 SERDES_TRANSITION(unit, port, serRESET, "Reset"); 167 } 168 169 return(SOC_E_NONE); 170 } 171 172 /* 173 * Function: 174 * phy_serdesassumed_enable_set 175 * Purpose: 176 * Enable or disable the physical interface. 177 * Parameters: 178 * unit - StrataSwitch unit #. 179 * port - StrataSwitch port #. 180 * enable - Boolean, true = enable PHY, false = disable. 181 * Returns: 182 * SOC_E_XXXX 183 */ 184 185 STATIC int 186 phy_serdesassumed_enable_set(int unit, soc_port_t port, int enable) 187 { 188 uint64 gpcsc; 189 190 if (enable) { 191 SOC_IF_ERROR_RETURN(_phy_serdesassumed_reset(unit, port, TRUE)); 192 } else { 193 /* 194 * Disable Disparity. 195 */ 196 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 197 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 1); 198 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 1); 199 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 200 SERDES_TRANSITION(unit, port, serDISABLED, "Disabled"); 201 } 202 203 return(SOC_E_NONE); 204 } 205 206 /* 207 * Function: 208 * phy_serdesassumed_enable_get 209 * Purpose: 210 * Enable or disable the physical interface for a SERDES device. 211 * Parameters: 212 * unit - StrataSwitch unit #. 213 * port - StrataSwitch port #. 214 * enable - (OUT) Boolean, true = enable PHY, false = disable. 215 * Returns: 216 * SOC_E_XXXX 217 */ 218 219 STATIC int 220 phy_serdesassumed_enable_get(int unit, soc_port_t port, int *enable) 221 { 222 if (SERDES_IS_ALLOC(unit)) { 223 *enable = (SERDES(unit, port).ser_state != serDISABLED); 224 } else { 225 *enable = 0; 226 } 227 return(SOC_E_NONE); 228 } 229 230 /* 231 * Function: 232 * _phy_serdesassumed_link 233 * Purpose: 234 * Determine the current link up/down status for a SERDES device, 235 * using the timeds state machine. 236 * Parameters: 237 * unit - StrataSwitch unit #. 238 * port - StrataSwitch port #. 239 * p_link - (OUT) Boolean, true indicates link established (may be NULL). 240 * p_an - (OUT) Boolean, true indicates AN is enabled (may be NULL). 241 * p_an_done - (OUT) Boolean, true indicates AN is complete (undefined 242 * if p_an is false, may be NULL). 243 * Returns: 244 * SOC_E_XXXX 245 */ 246 247 STATIC int 248 _phy_serdesassumed_link(int unit, soc_port_t port, 249 int *p_link, int *p_an, int *p_an_done) 250 { 251 uint64 anstt, anctl; 252 int sync_ok, an_enabled, an_done; 253 254 SOC_IF_ERROR_RETURN(READ_ANSTTr(unit, port, &anstt)); 255 SOC_IF_ERROR_RETURN(READ_ANCTLr(unit, port, &anctl)); 256 257 sync_ok = soc_reg64_field32_get(unit, ANSTTr, anstt, SYNCOKf); 258 an_done = soc_reg64_field32_get(unit, ANSTTr, anstt, ANCPLTf); 259 an_enabled = soc_reg64_field32_get(unit, ANCTLr, anctl, ANENf); 260 261 switch(SERDES(unit, port).ser_state) { 262 case serDISABLED: 263 break; 264 case serRESET: 265 if (SERDES_STABLE(unit, port)) { 266 uint64 gpcsc; 267 268 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 269 SERDES_TRANSITION(unit, port, serDOWN, "Reset Complete"); 270 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 0); 271 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 0); 272 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 273 } else { 274 break; 275 } 276 /* *** NOBREAK *** */ 277 case serDOWN: 278 if (!sync_ok) { 279 break; 280 } 281 SERDES_TRANSITION(unit, port, serSYNCOK, "Sync OK detected"); 282 /* *** NOBREAK *** */ 283 case serSYNCOK: 284 if (!sync_ok) { 285 SERDES_TRANSITION(unit, port, serDOWN, "SYNCOK lost"); 286 break; 287 } 288 289 if (SERDES_STABLE(unit, port)) { 290 if (!an_enabled) { 291 SERDES_TRANSITION(unit, port, serUP, "SYNCOK stable, no AN"); 292 } else { 293 SERDES_TRANSITION(unit, port, serAN, "SYNCOK stable, AN"); 294 } 295 } 296 break; 297 case serAN: 298 if (!an_enabled) { 299 SERDES_TRANSITION(unit, port, serDOWN, "AN disabled"); 300 } else if (!sync_ok) { 301 SERDES_TRANSITION(unit, port, serDOWN, "SYNCOK lost"); 302 } else if (an_done) { 303 uint64 anlpa; 304 305 SOC_IF_ERROR_RETURN(READ_ANLPAr(unit, port, &anlpa)); 306 307 if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPANERRf) != 0) { 308 uint64 anctl; 309 310 COMPILER_64_ZERO(anctl); 311 312 soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, 1); 313 soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 1); 314 315 SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl)); 316 317 soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0); 318 SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl)); 319 SERDES_TRANSITION(unit, port, serAN, "Remote Fault"); 320 } else { 321 SERDES_TRANSITION(unit, port, serUP, "AN Complete"); 322 } 323 } 324 break; 325 case serUP: 326 if (!sync_ok) { 327 SERDES_RESET(unit, port, "SYNCOK lost"); 328 } else if (an_enabled && !an_done) { 329 SERDES_RESET(unit, port, "AN-DONE lost"); 330 } 331 break; 332 default: 333 assert(0); 334 } 335 336 if (p_link) *p_link = SERDES(unit, port).ser_state == serUP; 337 if (p_an_done) *p_an_done = SERDES(unit, port).ser_state == serUP; 338 if (p_an) *p_an = an_enabled; 339 340 return(SOC_E_NONE); 341 } 342 343 #undef SERDES /* Used in above routine ONLY */ 344 #undef SERDES_ALLOC /* Used in above routine ONLY */ 345 #undef SERDES_IS_ALLOC /* Used in above routine ONLY */ 346 #undef SERDES_STABLE /* Used in above routine ONLY */ 347 #undef SERDES_TRANSITION /* Used in above routnes ONLY */ 348 #undef SERDES_RESET /* Used in above routnes ONLY */ 349 350 /* 351 * Function: 352 * phy_serdesassumed_init 353 * Purpose: 354 * Initialize the SERDES to a known good state. 355 * Parameters: 356 * unit - StrataSwitch unit #. 357 * port - StrataSwitch port #. 358 * Returns: 359 * SOC_E_XXXX 360 * Notes: 361 * No synchronization performed at this level. 362 */ 363 364 STATIC int 365 phy_serdesassumed_init(int unit, soc_port_t port) 366 { 367 soc_phy_info_t *pi = &SOC_PHY_INFO(unit, port); 368 uint64 gpcsc, anctl, annpg, anstt; 369 370 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 371 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf, 0); /* AN off */ 372 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DRRDf, 0); 373 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, DTRDf, 0); 374 375 if (!(pi->phy_flags & PHY_FLAGS_5421S)) { 376 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, EWRAPf, 0); /* loopback */ 377 } 378 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, JTRPSf, 4); 379 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, JTRPTf, 0); 380 /* RCSELf set in mac.c */ 381 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, SCLTf, 0); 382 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 383 384 COMPILER_64_ZERO(anctl); 385 soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, 0); 386 soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0); 387 SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl)); 388 389 COMPILER_64_ZERO(anstt); 390 soc_reg64_field32_set(unit, ANSTTr, &anstt, SYNCOKf, 0); 391 soc_reg64_field32_set(unit, ANSTTr, &anstt, LINKOKf, 0); 392 soc_reg64_field32_set(unit, ANSTTr, &anstt, PGRXf, 0); 393 soc_reg64_field32_set(unit, ANSTTr, &anstt, ANCPLTf, 0); 394 soc_reg64_field32_set(unit, ANSTTr, &anstt, RFINDf, 0); 395 SOC_IF_ERROR_RETURN(WRITE_ANSTTr(unit, port, anstt)); 396 397 COMPILER_64_ZERO(annpg); 398 soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 1); /* Default advert FD */ 399 SOC_IF_ERROR_RETURN(WRITE_ANNPGr(unit, port, annpg)); 400 401 _phy_serdesassumed_reset(unit, port, TRUE); 402 403 return(SOC_E_NONE); 404 } 405 406 /* 407 * Function: 408 * phy_serdesassumed_link_get 409 * Purpose: 410 * Determine the current link up/down status for a SERDES device. 411 * Parameters: 412 * unit - StrataSwitch unit #. 413 * port - StrataSwitch port #. 414 * link - (OUT) Boolean, true indicates link established. 415 * Returns: 416 * SOC_E_XXXX 417 * Notes: 418 * No synchronization performed at this level. This routine will 419 * POLL the LINKOK/SYNCOK status if the link was not previously 420 * detected as being up, but now appears so. 421 */ 422 423 STATIC int 424 phy_serdesassumed_link_get(int unit, soc_port_t port, int *link) 425 { 426 return(_phy_serdesassumed_link(unit, port, link, NULL, NULL)); 427 } 428 429 /* 430 * Function: 431 * phy_serdesassumed_duplex_set 432 * Purpose: 433 * Set the current duplex mode (forced). 434 * Parameters: 435 * unit - StrataSwitch unit #. 436 * port - StrataSwitch port #. 437 * duplex -Boolean, true indicates full duplex, false indicates half. 438 * Returns: 439 * SOC_E_NONE 440 * SOC_E_UNAVAIL - Half duplex requested, and not supported. 441 * Notes: 442 * No synchronization performed at this level. Autonegotiation is 443 * not manipulated. 444 */ 445 446 STATIC int 447 phy_serdesassumed_duplex_set(int unit, soc_port_t port, int duplex) 448 { 449 if (duplex) { 450 return (_phy_serdesassumed_reset(unit, port, FALSE)); 451 } else { 452 return (SOC_E_UNAVAIL); 453 } 454 } 455 456 /* 457 * Function: 458 * phy_serdesassumed_duplex_get 459 * Purpose: 460 * Get the current operating duplex mode. If autoneg is enabled, 461 * then operating mode is returned, otherwise forced mode is returned. 462 * Parameters: 463 * unit - StrataSwitch unit #. 464 * port - StrataSwitch port #. 465 * duplex - (OUT) Boolean, true indicates full duplex, false 466 * indicates half. 467 * Returns: 468 * SOC_E_NONE 469 * Notes: 470 * No synchronization performed at this level. Autonegotiation is 471 * not manipulated. 472 */ 473 474 STATIC int 475 phy_serdesassumed_duplex_get(int unit, soc_port_t port, int *duplex) 476 { 477 COMPILER_REFERENCE(unit); 478 COMPILER_REFERENCE(port); 479 480 *duplex = TRUE; 481 482 return(SOC_E_NONE); 483 } 484 485 486 /* 487 * Function: 488 * phy_serdesassumed_speed_set 489 * Purpose: 490 * Set the current operating speed (forced). 491 * Parameters: 492 * unit - StrataSwitch unit #. 493 * port - StrataSwitch port #. 494 * speed - Requested speed, only 1000 supported. 495 * Returns: 496 * SOC_E_XXXX 497 */ 498 499 STATIC int 500 phy_serdesassumed_speed_set(int unit, soc_port_t port, int speed) 501 { 502 if (speed == 0 || speed == 1000) { 503 return (_phy_serdesassumed_reset(unit, port, FALSE)); 504 } else { 505 return (SOC_E_CONFIG); 506 } 507 } 508 509 /* 510 * Function: 511 * phy_serdesassumed_speed_get 512 * Purpose: 513 * Get the current operating speed for a SERDES device. 514 * Parameters: 515 * unit - StrataSwitch unit #. 516 * port - StrataSwitch port #. 517 * duplex - (OUT) Boolean, true indicates full duplex, false 518 * indicates half. 519 * Returns: 520 * SOC_E_NONE 521 */ 522 523 STATIC int 524 phy_serdesassumed_speed_get(int unit, soc_port_t port, int *speed) 525 { 526 COMPILER_REFERENCE(unit); 527 COMPILER_REFERENCE(port); 528 529 *speed = 1000; 530 531 return(SOC_E_NONE); 532 } 533 534 /* 535 * Function: 536 * phy_serdesassumed_master_set 537 * Purpose: 538 * Set the current master mode 539 * Parameters: 540 * unit - StrataSwitch unit #. 541 * port - StrataSwitch port #. 542 * master - SOC_PORT_MS_* 543 * Returns: 544 * SOC_E_XXXX 545 */ 546 547 STATIC int 548 phy_serdesassumed_master_set(int unit, soc_port_t port, int master) 549 { 550 COMPILER_REFERENCE(unit); 551 COMPILER_REFERENCE(port); 552 COMPILER_REFERENCE(master); 553 554 return(SOC_E_NONE); 555 } 556 557 /* 558 * Function: 559 * phy_serdesassumed_master_get 560 * Purpose: 561 * Get the current master mode for a SERDES device. 562 * Parameters: 563 * unit - StrataSwitch unit #. 564 * port - StrataSwitch port #. 565 * master - (OUT) SOC_PORT_MS_* 566 * Returns: 567 * SOC_E_NONE 568 */ 569 570 STATIC int 571 phy_serdesassumed_master_get(int unit, soc_port_t port, int *master) 572 { 573 COMPILER_REFERENCE(unit); 574 COMPILER_REFERENCE(port); 575 576 *master = SOC_PORT_MS_NONE; 577 578 return(SOC_E_NONE); 579 } 580 581 /* 582 * Function: 583 * phy_serdesassumed_an_set 584 * Purpose: 585 * Enable or disabled auto-negotiation on the specified port for a 586 * SERDES device. 587 * Parameters: 588 * unit - StrataSwitch unit #. 589 * port - StrataSwitch port #. 590 * an - Boolean, if true, auto-negotiation is enabled 591 * (and/or restarted). If false, autonegotiation is disabled. 592 * Returns: 593 * SOC_E_XXXX - success 594 */ 595 596 STATIC int 597 phy_serdesassumed_an_set(int unit, soc_port_t port, int an) 598 { 599 uint64 anctl, gpcsc; 600 int autos; 601 602 autos = soc_property_port_get(unit, port, spn_PHY_SERDES_AUTOS, 0); 603 604 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, port, &gpcsc)); 605 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf, 606 (an && autos) ? 1 : 0); 607 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, port, gpcsc)); 608 609 COMPILER_64_ZERO(anctl); 610 soc_reg64_field32_set(unit, ANCTLr, &anctl, ANENf, an ? 1 : 0); 611 soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, an ? 1 : 0); 612 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, AUTOSf, 0); 613 614 SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl)); 615 616 soc_reg64_field32_set(unit, ANCTLr, &anctl, RSTANf, 0); 617 SOC_IF_ERROR_RETURN(WRITE_ANCTLr(unit, port, anctl)); 618 619 return(_phy_serdesassumed_reset(unit, port, FALSE)); 620 } 621 622 /* 623 * Function: 624 * phy_serdesassumed_an_get 625 * Purpose: 626 * Get the current auto-negotiation status (enabled/busy) 627 * Parameters: 628 * unit - StrataSwitch unit #. 629 * port - StrataSwitch port #. 630 * an - (OUT) if true, auto-negotiation is enabled. 631 * an_done - (OUT) if true, auto-negotioation is complete. This 632 * value is undefined if an == FALSE. 633 * Returns: 634 * SOC_E_XXXX 635 * Notes: 636 * This routine basis it's decision on the serdes S/W state, and not the 637 * Hardware bit. This allows proper 638 */ 639 640 STATIC int 641 phy_serdesassumed_an_get(int unit, soc_port_t port, int *an, int *an_done) 642 { 643 return(_phy_serdesassumed_link(unit, port, NULL, an, an_done)); 644 } 645 646 /* 647 * Function: 648 * phy_serdesassumed_adv_local_set 649 * Purpose: 650 * Set the current advertisement for auto-negotiation. 651 * Parameters: 652 * unit - StrataSwitch unit #. 653 * port - StrataSwitch port #. 654 * mode - Port mode mask indicating supported options/speeds. 655 * Returns: 656 * SOC_E_XXXX 657 * Notes: 658 * No synchronization performed at this level. The only options 659 * that are supported are pause and FD/HD. Although this routine 660 * supports FD/HD, in reality, the MAC only supports FULL so we 661 * should never really see it. 662 */ 663 664 STATIC int 665 phy_serdesassumed_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode) 666 { 667 uint64 annpg, gmacc0; 668 669 mode &= SOC_PM_1000MB_FD | SOC_PM_PAUSE; 670 COMPILER_64_ZERO(annpg); 671 672 if (mode & SOC_PM_1000MB_FD) { 673 soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 1); 674 } else if (mode & SOC_PM_1000MB_HD) { 675 soc_reg64_field32_set(unit, ANNPGr, &annpg, FDf, 0); 676 } else { 677 return(SOC_E_UNAVAIL); 678 } 679 680 switch (mode & SOC_PM_PAUSE) { 681 case SOC_PM_PAUSE_TX: 682 soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0); 683 soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 1); 684 break; 685 case SOC_PM_PAUSE_RX: 686 soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0); 687 soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 1); 688 break; 689 case SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX: 690 soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 1); 691 soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 0); 692 break; 693 default: /* No flow control */ 694 soc_reg64_field32_set(unit, ANNPGr, &annpg, PAUSEf, 0); 695 soc_reg64_field32_set(unit, ANNPGr, &annpg, ASMDRf, 0); 696 break; 697 } 698 699 SOC_IF_ERROR_RETURN(READ_GMACC0r(unit, port, &gmacc0)); /* into reset */ 700 soc_reg64_field32_set(unit, GMACC0r, &gmacc0, SRSTf, 1); 701 SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0)); 702 703 SOC_IF_ERROR_RETURN(WRITE_ANNPGr(unit, port, annpg)); 704 705 soc_reg64_field32_set(unit, GMACC0r, &gmacc0, SRSTf, 0); 706 SOC_IF_ERROR_RETURN(WRITE_GMACC0r(unit, port, gmacc0)); /* out of reset */ 707 708 return(SOC_E_NONE); 709 } 710 711 /* 712 * Function: 713 * phy_serdesassumed_adv_local_get 714 * Purpose: 715 * Get the current advertisement for auto-negotiation. 716 * Parameters: 717 * unit - StrataSwitch unit #. 718 * port - StrataSwitch port #. 719 * mode - (OUT) Port mode mask indicating supported options/speeds. 720 * Returns: 721 * SOC_E_XXXX 722 * Notes: 723 * No synchronization performed at this level. 724 */ 725 726 STATIC int 727 phy_serdesassumed_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode) 728 { 729 uint64 annpg; 730 731 *mode = 0; 732 733 SOC_IF_ERROR_RETURN(READ_ANNPGr(unit, port, &annpg)); 734 735 if (soc_reg64_field32_get(unit, ANNPGr, annpg, FDf)) { 736 *mode = SOC_PM_1000MB_FD; 737 } else { 738 *mode = SOC_PM_1000MB_HD; 739 } 740 741 /* PAUSE */ 742 743 if (soc_reg64_field32_get(unit, ANNPGr, annpg, ASMDRf)) { 744 if (soc_reg64_field32_get(unit, ANNPGr, annpg, PAUSEf)) { 745 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 746 } else { 747 *mode |= SOC_PM_PAUSE_TX; 748 } 749 } else { 750 if (soc_reg64_field32_get(unit, ANNPGr, annpg, PAUSEf)) { 751 *mode |= SOC_PM_PAUSE_TX | SOC_PM_PAUSE_RX; 752 } 753 } 754 return(SOC_E_NONE); 755 } 756 757 /* 758 * Function: 759 * phy_serdesassumed_adv_remote_get 760 * Purpose: 761 * Get partners current advertisement for auto-negotiation. 762 * Parameters: 763 * unit - StrataSwitch unit #. 764 * port - StrataSwitch port #. 765 * mode - (OUT) Port mode mask indicating supported options/speeds. 766 * Returns: 767 * SOC_E_XXXX 768 * Notes: 769 * No synchronization performed at this level. If Autonegotiation is 770 * disabled or in progress, this routine will return an error. 771 */ 772 773 STATIC int 774 phy_serdesassumed_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode) 775 { 776 uint64 anlpa; 777 int link, an, an_done; 778 779 *mode = 0; 780 781 SOC_IF_ERROR_RETURN(_phy_serdesassumed_link(unit, port, &link, &an, &an_done)); 782 783 if (!an) { 784 return(SOC_E_DISABLED); 785 } else if (!an_done) { 786 return(SOC_E_BUSY); 787 } 788 789 SOC_IF_ERROR_RETURN(READ_ANLPAr(unit, port, &anlpa)); 790 791 if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPANERRf)) { 792 return(SOC_E_FAIL); 793 } 794 795 /* Remote duplex negotiation */ 796 if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPFDf)) { 797 *mode |= SOC_PM_1000MB_FD; 798 } else { 799 *mode |= SOC_PM_1000MB_HD; 800 } 801 802 /* Remote pause negotiation */ 803 804 if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPPAUSEf)) { 805 *mode |= SOC_PM_PAUSE; 806 } else { 807 if (soc_reg64_field32_get(unit, ANLPAr, anlpa, LPASMDRf)) { 808 *mode |= SOC_PM_PAUSE_TX; 809 } 810 } 811 812 return(SOC_E_NONE); 813 } 814 815 /* 816 * Function: 817 * phy_serdesassumed_lb_set 818 * Purpose: 819 * Set the local PHY loopback mode. 820 * Parameters: 821 * unit - StrataSwitch unit #. 822 * port - StrataSwitch port #. 823 * loopback - Boolean: true = enable loopback, false = disable. 824 * Returns: 825 * SOC_E_XXXX 826 * Notes: 827 * No synchronization performed at this level. 828 * 829 * Only the Even numbered EWRAP lines are visible outside 830 * the chip. Thus, the even numbered EWRAP line controls 831 * both the specified port, and the specified port + 1. 832 * 833 * Although this is a matter of how the board is physically 834 * wired, this is the only general mechanism that makes sense 835 * for all the current chips. 836 */ 837 838 STATIC int 839 phy_serdesassumed_lb_set(int unit, soc_port_t port, int enable) 840 { 841 soc_port_t gp; 842 uint64 gpcsc; 843 int poff; 844 845 /* 846 * The EWRAP line for GE0 fans out to both of the GIGs. 847 * This means they are both in loopback at the same time, 848 * and we make this routine work by setting the port to GE0 if 849 * we see GE1. 850 */ 851 852 poff = SOC_PORT_OFFSET(unit, port); /* eg: 3 if ge3 */ 853 poff &= ~1; /* now 2 if ge3 */ 854 gp = SOC_PORT(unit, ge, poff); /* get ge2 */ 855 856 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, gp, &gpcsc)); 857 soc_reg64_field32_set(unit, GPCSCr, &gpcsc, EWRAPf, enable ? 1 : 0); 858 SOC_IF_ERROR_RETURN(WRITE_GPCSCr(unit, gp, gpcsc)); 859 860 return(SOC_E_NONE); 861 } 862 863 /* 864 * Function: 865 * phy_serdesassumed_lb_get 866 * Purpose: 867 * Get the local SERDES loopback mode. 868 * Parameters: 869 * unit - StrataSwitch unit #. 870 * port - StrataSwitch port #. 871 * loopback - (OUT) Boolean: true = enable loopback, false = disable. 872 * Returns: 873 * SOC_E_XXXX 874 */ 875 876 STATIC int 877 phy_serdesassumed_lb_get(int unit, soc_port_t port, int *enable) 878 { 879 soc_port_t gp; 880 uint64 gpcsc; 881 int poff; 882 883 /* 884 * See phy_serdesassumed_lb_set() 885 */ 886 poff = SOC_PORT_OFFSET(unit, port); /* eg: 3 if ge3 */ 887 poff &= ~1; /* now 2 if ge3 */ 888 gp = SOC_PORT(unit, ge, poff); /* get ge2 */ 889 890 SOC_IF_ERROR_RETURN(READ_GPCSCr(unit, gp, &gpcsc)); 891 *enable = soc_reg64_field32_get(unit, GPCSCr, gpcsc, EWRAPf) ? TRUE : FALSE; 892 893 return(SOC_E_NONE); 894 } 895 896 /* 897 * Function: 898 * phy_serdesassumed_interface_set 899 * Purpose: 900 * Set the current operating mode of the PHY (TBI or MII/GMII) 901 * Parameters: 902 * unit - StrataSwitch unit #. 903 * port - StrataSwitch port #. 904 * pif - one of SOC_PORT_IF_* 905 * Returns: 906 * SOC_E_XXXX 907 */ 908 909 STATIC int 910 phy_serdesassumed_interface_set(int unit, soc_port_t port, soc_port_if_t pif) 911 { 912 COMPILER_REFERENCE(unit); 913 COMPILER_REFERENCE(port); 914 915 switch (pif) { 916 case SOC_PORT_IF_TBI: 917 return SOC_E_NONE; 918 default: 919 return SOC_E_UNAVAIL; 920 } 921 } 922 923 /* 924 * Function: 925 * phy_serdesassumed_interface_get 926 * Purpose: 927 * Get the current operating mode of the PHY (TBI or MII/GMII) 928 * for SERDES device. 929 * Parameters: 930 * unit - StrataSwitch unit #. 931 * port - StrataSwitch port #. 932 * pif - (OUT) Interface 933 * Returns: 934 * SOC_E_XXXX 935 */ 936 937 STATIC int 938 phy_serdesassumed_interface_get(int unit, soc_port_t port, soc_port_if_t *pif) 939 { 940 COMPILER_REFERENCE(unit); 941 COMPILER_REFERENCE(port); 942 943 *pif = SOC_PORT_IF_TBI; 944 return(SOC_E_NONE); 945 } 946 947 /* 948 * Function: 949 * phy_serdesassumed_ability_get 950 * Purpose: 951 * Get the abilities of the local gigabit phy. 952 * Parameters: 953 * unit - StrataSwitch unit #. 954 * port - StrataSwitch port #. 955 * mode - (OUT) Port mode mask indicating supported options/speeds. 956 * Returns: 957 * SOC_E_NONE 958 */ 959 960 STATIC int 961 phy_serdesassumed_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode) 962 { 963 COMPILER_REFERENCE(unit); 964 COMPILER_REFERENCE(port); 965 966 *mode = (SOC_PM_AN | SOC_PM_LB_PHY | 967 SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM | 968 SOC_PM_TBI | SOC_PM_1000MB_FD); 969 970 return(SOC_E_NONE); 971 } 972 973 /* 974 * Variable: phy_serdesassumed_ge 975 * Purpose: Phy driver callouts for SERDES interface 976 */ 977 phy_driver_t phy_serdesassumed_ge = { 978 "Assumed SERDES Driver", 979 phy_serdesassumed_init, 980 phy_null_reset, 981 phy_serdesassumed_link_get, 982 phy_serdesassumed_enable_set, 983 phy_serdesassumed_enable_get, 984 phy_serdesassumed_duplex_set, 985 phy_serdesassumed_duplex_get, 986 phy_serdesassumed_speed_set, 987 phy_serdesassumed_speed_get, 988 phy_serdesassumed_master_set, 989 phy_serdesassumed_master_get, 990 phy_serdesassumed_an_set, 991 phy_serdesassumed_an_get, 992 phy_serdesassumed_adv_local_set, 993 phy_serdesassumed_adv_local_get, 994 phy_serdesassumed_adv_remote_get, 995 phy_serdesassumed_lb_set, 996 phy_serdesassumed_lb_get, 997 phy_serdesassumed_interface_set, 998 phy_serdesassumed_interface_get, 999 phy_serdesassumed_ability_get, 1000 NULL, 1001 NULL, 1002 phy_null_mdix_set, 1003 phy_null_mdix_get, 1004 phy_null_mdix_status_get, 1005 NULL, 1006 NULL, 1007 phy_null_medium_get, 1008 NULL, /* phy_cable_diag */ 1009 NULL, /* phy_link_change */ 1010 NULL, /* phy_control_set */ 1011 NULL, /* phy_control_get */ 1012 NULL, /* phy_reg_read */ 1013 NULL, /* phy_reg_write */ 1014 NULL /* phy_reg_modify */ 1015 }; 1016 1017 #else /* INCLUDE_SERDES_ASSUMED */ 1018 int _phy_serdesassumed_not_empty; 1019 #endif /* INCLUDE_SERDES_ASSUMED */ 1020