openbcm

Git mirror of https://github.com/Broadcom-Network-Switching-Software/OpenBCM
git clone git://git.finwo.net/mirror/broadcom/openbcm
Log | Files | Refs | README

phy5482.c (75696B)


      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:        phy5482.c
      8  * Purpose:     PHY driver for BCM5482 and BCM5482S
      9  *
     10  * Supported BCM546X Family of PHY devices:
     11  *
     12  *      Device  Ports   Media                           MAC Interface
     13  *      5482    2       Copper, Serdes                  SGMII
     14  *      5482S   2       Copper, Serdes                  SGMII
     15  *
     16  * Workarounds:
     17  *
     18  * References:
     19  * MCS5482S-DS200R    BCM5482S Preliminary Data Sheet
     20  * 5482S-AN103-R      BCM5482S Configuration Guide for SFP Module with
     21  *                    Optical/Copper Applications
     22  * 5482S-ES101-R      BCM5482S Errata Sheet
     23  * 5482_5482S-AN102-R Designing with BCM5482/BCM5482S
     24  *     
     25  *    +----------+   +---------------------------+
     26  *    |          |   |  SGMII     +->Copper      |<--> Magnetic
     27  *    |  SGMII   |<->| (Primary <-+              |
     28  *    | (SerDes) |   |  SerDes)   |              |
     29  *    |          |   |            +->SGMII/      |<--> (PHY)SFP (10/100/1000)
     30  *    +----------+   |               1000BASE-X/ |<--> 1000BASE-X SFP
     31  *        MAC        |               100BASE-FX  |<--> 100BASE-FX SFP
     32  *                   |               (Secondary  |
     33  *                   |                SerDes)    |
     34  *                   +---------------------------+
     35  *                               5482S
     36  *
     37  * Notes:
     38  * 1. Media auto-negotiation and MAC SGMII auto-negotiation must be enabled 
     39  *    to automatically detect between
     40  *    SGMII SFP and 1000BASE-X SFP.
     41  * 2. Auto detecting 100FX SFP is not supported. 
     42  * 3. To use 100BASE-FX,
     43  *       First, insert the 100BASE-FX SFP and connect the fiber cable. 
     44  *       The PHY will detect energy on fiber side and switch to fiber mode.
     45  *       Second, disable autoneg mode.
     46  *       Third, force speed to 100. Since the PHY is in fiber mode, forcing
     47  *       speed to 100 will put the PHY to 100BASE-FX mode.
     48  * 4. Forcing speed on the 5482S PHY with SGMII SFP is not supported in this
     49  *    driver. To use SGMII SFP, autoneg must be enabled.
     50  * 5. Some SFP continues to provide energy to the PHY even when the media 
     51  *    connected is removed. For those SFPs, the PHY will not switch to
     52  *    copper medium in combo mode even when there is no link on the fiber 
     53  *    medium because the PHY is not switching to copper mode.  
     54  * 6. If the MAC/SerDes attached to the PHY support SGMII autoneg, SGMII
     55  *    autoneg should be enabled with "config add phy_sgmii_autoneg_ge0=1".
     56  * 7. If the SFP module report loss of signal instead of signal detect, the
     57  *    signal detect should be inverted with "config add phy_fiber_detect=-2".
     58  */                        
     59 
     60 #include <sal/types.h>
     61 #include <sal/core/spl.h>
     62 #include <shared/bsl.h>
     63 #include <soc/drv.h>
     64 #include <soc/debug.h>
     65 #include <soc/error.h>
     66 #include <soc/phyreg.h>
     67 
     68 #include <soc/phy.h>
     69 #include <soc/phy/phyctrl.h>
     70 #include <soc/phy/drv.h>
     71 
     72 #include "phydefs.h"      /* Must include before other phy related includes */
     73 
     74 #if defined(INCLUDE_PHY_5482_ESW)
     75 #include "phyconfig.h"    /* Must be the first phy include after phydefs.h */
     76 #include "phyident.h"
     77 #include "phyreg.h"
     78 #include "phyfege.h"
     79 #include "phy5482.h"
     80 
     81 #define AUTO_MDIX_WHEN_AN_DIS   0       /* Non-standard-compliant option */
     82 #define DISABLE_CLK125          0       /* Disable if unused to reduce */
     83                                         /*  EMI emissions */
     84 
     85 #define ADVERT_ALL_COPPER \
     86         (SOC_PM_PAUSE | SOC_PM_10MB | SOC_PM_100MB | SOC_PM_1000MB)
     87 #define ADVERT_ALL_FIBER \
     88         (SOC_PM_PAUSE | SOC_PM_1000MB_FD)
     89 
     90 STATIC int _phy_5482_no_reset_setup(int unit, soc_port_t port);
     91 STATIC int _phy_5482_medium_change(int unit, soc_port_t port,int force_update);
     92 STATIC int phy_5482_duplex_set(int unit, soc_port_t port, int duplex);
     93 STATIC int phy_5482_speed_set(int unit, soc_port_t port, int speed);
     94 STATIC int phy_5482_master_set(int unit, soc_port_t port, int master);
     95 STATIC int phy_5482_adv_local_set(int unit, soc_port_t port,
     96                                   soc_port_mode_t mode);
     97 STATIC int phy_5482_autoneg_set(int unit, soc_port_t port, int autoneg);
     98 STATIC int phy_5482_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode);
     99 STATIC int phy_5482_speed_get(int unit, soc_port_t port, int *speed);
    100 
    101 /***********************************************************************
    102  *
    103  * HELPER FUNCTIONS
    104  */
    105 /*
    106  * Function:
    107  *      _phy_5482_medium_check
    108  * Purpose:
    109  *      Determine if chip should operate in copper or fiber mode.
    110  * Parameters:
    111  *      unit - StrataSwitch unit #.
    112  *      port - StrataSwitch port #.
    113  *      medium - (OUT) SOC_PORT_MEDIUM_XXX
    114  * Returns:
    115  *      SOC_E_XXX
    116  */
    117 STATIC int
    118 _phy_5482_medium_check(int unit, soc_port_t port, int *medium)
    119 {
    120     phy_ctrl_t    *pc = EXT_PHY_SW_STATE(unit, port);
    121     uint16         tmp = 0xffff;
    122 
    123     *medium = SOC_PORT_MEDIUM_COPPER;
    124 
    125     if (pc->automedium) {
    126         /* Read Mode Register (0x1c shadow 11111) */
    127         SOC_IF_ERROR_RETURN
    128             (READ_PHY5482_MODE_CTRLr(unit, pc, &tmp));
    129 
    130         if (pc->fiber.preferred) {
    131             /* 0x10 Fiber Signal Detect
    132              * 0x20 Copper Energy Detect
    133              */
    134             if ((tmp & 0x30) == 0x20) {
    135                 /* Only copper is link up */
    136                 *medium = SOC_PORT_MEDIUM_COPPER;
    137             } else {
    138                 *medium = SOC_PORT_MEDIUM_FIBER;
    139             }
    140         } else {
    141             if ((tmp & 0x30) == 0x10) {
    142                 /* Only fiber is link up */
    143                 *medium = SOC_PORT_MEDIUM_FIBER;
    144             } else {
    145                 *medium = SOC_PORT_MEDIUM_COPPER;
    146             }
    147         }
    148     } else {
    149         *medium = pc->fiber.preferred ? SOC_PORT_MEDIUM_FIBER:
    150                   SOC_PORT_MEDIUM_COPPER;
    151     } 
    152 
    153     LOG_VERBOSE(BSL_LS_SOC_PHY,
    154                 (BSL_META_U(unit,
    155                             "_phy_5482_medium_check: "
    156                             "u=%d p=%d fiber_pref=%d 0x1c(11111)=%04x fiber=%d\n"),
    157                  unit, port, pc->fiber.preferred, tmp, 
    158                  (*medium == SOC_PORT_MEDIUM_FIBER) ? 1 : 0));
    159 
    160     return SOC_E_NONE;
    161 }
    162 
    163 /*
    164  * Function:
    165  *      phy_5482_medium_status
    166  * Purpose:
    167  *      Indicate the current active medium
    168  * Parameters:
    169  *      unit - StrataSwitch unit #.
    170  *      port - StrataSwitch port #.
    171  *      medium - (OUT) One of:
    172  *              SOC_PORT_MEDIUM_COPPER
    173  *              SOC_PORT_MEDIUM_FIBER
    174  * Returns:
    175  *      SOC_E_NONE
    176  */
    177 
    178 STATIC int
    179 phy_5482_medium_status(int unit, soc_port_t port, soc_port_medium_t *medium)
    180 {
    181     if (PHY_COPPER_MODE(unit, port)) {
    182         *medium = SOC_PORT_MEDIUM_COPPER;
    183     } else {
    184         *medium = SOC_PORT_MEDIUM_FIBER;
    185     }
    186     return SOC_E_NONE;
    187 }
    188 
    189 /*
    190  * Function:
    191  *      _phy_5482_medium_config_update
    192  * Purpose:
    193  *      Update the PHY with config parameters
    194  * Parameters:
    195  *      unit - StrataSwitch unit #.
    196  *      port - StrataSwitch port #.
    197  *      cfg - Config structure.
    198  * Returns:
    199  *      SOC_E_XXX
    200  */
    201 
    202 STATIC int
    203 _phy_5482_medium_config_update(int unit, soc_port_t port,
    204                                 soc_phy_config_t *cfg)
    205 {
    206     SOC_IF_ERROR_RETURN
    207         (phy_5482_speed_set(unit, port, cfg->force_speed));
    208     SOC_IF_ERROR_RETURN
    209         (phy_5482_duplex_set(unit, port, cfg->force_duplex));
    210     SOC_IF_ERROR_RETURN
    211         (phy_5482_master_set(unit, port, cfg->master));
    212     SOC_IF_ERROR_RETURN
    213         (phy_5482_adv_local_set(unit, port, cfg->autoneg_advert));
    214     SOC_IF_ERROR_RETURN
    215         (phy_5482_autoneg_set(unit, port, cfg->autoneg_enable));
    216     SOC_IF_ERROR_RETURN
    217         (phy_5482_mdix_set(unit, port, cfg->mdix));
    218 
    219     return SOC_E_NONE;
    220 }
    221 
    222 /***********************************************************************
    223  *
    224  * PHY5482 DRIVER ROUTINES
    225  */
    226 
    227 /*
    228  * Function:
    229  *      phy_5482_medium_config_set
    230  * Purpose:
    231  *      Set the operating parameters that are automatically selected
    232  *      when medium switches type.
    233  * Parameters:
    234  *      unit - StrataSwitch unit #
    235  *      port - Port number
    236  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    237  *      cfg - Operating parameters
    238  * Returns:
    239  *      SOC_E_XXX
    240  */
    241 
    242 STATIC int
    243 phy_5482_medium_config_set(int unit, soc_port_t port, 
    244                            soc_port_medium_t  medium,
    245                            soc_phy_config_t  *cfg)
    246 {
    247     phy_ctrl_t    *pc;
    248     soc_phy_config_t *active_medium;  /* Currently active medium */
    249     soc_phy_config_t *change_medium;  /* Requested medium */
    250     soc_phy_config_t *other_medium;   /* The other medium */
    251     int               medium_update;
    252     soc_port_mode_t   advert_mask;
    253 
    254     if (NULL == cfg) {
    255         return SOC_E_PARAM;
    256     }
    257 
    258     pc            = EXT_PHY_SW_STATE(unit, port);
    259     medium_update = FALSE;
    260 
    261    switch (medium) {
    262     case SOC_PORT_MEDIUM_COPPER:
    263         if (!pc->automedium) {
    264             if (!PHY_COPPER_MODE(unit, port)) {
    265                 return SOC_E_UNAVAIL;
    266             }
    267             /* check if device is fiber capable before switching */
    268             if (cfg->preferred == 0) {
    269 
    270                 if (!soc_property_port_get(unit, port,
    271                               spn_PHY_FIBER_CAPABLE, TRUE)) {
    272                     /* return if not fiber capable*/
    273                     return SOC_E_UNAVAIL;
    274                 }
    275             }
    276         }
    277         
    278         change_medium  = &pc->copper;
    279         other_medium   = &pc->fiber;
    280         advert_mask    = ADVERT_ALL_COPPER;
    281         break;
    282     case SOC_PORT_MEDIUM_FIBER:
    283         if (!pc->automedium && !PHY_FIBER_MODE(unit, port)) {
    284             return SOC_E_UNAVAIL;
    285         }
    286         change_medium  = &pc->fiber;
    287         other_medium   = &pc->copper;
    288         advert_mask    = ADVERT_ALL_FIBER;
    289         break;
    290     default:
    291         return SOC_E_PARAM;
    292     }
    293 
    294     /*
    295      * Changes take effect immediately if the target medium is active or
    296      * the preferred medium changes.
    297      */
    298     if (change_medium->enable != cfg->enable) {
    299         medium_update = TRUE;
    300     }
    301     if (change_medium->preferred != cfg->preferred) {
    302         /* Make sure that only one medium is preferred */
    303         other_medium->preferred = !cfg->preferred;
    304         medium_update = TRUE;
    305     }
    306 
    307     sal_memcpy(change_medium, cfg, sizeof(*change_medium));
    308     change_medium->autoneg_advert &= advert_mask;
    309 
    310     if (medium_update) {
    311         /* The new configuration may cause medium change. Check
    312          * and update medium.
    313          */
    314         SOC_IF_ERROR_RETURN
    315             (_phy_5482_medium_change(unit, port,TRUE));
    316     } else {
    317         active_medium = (PHY_COPPER_MODE(unit, port)) ?  
    318                             &pc->copper : &pc->fiber;
    319         if (active_medium == change_medium) {
    320             /* If the medium to update is active, update the configuration */
    321             SOC_IF_ERROR_RETURN
    322                 (_phy_5482_medium_config_update(unit, port, change_medium));
    323         }
    324     }
    325     return SOC_E_NONE;
    326 }
    327 
    328 /*
    329  * Function:
    330  *      phy_5482_medium_config_get
    331  * Purpose:
    332  *      Get the operating parameters that are automatically selected
    333  *      when medium switches type.
    334  * Parameters:
    335  *      unit - StrataSwitch unit #
    336  *      port - Port number
    337  *      medium - SOC_PORT_MEDIUM_COPPER/FIBER
    338  *      cfg - (OUT) Operating parameters
    339  * Returns:
    340  *      SOC_E_XXX
    341  */
    342 
    343 STATIC int
    344 phy_5482_medium_config_get(int unit, soc_port_t port, 
    345                            soc_port_medium_t medium,
    346                            soc_phy_config_t *cfg)
    347 {
    348     int            rv;
    349     phy_ctrl_t    *pc;
    350 
    351     pc = EXT_PHY_SW_STATE(unit, port);
    352     rv = SOC_E_NONE;
    353 
    354     switch (medium) {
    355     case SOC_PORT_MEDIUM_COPPER:
    356         if (pc->automedium || PHY_COPPER_MODE(unit, port)) {
    357             sal_memcpy(cfg, &pc->copper, sizeof (*cfg));
    358         } else {
    359             rv = SOC_E_UNAVAIL;
    360         }
    361         break;
    362     case SOC_PORT_MEDIUM_FIBER:
    363         if (pc->automedium || PHY_FIBER_MODE(unit, port)) {
    364             sal_memcpy(cfg, &pc->fiber, sizeof (*cfg));
    365         } else {
    366             rv = SOC_E_UNAVAIL;
    367         }
    368         break;
    369     default:
    370         rv = SOC_E_PARAM;
    371         break;
    372     }
    373 
    374     return rv;
    375 }
    376 
    377 /*
    378  * Function:
    379  *      _phy_5482_reset_setup
    380  * Purpose:
    381  *      Function to reset the PHY and set up initial operating registers.
    382  * Parameters:
    383  *      unit - StrataSwitch unit #.
    384  *      port - StrataSwitch port #.
    385  * Returns:
    386  *      SOC_E_XXX
    387  * Notes:
    388  *      Configures for copper/fiber according to the current
    389  *      setting of PHY_FLAGS_FIBER.
    390  */
    391 
    392 STATIC int
    393 _phy_5482_reset_setup(int unit, soc_port_t port)
    394 {
    395     phy_ctrl_t    *pc;
    396 
    397     pc = EXT_PHY_SW_STATE(unit, port);
    398 
    399     /* Reset the PHY with previously registered callback function. 
    400      */
    401     SOC_IF_ERROR_RETURN(soc_phy_reset(unit, port));
    402 
    403     /* Reset the secondary SerDes         */
    404     SOC_IF_ERROR_RETURN
    405         (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, MII_CTRL_RESET));
    406     sal_usleep(10000);
    407 
    408     /* Disable super-isolate */
    409     SOC_IF_ERROR_RETURN
    410         (MODIFY_PHY5482_MII_POWER_CTRLr(unit, pc, 0x0, 1U<<5));
    411 
    412     SOC_IF_ERROR_RETURN
    413         (_phy_5482_no_reset_setup(unit, port));
    414 
    415     return SOC_E_NONE;
    416 }
    417 
    418 STATIC int
    419 _phy_5482_no_reset_setup(int unit, soc_port_t port)
    420 {
    421     phy_ctrl_t    *int_pc;
    422     phy_ctrl_t    *pc;
    423     uint16         data, mask;
    424 
    425     LOG_INFO(BSL_LS_SOC_PHY,
    426              (BSL_META_U(unit,
    427                          "_phy_5482_reset_setup: u=%d p=%d medium=%s\n"),
    428                          unit, port,
    429               PHY_COPPER_MODE(unit, port) ? "COPPER" : "FIBER"));
    430 
    431     pc      = EXT_PHY_SW_STATE(unit, port);
    432     int_pc  = INT_PHY_SW_STATE(unit, port);
    433 
    434     /* SGMII interface to MAC */
    435     /* soc_phy_reset has reset the phy, powering down the unstrapped interface.
    436      * Make sure enabled interfaces are powered up. 
    437      */
    438     SOC_IF_ERROR_RETURN
    439         (MODIFY_PHY5482_1000X_MII_CTRLr(unit, pc, 0, MII_CTRL_PD));
    440 
    441     /* 1000Base-X FullDuplex will be clear after the phy been 
    442      * reset in phy5482s 
    443      */
    444     data = MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_RAN | MII_CTRL_AE;
    445 
    446     SOC_IF_ERROR_RETURN
    447         (WRITE_PHY5482_1000X_MII_CTRLr(unit, pc, data));
    448    
    449     /* copper regs */
    450     if (!pc->copper.enable || (!pc->automedium && pc->fiber.preferred)) {
    451         /* Copper interface is not used. Powered down. */
    452         SOC_IF_ERROR_RETURN
    453             (MODIFY_PHY5482_MII_CTRLr(unit, pc, MII_CTRL_PD, MII_CTRL_PD));
    454     } else {
    455         SOC_IF_ERROR_RETURN
    456             (MODIFY_PHY5482_MII_CTRLr(unit, pc, 0, MII_CTRL_PD));
    457         SOC_IF_ERROR_RETURN
    458             (WRITE_PHY5482_MII_GB_CTRLr(unit, pc,  
    459                             MII_GB_CTRL_ADV_1000FD | MII_GB_CTRL_PT));
    460         SOC_IF_ERROR_RETURN
    461             (WRITE_PHY5482_MII_CTRLr(unit, pc, 
    462                 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE));
    463     }
    464           
    465     /* Adjust timing */
    466     SOC_IF_ERROR_RETURN
    467         (MODIFY_PHY5482_SPARE_CTRLr(unit, pc, 0x0002, 0x0002));
    468 
    469     if (PHY_SGMII_AUTONEG_MODE(unit, port)) {
    470         /* Disable parallel detect on SGMII interface with MAC to elimates
    471          * the possibility of the BCM5482S turning off the SGMII auto-neg 
    472          * interface connected to the MAC inadvertly.
    473          * Do not disable parallel detect if SGMII autoneg is disabled. 
    474          * Otherwise, the PHY will not able to detect the configuration
    475          * of MAC SerDes.
    476          */
    477         SOC_IF_ERROR_RETURN
    478             (WRITE_PHY5482_1ST_SERDES_CTRLr(unit, pc, 0));
    479     }
    480 
    481     if (NULL != int_pc) {
    482         SOC_IF_ERROR_RETURN
    483             (PHY_INIT(int_pc->pd, unit, port));
    484 
    485         if (PHY_FIBER_MODE(unit, port)) {
    486            /* Interface to MAC or internal SerDes is always SGMII mode.
    487             * Typical internal SerDes driver set the interface to 1000BASE-X,
    488             * if the media is fiber. Therefore, we need to force the interface 
    489             * of internal SerDes Driver to SGMII. */
    490            SOC_IF_ERROR_RETURN
    491                (PHY_NOTIFY(int_pc->pd, unit, port, phyEventInterface,
    492                            SOC_PORT_IF_SGMII));
    493         } 
    494 
    495         if (PHY_COPPER_MODE(unit, port) && 
    496             !PHY_SGMII_AUTONEG_MODE(unit, port)) {
    497             /* Make sure internal SerDes is in power down state 
    498              * until the MAC is ready. */
    499             SOC_IF_ERROR_RETURN
    500                 (PHY_NOTIFY(int_pc->pd, unit, port, 
    501                             phyEventStop, PHY_STOP_COPPER));
    502         }
    503     }
    504 
    505     /* Power down secondary SerDes */
    506     SOC_IF_ERROR_RETURN
    507         (MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, MII_CTRL_PD, 
    508                                                MII_CTRL_PD));
    509     if (pc->fiber.enable && (pc->automedium || pc->fiber.preferred)) {
    510         /* Secondary SerDes Control Register
    511          * Select secondary serdes 1000BaseX in full duplex
    512          */
    513         data  = 1 << 0;     /* Enable secondary SerDes */
    514         data |= 1 << 2;     /* Select Sync function from secondary SerDes */ 
    515         data |= 1 << 3;     /* Enable secondary SerDes to driver LEDs     */
    516         data |= 1 << 5;     /* Enable secondary SerDes 100FX full duplex  */
    517         SOC_IF_ERROR_RETURN
    518             (WRITE_PHY5482_2ND_SERDES_CTRLr(unit, pc, data));
    519         
    520         /* remove power down of secondary SerDes */
    521         SOC_IF_ERROR_RETURN
    522             (MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, 0, MII_CTRL_PD));
    523 
    524         /* Enable auto-detection between SGMII-slave and 1000BASE-X */
    525         SOC_IF_ERROR_RETURN
    526             (MODIFY_PHY5482_2ND_SERDES_SGMII_SLAVEr(unit, pc, 1, 1));
    527 
    528         /* set the advertisement of secondary serdes */
    529         /* Disable half-duplex, full-duplex capable */
    530         SOC_IF_ERROR_RETURN
    531             (MODIFY_PHY5482_2ND_SERDES_ANAr(unit, pc, (1 << 5), 
    532                                                 (1 << 5) | (1 << 6)));
    533       
    534         /* Restart secondary SerDes autonegotiation */
    535         SOC_IF_ERROR_RETURN
    536             (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc,
    537                 MII_CTRL_FD | MII_CTRL_SS_1000 | MII_CTRL_AE));
    538     
    539         switch (pc->fiber_detect) {
    540             case  2:         /* LED 2 */
    541             case -2:
    542             case  4:         /* LED 4 : kept for backward compatibility */
    543             case -4:
    544             case  10:        /* EN_10B for signal detect */
    545             case -10:
    546             case 0:         /* default */
    547                 /* GPIO Control/Status Register (0x1c shadow 01111) */
    548                 /* Change LED2 pin into an input */
    549                 SOC_IF_ERROR_RETURN
    550                     (MODIFY_PHY5482_LED_GPIO_CTRLr(unit, pc, 0x08, 0x08));
    551                 break;
    552             case  1:         /* PECL , no such pin in 5482 data sheet */
    553             case -1:
    554             default:
    555                 return SOC_E_CONFIG;
    556         }
    557     }
    558 
    559     /* Configure Auto-detect Medium (0x1c shadow 11110) */
    560     mask = 0x33f;               /* Auto-detect bit mask */
    561     data = 0;
    562     if (pc->automedium) {
    563         data |= 1 << 0;    /* Enable auto-detect medium */
    564         data |= 1 << 9;    /* Enable Secondary SerDes auto-detect */
    565     }
    566     /* When no link partner exists, fiber should be default medium */
    567     /* When both link partners exipc, fiber should be prefered medium
    568      * for the following reasons.
    569      * 1. Most fiber module generates signal detect when the fiber cable is
    570      *    plugged in regardless of any activity even if the link partner is
    571      *    powered down.
    572      * 2. Fiber mode consume much lesser power than copper mode.
    573      */
    574     if (pc->fiber.preferred) {
    575         data |= 1 << 1;    /* Fiber selected when both media are active */
    576         data |= 1 << 2;    /* Fiber selected when no medium is active */
    577     }
    578 
    579     /*
    580      * Enable internal inversion of LED2/SD input pin.  Used only if
    581      * the fiber module provides RX_LOS instead of Signal Detect.
    582      */
    583     if (pc->fiber_detect < 0) {
    584         data |= 1 << 8;    /* Fiber signal detect is active low from pin */
    585     }
    586     SOC_IF_ERROR_RETURN
    587         (MODIFY_PHY5482_AUTO_DETECT_MEDIUMr(unit, pc, data, mask));
    588 
    589 
    590 #if DISABLE_CLK125
    591     /* Note: CLK125 does not function properly on BCM5482S A0 and A1 */
    592     /*       Refer to 5482S-ES101-R for details.                     */ 
    593     /* Reduce EMI emissions by disabling the CLK125 pin if not used  */
    594     data = 0x001c;  /* When write, bit 9 and 7 must be zero and */ 
    595     data = 0x029c;  /* bit 2, 3, and 4 must be one. */ 
    596     SOC_IF_ERROR_RETURN
    597         (MODIFY_PHY5482_SPARE_CTRL_3r(unit, pc, 0, 1));
    598 #endif
    599 
    600 #if AUTO_MDIX_WHEN_AN_DIS
    601     /* Enable Auto-MDIX When autoneg disabled */
    602     SOC_IF_ERROR_RETURN
    603         (MODIFY_PHY5482_MII_MISC_CTRLr(unit, pc, 0x200, 0x200));
    604 #endif
    605 
    606     /*
    607      * Configure Auxiliary 1000BASE-X control register to turn off
    608      * carrier extension.  The Intel 7131 NIC does not accept carrier
    609      * extension and gets CRC errors.
    610      */
    611     SOC_IF_ERROR_RETURN
    612         (MODIFY_PHY5482_AUX_1000X_CTRLr(unit, pc, 0x0040, 0x0040));
    613 
    614     /* Configure extended control register for led mode and jumbo frame support
    615      */
    616     mask  = (1 << 5) | (1 << 0);
    617 
    618     /* if using led link/activity mode, disable led traffic mode */
    619     if (pc->ledctrl & 0x10 || pc->ledselect == 0x01) {
    620         data = 0;
    621     } else {
    622         data  = 1 << 5;      /* Enable LEDs to indicate traffic status */
    623     }
    624     /* Configure Extended Control Register for Jumbo frames support */
    625     data |= 1 << 0;      /* Set high FIFO elasticity to support jumbo frames */
    626     SOC_IF_ERROR_RETURN
    627         (MODIFY_PHY5482_MII_ECRr(unit, pc, data, mask));
    628 
    629     /* Enable extended packet length (4.5k through 25k) */
    630     SOC_IF_ERROR_RETURN
    631         (MODIFY_PHY5482_MII_AUX_CTRLr(unit, pc, 0x4000, 0x4000));
    632 
    633     /* Configure LED selectors */
    634     data = ((pc->ledmode[2] & 0xf) << 4) | (pc->ledmode[0] & 0xf);
    635     SOC_IF_ERROR_RETURN
    636         (WRITE_PHY5482_LED_SELECTOR_1r(unit, pc, data));
    637 
    638     data = ((pc->ledmode[1] & 0xf) << 4) | (pc->ledmode[3] & 0xf);
    639     SOC_IF_ERROR_RETURN
    640         (WRITE_PHY5482_LED_SELECTOR_2r(unit, pc, data));
    641 
    642     data = (pc->ledctrl & 0x3ff);
    643     SOC_IF_ERROR_RETURN
    644         (WRITE_PHY5482_LED_CTRLr(unit, pc, data));
    645 
    646     SOC_IF_ERROR_RETURN
    647         (WRITE_PHY5482_EXP_LED_SELECTORr(unit, pc, pc->ledselect));
    648 
    649    return SOC_E_NONE;
    650 }
    651 
    652 /*
    653  * Function:
    654  *      phy_5482_init
    655  * Purpose:
    656  *      Init function for 5482 PHY.
    657  * Parameters:
    658  *      unit - StrataSwitch unit #.
    659  *      port - StrataSwitch port #.
    660  * Returns:
    661  *      SOC_E_NONE
    662  */
    663 
    664 STATIC int
    665 phy_5482_init(int unit, soc_port_t port)
    666 {
    667     phy_ctrl_t        *pc;
    668     int                 fiber_capable;
    669     int                 fiber_preferred;
    670 
    671     LOG_INFO(BSL_LS_SOC_PHY,
    672              (BSL_META_U(unit,
    673                          "phy_5482_init: u=%d p=%d\n"),
    674                          unit, port));
    675 
    676     /* Only SGMII interface to switch MAC is supported */ 
    677     if (IS_GMII_PORT(unit, port)) {
    678         return SOC_E_CONFIG; 
    679     }
    680 
    681     pc = EXT_PHY_SW_STATE(unit, port);
    682 
    683     pc->interface = SOC_PORT_IF_SGMII;
    684 
    685     fiber_capable = soc_property_port_get(unit, port,
    686                               spn_PHY_FIBER_CAPABLE, TRUE);
    687 
    688     /*
    689      * In automedium mode, the property phy_fiber_pref_port<X> is used
    690      * to set a preference for fiber mode in the event both copper and
    691      * fiber links are up.
    692      *
    693      * If NOT in automedium mode, phy_fiber_pref_port<X> is used to
    694      * select which of fiber or copper is forced.
    695      */
    696     if (!fiber_capable) {
    697         fiber_preferred = 0;
    698         pc->automedium      = 0;
    699         pc->fiber_detect    = 0;
    700     } else {
    701         fiber_preferred =
    702             soc_property_port_get(unit, port, spn_PHY_FIBER_PREF, 1);
    703         pc->automedium =
    704             soc_property_port_get(unit, port, spn_PHY_AUTOMEDIUM, 1);
    705         pc->fiber_detect =
    706             soc_property_port_get(unit, port, spn_PHY_FIBER_DETECT, 0);
    707     }
    708 
    709     LOG_INFO(BSL_LS_SOC_PHY,
    710              (BSL_META_U(unit,
    711                          "phy_5482_init: "
    712                          "u=%d p=%d type=5482%s automedium=%d fiber_pref=%d detect=%d\n"),
    713               unit, port, fiber_capable ? "S" : "",
    714               pc->automedium, fiber_preferred, pc->fiber_detect));
    715 
    716     pc->copper.enable = TRUE;
    717     pc->copper.preferred = !fiber_preferred;
    718     pc->copper.autoneg_enable = TRUE;
    719     pc->copper.autoneg_advert = ADVERT_ALL_COPPER;
    720     pc->copper.force_speed = 1000;
    721     pc->copper.force_duplex = TRUE;
    722     pc->copper.master = SOC_PORT_MS_AUTO;
    723     pc->copper.mdix = SOC_PORT_MDIX_AUTO;
    724 
    725     pc->fiber.enable = fiber_capable;
    726     pc->fiber.preferred = fiber_preferred;
    727     pc->fiber.autoneg_enable = fiber_capable;
    728     pc->fiber.autoneg_advert = ADVERT_ALL_FIBER;
    729     pc->fiber.force_speed = 1000;
    730     pc->fiber.force_duplex = TRUE;
    731     pc->fiber.master = SOC_PORT_MS_NONE;
    732     pc->fiber.mdix = SOC_PORT_MDIX_NORMAL;
    733 
    734     /* Initially configure for the preferred medium. */
    735     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
    736     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    737     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_PASSTHRU);
    738     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    739     if (pc->fiber.preferred) {
    740         PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
    741     } else {
    742         PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
    743     }
    744 
    745     /* Get Requested LED selectors (defaults are hardware defaults) */
    746     pc->ledmode[0] = soc_property_port_get(unit, port, spn_PHY_LED1_MODE, 0);
    747     pc->ledmode[1] = soc_property_port_get(unit, port, spn_PHY_LED2_MODE, 1);
    748     pc->ledmode[2] = soc_property_port_get(unit, port, spn_PHY_LED3_MODE, 3);
    749     pc->ledmode[3] = soc_property_port_get(unit, port, spn_PHY_LED4_MODE, 6);
    750     pc->ledctrl = soc_property_port_get(unit, port, spn_PHY_LED_CTRL, 0x8);
    751     pc->ledselect = soc_property_port_get(unit, port, spn_PHY_LED_SELECT, 0);
    752 
    753     SOC_IF_ERROR_RETURN
    754         (_phy_5482_reset_setup(unit, port));
    755 
    756     SOC_IF_ERROR_RETURN
    757         (_phy_5482_medium_config_update(unit, port,
    758                                         PHY_COPPER_MODE(unit, port) ?
    759                                         &pc->copper :
    760                                         &pc->fiber));
    761 
    762     return SOC_E_NONE;
    763 }
    764 
    765 /*
    766  * Function:
    767  *      phy_5482_enable_set
    768  * Purpose:
    769  *      Enable or disable the physical interface.
    770  * Parameters:
    771  *      unit - StrataSwitch unit #.
    772  *      port - StrataSwitch port #.
    773  *      enable - Boolean, true = enable PHY, false = disable.
    774  * Returns:
    775  *      SOC_E_XXX
    776  */
    777 
    778 STATIC int
    779 phy_5482_enable_set(int unit, soc_port_t port, int enable)
    780 {
    781     uint16         power;
    782     phy_ctrl_t    *pc;
    783 
    784     pc     = EXT_PHY_SW_STATE(unit, port);
    785     power  = (enable) ? 0 : MII_CTRL_PD;
    786 
    787     /* Do not incorrectly Power up the interface if medium is disabled and 
    788      * global enable = true
    789      */
    790     if (pc->copper.enable && (pc->automedium || PHY_COPPER_MODE(unit, port))) {
    791         SOC_IF_ERROR_RETURN
    792             (MODIFY_PHY5482_MII_CTRLr(unit, pc, power, MII_CTRL_PD));
    793 
    794         LOG_INFO(BSL_LS_SOC_PHY,
    795                  (BSL_META_U(unit,
    796                              "phy_5482_enable_set: "
    797                              "Power %s copper medium\n"), (enable) ? "up" : "down"));
    798     }
    799 
    800     if (pc->fiber.enable && (pc->automedium || PHY_FIBER_MODE(unit, port))) {
    801         SOC_IF_ERROR_RETURN
    802             (MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, power, 
    803                                                    MII_CTRL_PD));
    804 
    805         LOG_INFO(BSL_LS_SOC_PHY,
    806                  (BSL_META_U(unit,
    807                              "phy_5482_enable_set: "
    808                              "Power %s fiber medium\n"), (enable) ? "up" : "down"));
    809     }
    810 
    811     /* Update software state */
    812     SOC_IF_ERROR_RETURN(phy_fe_ge_enable_set(unit, port, enable));
    813 
    814     return SOC_E_NONE;
    815 }
    816 
    817 /*
    818  * Function:
    819  *      phy_5482_enable_get
    820  * Purpose:
    821  *      Enable or disable the physical interface for a 5482 device.
    822  * Parameters:
    823  *      unit - StrataSwitch unit #.
    824  *      port - StrataSwitch port #.
    825  *      enable - (OUT) Boolean, true = enable PHY, false = disable.
    826  * Returns:
    827  *      SOC_E_XXX
    828  */
    829 
    830 STATIC int
    831 phy_5482_enable_get(int unit, soc_port_t port, int *enable)
    832 {
    833     return phy_fe_ge_enable_get(unit, port, enable);
    834 }
    835 
    836 /*
    837  * Function:
    838  *      _phy_5482_100fx_setup
    839  * Purpose:
    840  *      Switch from 1000X mode to 100FX.  
    841  * Parameters:
    842  *      unit - StrataSwitch unit #.
    843  *      port - StrataSwitch port #.
    844  * Returns:
    845  *      SOC_E_XXX
    846  */
    847 STATIC int
    848 _phy_5482_fiber_100fx_setup(int unit, soc_port_t port) 
    849 {
    850     uint16               data;
    851     phy_ctrl_t    *pc;
    852 
    853     pc          = EXT_PHY_SW_STATE(unit, port);
    854 
    855     LOG_VERBOSE(BSL_LS_SOC_PHY,
    856                 (BSL_META_U(unit,
    857                             "_phy_5482_1000x_to_100fx: u=%d p=%d \n"),
    858                  unit, port));
    859 
    860     /* Operate secondary SerDes in 100FX  */
    861     data  = 1 << 0;     /* Enable secondary SerDes */
    862     data |= 1 << 2;     /* Select Sync function from secondary SerDes */
    863     data |= 1 << 3;     /* Enable secondary SerDes to driver LEDs     */
    864     data |= 1 << 4;     /* Operate secondary SerDes in 100Base-FX mode */
    865     if (pc->fiber.force_duplex) {
    866         data |= 1 << 5;   /* Enable secondary SerDes 100FX full duplex  */
    867     }
    868     SOC_IF_ERROR_RETURN
    869             (WRITE_PHY5482_2ND_SERDES_CTRLr(unit, pc, data));
    870 
    871     /* Secondary SerDes */
    872     /* Reset the secondary SerDes         */
    873     SOC_IF_ERROR_RETURN
    874         (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, MII_CTRL_RESET));
    875     sal_usleep(10000);
    876 
    877     /* Power up the secondary SerDes      */ 
    878     SOC_IF_ERROR_RETURN
    879         (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, 
    880                      MII_CTRL_AE | MII_CTRL_FD | MII_CTRL_SS_100 |
    881                      (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE) ? MII_CTRL_PD : 0)));
    882 
    883     /* Enable extended packet length (100fx-mode) */ 
    884     SOC_IF_ERROR_RETURN
    885         (MODIFY_PHY5482_2ND_SERDES_MISC1r(unit, pc, 0x01, 0x01));
    886 
    887     PHY_FLAGS_SET(unit, port, PHY_FLAGS_100FX);
    888     pc->fiber.force_speed    = 100;
    889     pc->fiber.autoneg_enable = FALSE;
    890 
    891     return SOC_E_NONE;
    892 }
    893 
    894 /*
    895  * Function:
    896  *      _phy_5482_1000x_setup
    897  * Purpose:
    898  *      Switch from 100FX mode to 1000X.  
    899  * Parameters:
    900  *      unit - StrataSwitch unit #.
    901  *      port - StrataSwitch port #.
    902  * Returns:
    903  *      SOC_E_XXX
    904  */
    905 STATIC int
    906 _phy_5482_fiber_1000x_setup(int unit, soc_port_t port) 
    907 {
    908     uint16         data;
    909     phy_ctrl_t    *pc;
    910 
    911     pc          = EXT_PHY_SW_STATE(unit, port);
    912 
    913     LOG_VERBOSE(BSL_LS_SOC_PHY,
    914                 (BSL_META_U(unit,
    915                             "_phy_5482_fiber_1000x_setup: u=%d p=%d \n"),
    916                  unit, port));
    917  
    918     /* Operate secondary SerDes in 1000X  */
    919     data  = 1 << 0;     /* Enable secondary SerDes */
    920     data |= 1 << 2;     /* Select Sync function from secondary SerDes */
    921     data |= 1 << 3;     /* Enable secondary SerDes to driver LEDs     */
    922     data |= 1 << 5;     /* Enable secondary SerDes 100FX full duplex  */
    923     SOC_IF_ERROR_RETURN
    924         (WRITE_PHY5482_2ND_SERDES_CTRLr(unit, pc, data));
    925 
    926     /* Reset the secondary SerDes         */
    927     SOC_IF_ERROR_RETURN
    928         (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, MII_CTRL_RESET));
    929     sal_usleep(10000);
    930     
    931     /* Power up the secondary SerDes      */ 
    932     if (pc->fiber.autoneg_enable) {
    933         data = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000;
    934     } else {
    935         data = MII_CTRL_RAN | MII_CTRL_FD | MII_CTRL_SS_1000;
    936     }
    937 
    938     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
    939         data |= MII_CTRL_PD; 
    940     }
    941     SOC_IF_ERROR_RETURN
    942         (WRITE_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, data));
    943 
    944     pc->fiber.force_duplex = TRUE;
    945     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    946 
    947     return SOC_E_NONE;
    948 }
    949 
    950 STATIC int
    951 _phy_5482_medium_change(int unit, soc_port_t port, int force_update)
    952 {
    953     phy_ctrl_t    *pc;
    954     int            medium;
    955 
    956     pc    = EXT_PHY_SW_STATE(unit, port);
    957 
    958     SOC_IF_ERROR_RETURN
    959         (_phy_5482_medium_check(unit, port, &medium));
    960 
    961     if (medium == SOC_PORT_MEDIUM_COPPER) {
    962         if ((!PHY_COPPER_MODE(unit, port)) || force_update) { /* Was fiber */ 
    963             PHY_FLAGS_SET(unit, port, PHY_FLAGS_COPPER);
    964             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_FIBER);
    965             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_100FX);
    966             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
    967             SOC_IF_ERROR_RETURN
    968                 (_phy_5482_no_reset_setup(unit, port));
    969 
    970             /* Do not power up the interface if medium is disabled. */
    971             if (pc->copper.enable) {
    972                 SOC_IF_ERROR_RETURN
    973                     (_phy_5482_medium_config_update(unit, port, &pc->copper));
    974             }
    975             LOG_INFO(BSL_LS_SOC_PHY,
    976                      (BSL_META_U(unit,
    977                                  "_phy_5482_link_auto_detect: u=%d p=%d [F->C]\n"),
    978                       unit, port));
    979         }
    980     } else {        /* Fiber */
    981         if (PHY_COPPER_MODE(unit, port) || force_update) { /* Was copper */
    982             PHY_FLAGS_CLR(unit, port, PHY_FLAGS_COPPER);
    983             PHY_FLAGS_SET(unit, port, PHY_FLAGS_FIBER);
    984             PHY_FLAGS_SET(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
    985             SOC_IF_ERROR_RETURN
    986                 (_phy_5482_no_reset_setup(unit, port));
    987 
    988             if (pc->fiber.enable) {
    989                 SOC_IF_ERROR_RETURN
    990                     (_phy_5482_medium_config_update(unit, port, &pc->fiber));
    991             }
    992             LOG_INFO(BSL_LS_SOC_PHY,
    993                      (BSL_META_U(unit,
    994                                  "_phy_5482_link_auto_detect: u=%d p=%d [C->F]\n"),
    995                       unit, port));
    996         }
    997     }
    998     return SOC_E_NONE;
    999 }
   1000 
   1001 /*
   1002  * Function:
   1003  *      phy_5482_link_get
   1004  * Purpose:
   1005  *      Determine the current link up/down status for a 5482 device.
   1006  * Parameters:
   1007  *      unit - StrataSwitch unit #.
   1008  *      port - StrataSwitch port #.
   1009  *      link - (OUT) Boolean, true indicates link established.
   1010  * Returns:
   1011  *      SOC_E_XXX
   1012  * Notes:
   1013  *      If using automedium, also switches the mode.
   1014  */
   1015 STATIC int
   1016 phy_5482_link_get(int unit, soc_port_t port, int *link)
   1017 {
   1018     phy_ctrl_t    *pc;
   1019     uint16         data; 
   1020     uint16         mask;
   1021 
   1022     pc    = EXT_PHY_SW_STATE(unit, port);
   1023     *link = FALSE;      /* Default return */
   1024 
   1025     if (PHY_FLAGS_TST(unit, port, PHY_FLAGS_DISABLE)) {
   1026         return SOC_E_NONE;
   1027     }
   1028 
   1029     if (!pc->fiber.enable && !pc->copper.enable) {
   1030         return SOC_E_NONE;
   1031     }
   1032 
   1033     PHY_FLAGS_CLR(unit, port, PHY_FLAGS_MEDIUM_CHANGE);
   1034     if (pc->automedium) {
   1035         /* Check for medium change and update HW/SW accordingly. */
   1036         SOC_IF_ERROR_RETURN
   1037             (_phy_5482_medium_change(unit, port,FALSE));
   1038     }
   1039     if (PHY_COPPER_MODE(unit, port)) {
   1040         SOC_IF_ERROR_RETURN(phy_fe_ge_link_get(unit, port, link));
   1041     } else {
   1042         SOC_IF_ERROR_RETURN
   1043             (READ_PHY5482_2ND_SERDES_1000X_STATr(unit, pc, &data));
   1044         *link = (data != 0xffff) && (data & MII_STAT_LA) ? TRUE : FALSE;
   1045     }
   1046 
   1047     /* If preferred medium is up, disable the other medium 
   1048      * to prevent false link. */
   1049     if (pc->automedium) {
   1050         mask = MII_CTRL_PD;
   1051         if (pc->copper.preferred) {
   1052             if (pc->fiber.enable) {
   1053                 /* power down secondary serdes */
   1054                 data = (*link && PHY_COPPER_MODE(unit, port)) ? MII_CTRL_PD : 0;
   1055             } else {
   1056                 data = MII_CTRL_PD;
   1057             }
   1058             SOC_IF_ERROR_RETURN
   1059                 (MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, data, mask));
   1060         } else {  /* pc->fiber.preferred */
   1061             if (pc->copper.enable) {
   1062                 data = (*link && PHY_FIBER_MODE(unit, port)) ? MII_CTRL_PD : 0;
   1063             } else {
   1064                 data = MII_CTRL_PD;
   1065             }
   1066             SOC_IF_ERROR_RETURN
   1067                 (MODIFY_PHY5482_MII_CTRLr(unit, pc, data, mask));
   1068         }
   1069     }
   1070 
   1071     LOG_VERBOSE(BSL_LS_SOC_PHY,
   1072                 (BSL_META_U(unit,
   1073                             "phy_5482_link_get: u=%d p=%d mode=%s%s link=%d\n"),
   1074                  unit, port,
   1075                  PHY_COPPER_MODE(unit, port) ? "C" : "F",
   1076                  PHY_FIBER_100FX_MODE(unit, port)? "(100FX)" : "",
   1077                  *link));
   1078 
   1079     return SOC_E_NONE;
   1080 }
   1081 
   1082 /*
   1083  * Function:
   1084  *      phy_5482_duplex_set
   1085  * Purpose:
   1086  *      Set the current duplex mode (forced).
   1087  * Parameters:
   1088  *      unit - StrataSwitch unit #.
   1089  *      port - StrataSwitch port #.
   1090  *      duplex - Boolean, true indicates full duplex, false indicates half.
   1091  * Returns:
   1092  *      SOC_E_NONE
   1093  *      SOC_E_UNAVAIL - Half duplex requested, and not supported.
   1094  * Notes:
   1095  *      The duplex is set only for the ACTIVE medium.
   1096  *      No synchronization performed at this level.
   1097  *      Autonegotiation is not manipulated.
   1098  */
   1099 
   1100 STATIC int
   1101 phy_5482_duplex_set(int unit, soc_port_t port, int duplex)
   1102 {
   1103     int                  rv;
   1104     phy_ctrl_t    *pc;
   1105 
   1106     pc = EXT_PHY_SW_STATE(unit, port);
   1107     rv = SOC_E_NONE;
   1108     if (PHY_COPPER_MODE(unit, port)) {
   1109         /* Note: mac.c uses phy_5690_notify_duplex to update 5690 */
   1110         rv = phy_fe_ge_duplex_set(unit, port, duplex);
   1111         if (SOC_SUCCESS(rv)) {
   1112             pc->copper.force_duplex = duplex;
   1113         }
   1114     } else {    /* Fiber */
   1115         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1116             SOC_IF_ERROR_RETURN
   1117                 (MODIFY_PHY5482_2ND_SERDES_CTRLr(unit, pc,
   1118                        duplex? PHY_5482_2ND_SERDES_100FX_FD:0,
   1119                        PHY_5482_2ND_SERDES_100FX_FD));
   1120             pc->fiber.force_duplex = duplex;
   1121         } else {
   1122             if (!duplex) {
   1123                 rv = SOC_E_UNAVAIL;
   1124             }
   1125         }
   1126     }
   1127 
   1128     LOG_INFO(BSL_LS_SOC_PHY,
   1129              (BSL_META_U(unit,
   1130                          "phy_5482_duplex_set: u=%d p=%d d=%d rv=%d\n"),
   1131               unit, port, duplex, rv));
   1132 
   1133     return rv;
   1134 }
   1135 
   1136 /*
   1137  * Function:
   1138  *      phy_5482_duplex_get
   1139  * Purpose:
   1140  *      Get the current operating duplex mode. If autoneg is enabled,
   1141  *      then operating mode is returned, otherwise forced mode is returned.
   1142  * Parameters:
   1143  *      unit - StrataSwitch unit #.
   1144  *      port - StrataSwitch port #.
   1145  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1146  *              indicates half.
   1147  * Returns:
   1148  *      SOC_E_NONE
   1149  * Notes:
   1150  *      The duplex is retrieved for the ACTIVE medium.
   1151  *      No synchronization performed at this level. Autonegotiation is
   1152  *      not manipulated.
   1153  */
   1154 
   1155 STATIC int
   1156 phy_5482_duplex_get(int unit, soc_port_t port, int *duplex)
   1157 {
   1158     phy_ctrl_t    *pc;
   1159     uint16 data16;
   1160 
   1161     pc = EXT_PHY_SW_STATE(unit, port);
   1162 
   1163     if (PHY_COPPER_MODE(unit, port)) {
   1164         return phy_fe_ge_duplex_get(unit, port, duplex);    
   1165     } else {
   1166         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1167             SOC_IF_ERROR_RETURN
   1168                 (READ_PHY5482_2ND_SERDES_CTRLr(unit, pc, &data16));
   1169             *duplex = (data16 & PHY_5482_2ND_SERDES_100FX_FD) ?
   1170                       TRUE: FALSE;
   1171         } else { /* 1000X */ 
   1172             *duplex = TRUE;
   1173         }
   1174     }
   1175         
   1176     return SOC_E_NONE;
   1177 }
   1178 
   1179 /*
   1180  * Function:
   1181  *      phy_5482_speed_set
   1182  * Purpose:
   1183  *      Set the current operating speed (forced).
   1184  * Parameters:
   1185  *      unit - StrataSwitch unit #.
   1186  *      port - StrataSwitch port #.
   1187  *      speed - Requested speed, only 1000 supported.
   1188  * Returns:
   1189  *      SOC_E_XXX
   1190  * Notes:
   1191  *      The speed is set only for the ACTIVE medium.
   1192  */
   1193 
   1194 STATIC int
   1195 phy_5482_speed_set(int unit, soc_port_t port, int speed)
   1196 {
   1197     int            rv; 
   1198     phy_ctrl_t    *pc;
   1199 
   1200     pc = EXT_PHY_SW_STATE(unit, port);
   1201     rv = SOC_E_NONE;
   1202     if (PHY_COPPER_MODE(unit, port)) {
   1203         /* Note: mac.c uses phy_5690_notify_speed to update 5690 */
   1204         rv = phy_fe_ge_speed_set(unit, port, speed);
   1205         if (SOC_SUCCESS(rv)) {
   1206             pc->copper.force_speed = speed;
   1207         }
   1208     } else {    /* Fiber */
   1209         if (speed == 100) {
   1210             rv = _phy_5482_fiber_100fx_setup(unit, port);
   1211        } else  if (speed == 0 || speed == 1000) {
   1212             rv = _phy_5482_fiber_1000x_setup(unit, port);
   1213        } else {
   1214             rv = SOC_E_CONFIG;
   1215        }
   1216        if (SOC_SUCCESS(rv)) {
   1217            pc->fiber.force_speed = speed;
   1218        }
   1219     }
   1220     if (SOC_SUCCESS(rv) && !PHY_SGMII_AUTONEG_MODE(unit, port)) {
   1221         uint16 mii_ctrl;
   1222 
   1223         SOC_IF_ERROR_RETURN
   1224             (READ_PHY5482_1000X_MII_CTRLr(unit, pc, &mii_ctrl));
   1225 
   1226         mii_ctrl &= ~(MII_CTRL_SS_LSB | MII_CTRL_SS_MSB);
   1227         switch(speed) {
   1228         case 10:
   1229             mii_ctrl |= MII_CTRL_SS_10;
   1230             break;
   1231         case 100:
   1232             mii_ctrl |= MII_CTRL_SS_100;
   1233             break;
   1234         case 0: 
   1235         case 1000:
   1236             mii_ctrl |= MII_CTRL_SS_1000;
   1237             break;
   1238         default:
   1239             return(SOC_E_CONFIG);
   1240         }
   1241 
   1242         SOC_IF_ERROR_RETURN
   1243             (WRITE_PHY5482_1000X_MII_CTRLr(unit, pc, mii_ctrl));
   1244     }
   1245 
   1246     LOG_INFO(BSL_LS_SOC_PHY,
   1247              (BSL_META_U(unit,
   1248                          "phy_5482_speed_set: u=%d p=%d s=%d fiber=%d rv=%d\n"),
   1249               unit, port, speed, PHY_FIBER_MODE(unit, port), rv));
   1250 
   1251     return rv;
   1252 }
   1253 
   1254 /*
   1255  * Function:
   1256  *      phy_5482_speed_get
   1257  * Purpose:
   1258  *      Get the current operating speed for a 5482 device.
   1259  * Parameters:
   1260  *      unit - StrataSwitch unit #.
   1261  *      port - StrataSwitch port #.
   1262  *      duplex - (OUT) Boolean, true indicates full duplex, false
   1263  *              indicates half.
   1264  * Returns:
   1265  *      SOC_E_NONE
   1266  * Notes:
   1267  *      The speed is retrieved for the ACTIVE medium.
   1268  */
   1269 
   1270 STATIC int
   1271 phy_5482_speed_get(int unit, soc_port_t port, int *speed)
   1272 {
   1273     phy_ctrl_t    *pc;
   1274     uint16         opt_mode;
   1275 
   1276     pc = EXT_PHY_SW_STATE(unit, port);
   1277 
   1278     if (PHY_COPPER_MODE(unit, port)) {
   1279         return phy_fe_ge_speed_get(unit, port, speed);
   1280     } else {
   1281         *speed = 1000;
   1282         SOC_IF_ERROR_RETURN
   1283             (READ_PHY5482_EXP_OPT_MODE_STATr(unit, pc, &opt_mode));
   1284         switch(opt_mode & (0x3 << 13)) {
   1285         case (0 << 13):
   1286             *speed = 10;
   1287             break;
   1288         case (1 << 13):
   1289             *speed = 100;
   1290             break;
   1291         case (2 << 13):
   1292             *speed = 1000;
   1293             break;
   1294         default:
   1295             LOG_WARN(BSL_LS_SOC_PHY,
   1296                      (BSL_META_U(unit,
   1297                                  "phy_5482_speed_get: u=%d p=%d invalid speed\n"),
   1298                       unit, port));
   1299         }
   1300     }
   1301 
   1302     return SOC_E_NONE;
   1303 }
   1304 
   1305 /*
   1306  * Function:
   1307  *      phy_5482_master_set
   1308  * Purpose:
   1309  *      Set the current master mode
   1310  * Parameters:
   1311  *      unit - StrataSwitch unit #.
   1312  *      port - StrataSwitch port #.
   1313  *      master - SOC_PORT_MS_*
   1314  * Returns:
   1315  *      SOC_E_XXX
   1316  * Notes:
   1317  *      The master mode is set only for the ACTIVE medium.
   1318  */
   1319 STATIC int
   1320 phy_5482_master_set(int unit, soc_port_t port, int master)
   1321 {
   1322     int                  rv;
   1323     phy_ctrl_t    *pc;
   1324 
   1325     pc = EXT_PHY_SW_STATE(unit, port);
   1326     rv = SOC_E_NONE;
   1327     if (PHY_COPPER_MODE(unit, port)) {
   1328         rv = phy_fe_ge_master_set(unit, port, master);
   1329         if (SOC_SUCCESS(rv)) {
   1330             pc->copper.master = master;
   1331         }
   1332     }
   1333     LOG_INFO(BSL_LS_SOC_PHY,
   1334              (BSL_META_U(unit,
   1335                          "phy_5482_master_set: u=%d p=%d master=%d fiber=%d rv=%d\n"),
   1336               unit, port, master, PHY_FIBER_MODE(unit, port), rv));
   1337     return rv;
   1338 }
   1339 
   1340 /*
   1341  * Function:
   1342  *      phy_5482_master_get
   1343  * Purpose:
   1344  *      Get the current master mode for a 5482 device.
   1345  * Parameters:
   1346  *      unit - StrataSwitch unit #.
   1347  *      port - StrataSwitch port #.
   1348  *      master - (OUT) SOC_PORT_MS_*
   1349  * Returns:
   1350  *      SOC_E_NONE
   1351  * Notes:
   1352  *      The master mode is retrieved for the ACTIVE medium.
   1353  */
   1354 
   1355 STATIC int
   1356 phy_5482_master_get(int unit, soc_port_t port, int *master)
   1357 {
   1358     if (PHY_COPPER_MODE(unit, port)) {
   1359         return phy_fe_ge_master_get(unit, port, master);
   1360     } else {
   1361         *master = SOC_PORT_MS_NONE;
   1362         return SOC_E_NONE;
   1363     }
   1364 }
   1365 
   1366 /*
   1367  * Function:
   1368  *      phy_5482_autoneg_set
   1369  * Purpose:
   1370  *      Enable or disable auto-negotiation on the specified port.
   1371  * Parameters:
   1372  *      unit - StrataSwitch unit #.
   1373  *      port - StrataSwitch port #.
   1374  *      autoneg - Boolean, if true, auto-negotiation is enabled
   1375  *              (and/or restarted). If false, autonegotiation is disabled.
   1376  * Returns:
   1377  *      SOC_E_XXX
   1378  * Notes:
   1379  *      The autoneg mode is set only for the ACTIVE medium.
   1380  */
   1381 
   1382 STATIC int
   1383 phy_5482_autoneg_set(int unit, soc_port_t port, int autoneg)
   1384 {
   1385     int                 rv;
   1386     uint16              data, mask;
   1387     phy_ctrl_t   *pc;
   1388 
   1389     pc = EXT_PHY_SW_STATE(unit, port);
   1390     rv = SOC_E_NONE;
   1391     if (PHY_COPPER_MODE(unit, port)) {
   1392         rv = phy_fe_ge_an_set(unit, port, autoneg);
   1393         if (SOC_SUCCESS(rv)) {
   1394             pc->copper.autoneg_enable = autoneg ? 1 : 0;
   1395         }
   1396     } else { 
   1397         /* Disable/Enable auto-detection between SGMII-slave and 1000BASE-X */
   1398         if (autoneg) {
   1399             /* When enabling autoneg, set the default speed to 1000Mbps first.
   1400              * PHY will not enable autoneg if the PHY is in 100FX mode.
   1401              */
   1402             SOC_IF_ERROR_RETURN
   1403                 (phy_5482_speed_set(unit, port, 1000));
   1404         }
   1405         data = (autoneg) ? (1 << 0) : 0;
   1406         mask  = (1 << 0);     /* Switch between 1000BASE-X and SGMII slave 
   1407                                * modes based on SerDes-received auto-neg
   1408                                * code word. */
   1409         mask |= (1 << 1);     /* Enable/Disable SGMII slave mode */
   1410         SOC_IF_ERROR_RETURN
   1411             (MODIFY_PHY5482_2ND_SERDES_SGMII_SLAVEr(unit, pc, data, mask));
   1412         
   1413         SOC_IF_ERROR_RETURN
   1414             (phy_5482_adv_local_set(unit, port, pc->fiber.autoneg_advert));
   1415 
   1416         /* If enable autoneg, also enable parallel detect */
   1417         data = (autoneg) ? (1 << 1) : 0;
   1418         mask = (1 << 1);
   1419         SOC_IF_ERROR_RETURN
   1420             (MODIFY_PHY5482_EXP_2ND_SERDES_CTRLr(unit, pc, data, mask));
   1421 
   1422         data = MII_CTRL_FD;
   1423         data |= (autoneg) ? MII_CTRL_AE | MII_CTRL_RAN : 0;
   1424         mask = MII_CTRL_AE | MII_CTRL_RAN | MII_CTRL_FD;
   1425         SOC_IF_ERROR_RETURN
   1426             (MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, data, mask));
   1427 
   1428 
   1429         pc->fiber.autoneg_enable = autoneg ? TRUE : FALSE;
   1430     }
   1431  
   1432     LOG_INFO(BSL_LS_SOC_PHY,
   1433              (BSL_META_U(unit,
   1434                          "phy_5482_autoneg_set: u=%d p=%d autoneg=%d rv=%d\n"),
   1435               unit, port, autoneg, rv));
   1436 
   1437     return rv;
   1438 }
   1439 
   1440 /*
   1441  * Function:
   1442  *      phy_5482_autoneg_get
   1443  * Purpose:
   1444  *      Get the current auto-negotiation status (enabled/busy).
   1445  * Parameters:
   1446  *      unit - StrataSwitch unit #.
   1447  *      port - StrataSwitch port #.
   1448  *      autoneg - (OUT) if true, auto-negotiation is enabled.
   1449  *      autoneg_done - (OUT) if true, auto-negotiation is complete. This
   1450  *              value is undefined if autoneg == FALSE.
   1451  * Returns:
   1452  *      SOC_E_XXX
   1453  * Notes:
   1454  *      The autoneg mode is retrieved for the ACTIVE medium.
   1455  */
   1456 
   1457 STATIC int
   1458 phy_5482_autoneg_get(int unit, soc_port_t port,
   1459                      int *autoneg, int *autoneg_done)
   1460 {
   1461     int           rv;
   1462     uint16        data;
   1463     phy_ctrl_t   *pc;
   1464 
   1465     pc = EXT_PHY_SW_STATE(unit, port);
   1466 
   1467     rv            = SOC_E_NONE;
   1468     *autoneg      = FALSE;
   1469     *autoneg_done = FALSE;
   1470     if (PHY_COPPER_MODE(unit, port)) {
   1471         rv = phy_fe_ge_an_get(unit, port, autoneg, autoneg_done);
   1472     } else {
   1473         /* autoneg is not enabled in 100FX mode */
   1474         if (PHY_FIBER_100FX_MODE(unit, port)) {
   1475             *autoneg = FALSE;
   1476             *autoneg_done = TRUE;
   1477             return rv;
   1478         }
   1479         SOC_IF_ERROR_RETURN
   1480             (READ_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, &data));
   1481         if (data & MII_CTRL_AE) {
   1482             *autoneg = TRUE;
   1483 
   1484             SOC_IF_ERROR_RETURN
   1485                 (READ_PHY5482_2ND_SERDES_1000X_STATr(unit, pc, &data));
   1486             if (data & MII_STAT_AN_DONE) {
   1487                 *autoneg_done = TRUE;
   1488             }
   1489         }
   1490         
   1491     }
   1492 
   1493     return rv;
   1494 }
   1495 
   1496 /*
   1497  * Function:
   1498  *      phy_5482_adv_local_set
   1499  * Purpose:
   1500  *      Set the current advertisement for auto-negotiation.
   1501  * Parameters:
   1502  *      unit - StrataSwitch unit #.
   1503  *      port - StrataSwitch port #.
   1504  *      mode - Port mode mask indicating supported options/speeds.
   1505  * Returns:
   1506  *      SOC_E_XXX
   1507  * Notes:
   1508  *      The advertisement is set only for the ACTIVE medium.
   1509  *      No synchronization performed at this level.
   1510  */
   1511 
   1512 STATIC int
   1513 phy_5482_adv_local_set(int unit, soc_port_t port, soc_port_mode_t mode)
   1514 {
   1515     int                  rv;
   1516     phy_ctrl_t    *pc;
   1517 
   1518     pc = EXT_PHY_SW_STATE(unit, port);
   1519     rv = SOC_E_NONE;
   1520     if (PHY_COPPER_MODE(unit, port)) {
   1521         rv = phy_ge_adv_local_set(unit, port, mode);
   1522         if (SOC_SUCCESS(rv)) {
   1523             pc->copper.autoneg_advert = mode & ADVERT_ALL_COPPER;
   1524         }
   1525     } else { 
   1526         uint16  mii_adv;
   1527     
   1528         mii_adv = MII_ANA_C37_FD;  /* Always advertise 1000X full duplex */
   1529         switch (mode & SOC_PM_PAUSE) {
   1530         case SOC_PM_PAUSE:
   1531             mii_adv |= MII_ANA_C37_PAUSE;
   1532             break;
   1533         case SOC_PM_PAUSE_TX:
   1534             mii_adv |= MII_ANA_C37_ASYM_PAUSE;
   1535             break;
   1536         case SOC_PM_PAUSE_RX:
   1537             mii_adv |= (MII_ANA_C37_ASYM_PAUSE | MII_ANA_C37_PAUSE);
   1538             break;
   1539         }
   1540         /* Write to Secondary SerDes Auto-Neg Advertisement Reg */
   1541         rv = WRITE_PHY5482_2ND_SERDES_ANAr(unit, pc, mii_adv);
   1542         if (SOC_SUCCESS(rv)) {
   1543             pc->fiber.autoneg_advert = mode & ADVERT_ALL_FIBER;
   1544         }
   1545     }
   1546     LOG_INFO(BSL_LS_SOC_PHY,
   1547              (BSL_META_U(unit,
   1548                          "phy_5482_adv_local_set: u=%d p=%d mode=0x%x, rv=%d\n"),
   1549               unit, port, mode, rv));
   1550     return rv;
   1551 }
   1552 
   1553 /*
   1554  * Function:
   1555  *      phy_5482_adv_local_get
   1556  * Purpose:
   1557  *      Get the current advertisement for auto-negotiation.
   1558  * Parameters:
   1559  *      unit - StrataSwitch unit #.
   1560  *      port - StrataSwitch port #.
   1561  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1562  * Returns:
   1563  *      SOC_E_XXX
   1564  * Notes:
   1565  *      The advertisement is retrieved for the ACTIVE medium.
   1566  *      No synchronization performed at this level.
   1567  */
   1568 
   1569 STATIC int
   1570 phy_5482_adv_local_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1571 {
   1572     uint16         mii_adv;
   1573     phy_ctrl_t    *pc;
   1574 
   1575     pc = EXT_PHY_SW_STATE(unit, port);
   1576 
   1577     if (PHY_COPPER_MODE(unit, port)) {
   1578         return phy_ge_adv_local_get(unit, port, mode);
   1579     } else {    /* PHY_FIBER_MODE */
   1580         /* read the 1000BASE-X Auto-Neg Advertisement Reg ( Address 0x04 ) */
   1581         SOC_IF_ERROR_RETURN
   1582             (READ_PHY5482_2ND_SERDES_ANAr(unit, pc, &mii_adv));
   1583 
   1584         *mode = 0;
   1585         *mode |= (mii_adv & MII_ANA_C37_FD) ? SOC_PM_1000MB_FD : 0;
   1586         *mode |= (mii_adv & MII_ANA_C37_HD) ? SOC_PM_1000MB_HD : 0;
   1587         switch (mii_adv & (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE)) {
   1588         case MII_ANA_C37_PAUSE:
   1589             *mode |= SOC_PM_PAUSE;
   1590             break;
   1591         case MII_ANA_C37_ASYM_PAUSE:
   1592             *mode |= SOC_PM_PAUSE_TX;
   1593             break;
   1594         case (MII_ANA_C37_PAUSE | MII_ANA_C37_ASYM_PAUSE):
   1595             *mode |= SOC_PM_PAUSE_RX;
   1596             break;
   1597         }
   1598     }
   1599     return SOC_E_NONE;
   1600 }
   1601 
   1602 /*
   1603  * Function:
   1604  *      phy_5482_adv_remote_get
   1605  * Purpose:
   1606  *      Get partners current advertisement for auto-negotiation.
   1607  * Parameters:
   1608  *      unit - StrataSwitch unit #.
   1609  *      port - StrataSwitch port #.
   1610  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1611  * Returns:
   1612  *      SOC_E_XXX
   1613  * Notes:
   1614  *      The remote advertisement is retrieved for the ACTIVE medium.
   1615  *      No synchronization performed at this level. If Autonegotiation is
   1616  *      disabled or in progress, this routine will return an error.
   1617  */
   1618 
   1619 STATIC int
   1620 phy_5482_adv_remote_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1621 {
   1622     uint16               data;
   1623     phy_ctrl_t    *pc;
   1624 
   1625     pc = EXT_PHY_SW_STATE(unit, port);
   1626     if (PHY_COPPER_MODE(unit, port)) {
   1627         return phy_ge_adv_remote_get(unit, port, mode);
   1628     } else {    /* PHY_FIBER_MODE */
   1629 
   1630         *mode = 0;
   1631         /* read the 1000BASE-X     Control Reg ( Address 0x00 ),
   1632          *   Auto-Neg Link Partner Ability Reg ( Address 0x05 )
   1633          */
   1634         SOC_IF_ERROR_RETURN
   1635             (READ_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, &data));
   1636         if (!(data & MII_CTRL_AE)) {
   1637             return SOC_E_DISABLED;
   1638         }
   1639 
   1640         SOC_IF_ERROR_RETURN
   1641             (READ_PHY5482_2ND_SERDES_ANPr(unit, pc, &data));
   1642         if (data & MII_ANP_SGMII_MODE) {
   1643             /* Link partner is SGMII master */
   1644             switch(data & MII_ANP_SGMII_SS_MASK) {
   1645             case MII_ANP_SGMII_SS_10:
   1646                 *mode = SOC_PM_10MB;
   1647                 break;
   1648             case MII_ANP_SGMII_SS_100:
   1649                 *mode = SOC_PM_100MB;
   1650                 break;
   1651             case MII_ANP_SGMII_SS_1000:
   1652                 *mode = SOC_PM_1000MB;
   1653                 break;
   1654             }
   1655 
   1656             *mode &= (data & MII_ANP_SGMII_FD) ? SOC_PM_FD : SOC_PM_HD;
   1657         } else {
   1658             *mode |= (data & MII_ANP_C37_FD) ? SOC_PM_1000MB_FD : 0;
   1659             *mode |= (data & MII_ANP_C37_HD) ? SOC_PM_1000MB_HD : 0;
   1660             switch (data & (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE)) {
   1661             case MII_ANP_C37_PAUSE:
   1662                 *mode |= SOC_PM_PAUSE;
   1663                 break;
   1664             case MII_ANP_C37_ASYM_PAUSE:
   1665                 *mode |= SOC_PM_PAUSE_TX;
   1666                 break;
   1667             case (MII_ANP_C37_PAUSE | MII_ANP_C37_ASYM_PAUSE):
   1668                 *mode |= SOC_PM_PAUSE_RX;
   1669                 break;
   1670             }
   1671         }
   1672     }
   1673     return SOC_E_NONE;
   1674 }
   1675 
   1676 /*
   1677  * Function:
   1678  *      phy_5482_lb_set
   1679  * Purpose:
   1680  *      Set the local PHY loopback mode.
   1681  * Parameters:
   1682  *      unit - StrataSwitch unit #.
   1683  *      port - StrataSwitch port #.
   1684  *      loopback - Boolean: true = enable loopback, false = disable.
   1685  * Returns:
   1686  *      SOC_E_XXX
   1687  * Notes:
   1688  *      The loopback mode is set only for the ACTIVE medium.
   1689  *      No synchronization performed at this level.
   1690  */
   1691 
   1692 STATIC int
   1693 phy_5482_lb_set(int unit, soc_port_t port, int enable)
   1694 {
   1695     int            rv;
   1696     uint16         data;
   1697     phy_ctrl_t    *pc;
   1698 
   1699     pc = EXT_PHY_SW_STATE(unit, port);
   1700     rv = SOC_E_NONE;
   1701 
   1702 #if AUTO_MDIX_WHEN_AN_DIS
   1703     {
   1704         /* Disable Auto-MDIX When autoneg disabled */
   1705         /* Enable Auto-MDIX When autoneg disabled */
   1706         data = (enable) ? 0x0000 : 0x0200;
   1707         SOC_IF_ERROR_RETURN
   1708             (MODIFY_PHY_5482_MII_MISC_CTRLr(unit, pc, data, 0x0200)); 
   1709     }
   1710 #endif
   1711 
   1712     if (PHY_COPPER_MODE(unit, port)) {
   1713         rv = phy_fe_ge_lb_set(unit, port, enable);
   1714     } else { 
   1715         data = (enable) ? MII_CTRL_LE : 0;
   1716         rv   = MODIFY_PHY5482_2ND_SERDES_1000X_CTRLr
   1717                   (unit, pc, data, MII_CTRL_LE);
   1718         if (enable && SOC_SUCCESS(rv)) {
   1719             uint16        stat;
   1720             int           link;
   1721             soc_timeout_t to;
   1722 
   1723             /* Wait up to 5000 msec for link up */
   1724             soc_timeout_init(&to, 5000000, 0);
   1725             link = 0;
   1726             while (!soc_timeout_check(&to)) {
   1727                 rv = READ_PHY5482_2ND_SERDES_1000X_STATr(unit, pc, &stat);
   1728                 link = stat & MII_STAT_LA;
   1729                 if (link || SOC_FAILURE(rv)) {
   1730                     break;
   1731                 }
   1732             }
   1733             if (!link) {
   1734                 LOG_WARN(BSL_LS_SOC_PHY,
   1735                          (BSL_META_U(unit,
   1736                                      "phy_5482_lb_set: u=%d p=%d TIMEOUT\n"),
   1737                           unit, port));
   1738 
   1739                 rv = SOC_E_TIMEOUT;
   1740             }
   1741         }
   1742     }
   1743     LOG_INFO(BSL_LS_SOC_PHY,
   1744              (BSL_META_U(unit,
   1745                          "phy_5482_lb_set: u=%d p=%d en=%d rv=%d\n"), 
   1746               unit, port, enable, rv));
   1747 
   1748     return rv; 
   1749 }
   1750 
   1751 /*
   1752  * Function:
   1753  *      phy_5482_lb_get
   1754  * Purpose:
   1755  *      Get the local PHY loopback mode.
   1756  * Parameters:
   1757  *      unit - StrataSwitch unit #.
   1758  *      port - StrataSwitch port #.
   1759  *      loopback - (OUT) Boolean: true = enable loopback, false = disable.
   1760  * Returns:
   1761  *      SOC_E_XXX
   1762  * Notes:
   1763  *      The loopback mode is retrieved for the ACTIVE medium.
   1764  */
   1765 
   1766 STATIC int
   1767 phy_5482_lb_get(int unit, soc_port_t port, int *enable)
   1768 {
   1769     uint16               data;
   1770     phy_ctrl_t    *pc;
   1771 
   1772     pc = EXT_PHY_SW_STATE(unit, port);
   1773 
   1774     if (PHY_COPPER_MODE(unit, port)) {
   1775         SOC_IF_ERROR_RETURN
   1776             (phy_fe_ge_lb_get(unit, port, enable));
   1777     } else {
   1778        SOC_IF_ERROR_RETURN
   1779            (READ_PHY5482_2ND_SERDES_1000X_CTRLr(unit, pc, &data));
   1780         *enable = (data & MII_CTRL_LE) ? 1 : 0;
   1781     }
   1782 
   1783     return SOC_E_NONE; 
   1784 }
   1785 
   1786 /*
   1787  * Function:
   1788  *      phy_5482_interface_set
   1789  * Purpose:
   1790  *      Set the current operating mode of the PHY.
   1791  * Parameters:
   1792  *      unit - StrataSwitch unit #.
   1793  *      port - StrataSwitch port #.
   1794  *      pif - one of SOC_PORT_IF_*
   1795  * Returns:
   1796  *      SOC_E_NONE - success
   1797  *      SOC_E_UNAVAIL - unsupported interface
   1798  */
   1799 
   1800 STATIC int
   1801 phy_5482_interface_set(int unit, soc_port_t port, soc_port_if_t pif)
   1802 {
   1803     COMPILER_REFERENCE(unit);
   1804     COMPILER_REFERENCE(port);
   1805 
   1806     switch (pif) {
   1807     case SOC_PORT_IF_SGMII:
   1808     case SOC_PORT_IF_GMII: 
   1809         return SOC_E_NONE;
   1810     default:
   1811         return SOC_E_UNAVAIL;
   1812     }
   1813 }
   1814 
   1815 /*
   1816  * Function:
   1817  *      phy_5482_interface_get
   1818  * Purpose:
   1819  *      Get the current operating mode of the PHY.
   1820  * Parameters:
   1821  *      unit - StrataSwitch unit #.
   1822  *      port - StrataSwitch port #.
   1823  *      pif - (OUT) one of SOC_PORT_IF_*
   1824  * Returns:
   1825  *      SOC_E_NONE
   1826  */
   1827 
   1828 STATIC int
   1829 phy_5482_interface_get(int unit, soc_port_t port, soc_port_if_t *pif)
   1830 {
   1831     COMPILER_REFERENCE(unit);
   1832     COMPILER_REFERENCE(port);
   1833 
   1834     *pif = SOC_PORT_IF_SGMII;
   1835 
   1836     return SOC_E_NONE;
   1837 }
   1838 
   1839 /*
   1840  * Function:
   1841  *      phy_5482_ability_get
   1842  * Purpose:
   1843  *      Get the abilities of the local gigabit PHY.
   1844  * Parameters:
   1845  *      unit - StrataSwitch unit #.
   1846  *      port - StrataSwitch port #.
   1847  *      mode - (OUT) Port mode mask indicating supported options/speeds.
   1848  * Returns:
   1849  *      SOC_E_NONE
   1850  * Notes:
   1851  *      The ability is retrieved only for the ACTIVE medium.
   1852  */
   1853 
   1854 STATIC int
   1855 phy_5482_ability_get(int unit, soc_port_t port, soc_port_mode_t *mode)
   1856 {
   1857     int         rv;
   1858     phy_ctrl_t *pc;
   1859 
   1860     rv = SOC_E_NONE;
   1861     if (PHY_COPPER_MODE(unit, port)) {
   1862         rv = phy_ge_ability_get(unit, port, mode);
   1863     } else { /* fiber mode */
   1864         *mode = (SOC_PM_AN | SOC_PM_LB_PHY | 
   1865                  SOC_PM_PAUSE | SOC_PM_PAUSE_ASYMM |
   1866                  SOC_PM_GMII | SOC_PM_SGMII | SOC_PM_1000MB_FD |
   1867                  SOC_PM_100MB_FD | SOC_PM_100MB_HD);
   1868     }
   1869 
   1870     pc = EXT_PHY_SW_STATE(unit, port);
   1871     if (pc->automedium) {
   1872         *mode |= SOC_PM_COMBO;
   1873     }
   1874 
   1875     return rv;
   1876 }
   1877 
   1878 /*
   1879  * Function:
   1880  *      phy_5482_mdix_set
   1881  * Description:
   1882  *      Set the Auto-MDIX mode of a port/PHY
   1883  * Parameters:
   1884  *      unit - Device number
   1885  *      port - Port number
   1886  *      mode - One of:
   1887  *              SOC_PORT_MDIX_AUTO
   1888  *                      Enable auto-MDIX when autonegotiation is enabled
   1889  *              SOC_PORT_MDIX_FORCE_AUTO
   1890  *                      Enable auto-MDIX always
   1891  *              SOC_PORT_MDIX_NORMAL
   1892  *                      Disable auto-MDIX
   1893  *              SOC_PORT_MDIX_XOVER
   1894  *                      Disable auto-MDIX, and swap cable pairs
   1895  * Return Value:
   1896  *      SOC_E_XXX
   1897  */
   1898 STATIC int
   1899 phy_5482_mdix_set(int unit, soc_port_t port, soc_port_mdix_t mode)
   1900 {
   1901     phy_ctrl_t    *pc;
   1902     int                  speed;
   1903 
   1904     pc = EXT_PHY_SW_STATE(unit, port);
   1905     if (PHY_COPPER_MODE(unit, port)) {
   1906         switch (mode) {
   1907         case SOC_PORT_MDIX_AUTO:
   1908             /* Clear bit 14 for automatic MDI crossover */
   1909             SOC_IF_ERROR_RETURN
   1910                 (MODIFY_PHY5482_MII_ECRr(unit, pc, 0, 0x4000));
   1911 
   1912             /* Clear bit 9 to disable forced auto MDI xover */
   1913             SOC_IF_ERROR_RETURN
   1914                 (MODIFY_PHY5482_MII_MISC_CTRLr(unit, pc, 0, 0x0200));
   1915             break;
   1916 
   1917         case SOC_PORT_MDIX_FORCE_AUTO:
   1918             /* Clear bit 14 for automatic MDI crossover */
   1919             SOC_IF_ERROR_RETURN
   1920                 (MODIFY_PHY5482_MII_ECRr(unit, pc, 0, 0x4000));
   1921 
   1922             /* Set bit 9 to disable forced auto MDI xover */
   1923             SOC_IF_ERROR_RETURN
   1924                 (MODIFY_PHY5482_MII_MISC_CTRLr(unit, pc, 0x0200, 0x0200));
   1925             break;
   1926 
   1927         case SOC_PORT_MDIX_NORMAL:
   1928             SOC_IF_ERROR_RETURN(phy_5482_speed_get(unit, port, &speed));
   1929             if (speed == 0 || speed == 10 || speed == 100) {
   1930                 /* Set bit 14 for automatic MDI crossover */
   1931                 SOC_IF_ERROR_RETURN
   1932                     (MODIFY_PHY5482_MII_ECRr(unit, pc, 0x4000, 0x4000));
   1933 
   1934                 SOC_IF_ERROR_RETURN
   1935                     (WRITE_PHY5482_TEST1r(unit, pc, 0));
   1936             } else {
   1937                 return SOC_E_UNAVAIL;
   1938             }
   1939             break;
   1940 
   1941         case SOC_PORT_MDIX_XOVER:
   1942             SOC_IF_ERROR_RETURN(phy_5482_speed_get(unit, port, &speed));
   1943             if (speed == 0 || speed == 10 || speed == 100) {
   1944                 /* Set bit 14 for automatic MDI crossover */
   1945                 SOC_IF_ERROR_RETURN
   1946                     (MODIFY_PHY5482_MII_ECRr(unit, pc, 0x4000, 0x4000));
   1947 
   1948                 SOC_IF_ERROR_RETURN
   1949                     (WRITE_PHY5482_TEST1r(unit, pc, 0x0080));
   1950             } else {
   1951                 return SOC_E_UNAVAIL;
   1952             }
   1953             break;
   1954 
   1955         default:
   1956             return SOC_E_PARAM;
   1957         }
   1958         pc->copper.mdix = mode;
   1959     } else {    /* fiber */
   1960         if (mode != SOC_PORT_MDIX_NORMAL) {
   1961             return SOC_E_UNAVAIL;
   1962         }
   1963     }
   1964     return SOC_E_NONE;
   1965 }        
   1966 
   1967 /*
   1968  * Function:
   1969  *      phy_5482_mdix_get
   1970  * Description:
   1971  *      Get the Auto-MDIX mode of a port/PHY
   1972  * Parameters:
   1973  *      unit - Device number
   1974  *      port - Port number
   1975  *      mode - (Out) One of:
   1976  *              SOC_PORT_MDIX_AUTO
   1977  *                      Enable auto-MDIX when autonegotiation is enabled
   1978  *              SOC_PORT_MDIX_FORCE_AUTO
   1979  *                      Enable auto-MDIX always
   1980  *              SOC_PORT_MDIX_NORMAL
   1981  *                      Disable auto-MDIX
   1982  *              SOC_PORT_MDIX_XOVER
   1983  *                      Disable auto-MDIX, and swap cable pairs
   1984  * Return Value:
   1985  *      SOC_E_XXX
   1986  */
   1987 STATIC int
   1988 phy_5482_mdix_get(int unit, soc_port_t port, soc_port_mdix_t *mode)
   1989 {
   1990     phy_ctrl_t    *pc;
   1991     int            speed;
   1992 
   1993     if (mode == NULL) {
   1994         return SOC_E_PARAM;
   1995     }
   1996 
   1997     pc = EXT_PHY_SW_STATE(unit, port);
   1998 
   1999     if (PHY_COPPER_MODE(unit, port)) {
   2000         SOC_IF_ERROR_RETURN(phy_5482_speed_get(unit, port, &speed));
   2001         if (speed == 1000) {
   2002            *mode = SOC_PORT_MDIX_AUTO;
   2003         } else {
   2004             *mode = pc->copper.mdix;
   2005         }
   2006     } else {
   2007         *mode = SOC_PORT_MDIX_NORMAL;
   2008     }
   2009 
   2010     return SOC_E_NONE;
   2011 }    
   2012 
   2013 /*
   2014  * Function:
   2015  *      phy_5482_mdix_status_get
   2016  * Description:
   2017  *      Get the current MDIX status on a port/PHY
   2018  * Parameters:
   2019  *      unit    - Device number
   2020  *      port    - Port number
   2021  *      status  - (OUT) One of:
   2022  *              SOC_PORT_MDIX_STATUS_NORMAL
   2023  *                      Straight connection
   2024  *              SOC_PORT_MDIX_STATUS_XOVER
   2025  *                      Crossover has been performed
   2026  * Return Value:
   2027  *      SOC_E_XXX
   2028  */
   2029 STATIC int
   2030 phy_5482_mdix_status_get(int unit, soc_port_t port, 
   2031                          soc_port_mdix_status_t *status)
   2032 {
   2033     phy_ctrl_t    *pc;
   2034     uint16          data;
   2035 
   2036     if (status == NULL) {
   2037         return SOC_E_PARAM;
   2038     }
   2039 
   2040     pc = EXT_PHY_SW_STATE(unit, port);
   2041 
   2042     if (PHY_COPPER_MODE(unit, port)) {
   2043         SOC_IF_ERROR_RETURN
   2044             (READ_PHY5482_MII_ESRr(unit, pc, &data));
   2045         if (data & 0x2000) {
   2046             *status = SOC_PORT_MDIX_STATUS_XOVER;
   2047         } else {
   2048             *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2049         }
   2050     } else {
   2051         *status = SOC_PORT_MDIX_STATUS_NORMAL;
   2052     }
   2053 
   2054     return SOC_E_NONE;
   2055 }    
   2056 
   2057 
   2058 STATIC int
   2059 phy_5482_control_linkdown_transmit_set(int unit, soc_port_t port, 
   2060                                        uint32 value)
   2061 {
   2062     phy_ctrl_t  *pc;
   2063     int         speed;             
   2064     uint16      data;
   2065     int         rv = SOC_E_NONE;
   2066 
   2067     if (PHY_COPPER_MODE(unit, port)) {
   2068         return SOC_E_UNAVAIL;
   2069     }
   2070 
   2071     SOC_IF_ERROR_RETURN
   2072         (phy_5482_speed_get(unit, port, &speed));
   2073 
   2074     pc = EXT_PHY_SW_STATE(unit, port);
   2075 
   2076     switch (speed) {
   2077     case 10:
   2078         rv = SOC_E_UNAVAIL;
   2079         break;
   2080     case 100:
   2081         /* 100FX Unidirectional */
   2082         SOC_IF_ERROR_RETURN
   2083             (READ_PHY5482_2ND_SERDES_100FX_TESTr(unit, pc, &data));
   2084         if (value) {
   2085             data |= 0x00c0;
   2086         } else {
   2087             data &= ~0x00c0;
   2088         }
   2089         SOC_IF_ERROR_RETURN
   2090             (WRITE_PHY5482_2ND_SERDES_100FX_TESTr(unit, pc, data));
   2091             /* Supress incoming data */
   2092 
   2093         SOC_IF_ERROR_RETURN
   2094             (READ_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, &data));
   2095         if (value) {
   2096             data |= 0x0001;
   2097         } else {
   2098             data &= ~0x0001;
   2099         }
   2100         SOC_IF_ERROR_RETURN
   2101             (WRITE_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, data));
   2102         break;
   2103         
   2104     case 1000:
   2105         /* 1000-X Force XMIT */
   2106         SOC_IF_ERROR_RETURN
   2107             (READ_PHY5482_2ND_SERDES_MISC_CTRL2r(unit, pc, &data));
   2108         if (value) {
   2109             data |= 0x0008;
   2110         } else {
   2111             data &= ~0x0008;
   2112         }
   2113         SOC_IF_ERROR_RETURN
   2114             (WRITE_PHY5482_2ND_SERDES_MISC_CTRL2r(unit, pc, data));
   2115         
   2116         SOC_IF_ERROR_RETURN
   2117             (READ_PHY5482_MISC_1000X_CTRL2r(unit, pc, &data));
   2118         if (value) {
   2119             data |= 0x0008;
   2120         } else {
   2121             data &= ~0x0008;
   2122         }
   2123         SOC_IF_ERROR_RETURN
   2124             (WRITE_PHY5482_MISC_1000X_CTRL2r(unit, pc, data));
   2125         
   2126         /* Supress incoming data */
   2127         SOC_IF_ERROR_RETURN
   2128             (READ_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, &data));
   2129         if (value) {
   2130             data |= 0x0001;
   2131         } else {
   2132             data &= ~0x0001;
   2133         }
   2134         SOC_IF_ERROR_RETURN
   2135             (WRITE_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, data));
   2136         break;
   2137         
   2138     default:
   2139         rv = SOC_E_UNAVAIL;
   2140     }
   2141 
   2142     return rv;
   2143 }
   2144 
   2145 
   2146 STATIC int
   2147 phy_5482_control_linkdown_transmit_get(int unit, soc_port_t port, 
   2148                                        uint32 *value)
   2149 {
   2150     phy_ctrl_t  *pc;
   2151     int         speed;             
   2152     uint16      data;
   2153     int         rv = SOC_E_NONE;
   2154 
   2155     if (PHY_COPPER_MODE(unit, port)) {
   2156         return SOC_E_UNAVAIL;
   2157     }
   2158 
   2159     SOC_IF_ERROR_RETURN
   2160         (phy_5482_speed_get(unit, port, &speed));
   2161 
   2162     pc = EXT_PHY_SW_STATE(unit, port);
   2163 
   2164     switch (speed) {
   2165     case 10:
   2166         rv = SOC_E_UNAVAIL;
   2167         break;
   2168     case 100:
   2169         /* Check 100FX Unidirectional */
   2170         SOC_IF_ERROR_RETURN
   2171             (READ_PHY5482_2ND_SERDES_100FX_TESTr(unit, pc, &data));
   2172         *value = (data & 0x00c0) ? 1 : 0;
   2173         break;
   2174 
   2175     case 1000:
   2176         /* Check 1000-X Force XMIT */
   2177         SOC_IF_ERROR_RETURN
   2178             (READ_PHY5482_2ND_SERDES_MISC_CTRL2r(unit, pc, &data));
   2179         *value = (data & 0x0008) ? 1 : 0;
   2180         break;
   2181 
   2182     default:
   2183         rv = SOC_E_UNAVAIL;
   2184     }
   2185 
   2186     return rv;
   2187 }
   2188 
   2189 STATIC int
   2190 _phy_5482_power_mode_set (int unit, soc_port_t port, int mode)
   2191 {
   2192     phy_ctrl_t    *pc;
   2193     int rv;
   2194     pc       = EXT_PHY_SW_STATE(unit, port);
   2195 
   2196     rv = SOC_E_NONE;
   2197     if (pc->power_mode == mode) {
   2198         return SOC_E_NONE;
   2199     }
   2200 
   2201     if (mode == SOC_PHY_CONTROL_POWER_FULL) {
   2202         /* disable the auto power mode */
   2203         SOC_IF_ERROR_RETURN
   2204             (MODIFY_PHY5482_AUTO_POWER_DOWNr(unit,pc,
   2205                         0,
   2206                         PHY_5482_AUTO_PWRDWN_EN));
   2207         pc->power_mode = mode;
   2208     } else if (mode == SOC_PHY_CONTROL_POWER_AUTO) {
   2209         SOC_IF_ERROR_RETURN
   2210             (MODIFY_PHY5482_AUTO_POWER_DOWNr(unit,pc,
   2211                         PHY_5482_AUTO_PWRDWN_EN,
   2212                         PHY_5482_AUTO_PWRDWN_EN));
   2213         pc->power_mode = mode;
   2214     } else {
   2215         rv = SOC_E_UNAVAIL;
   2216     }
   2217     return rv;
   2218 }
   2219 
   2220 
   2221 
   2222 /*
   2223  * Function:
   2224  *      phy_5482_control_set
   2225  * Purpose:
   2226  *      Configure PHY device specific control fucntion.
   2227  * Parameters:
   2228  *      unit  - StrataSwitch unit #.
   2229  *      port  - StrataSwitch port #.
   2230  *      type  - Control to update
   2231  *      value - New setting for the control
   2232  * Returns:
   2233  *      SOC_E_NONE
   2234  */
   2235 STATIC int
   2236 phy_5482_control_set(int unit, soc_port_t port,
   2237                      soc_phy_control_t type, uint32 value)
   2238 {
   2239     int rv;
   2240     phy_ctrl_t *pc;
   2241     uint16 data16;
   2242 
   2243     PHY_CONTROL_TYPE_CHECK(type);
   2244 
   2245     pc = EXT_PHY_SW_STATE(unit, port);
   2246     rv = SOC_E_NONE;
   2247 
   2248     switch(type) {
   2249     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   2250         if (pc->phy_rev == 0xB) {
   2251             SOC_IF_ERROR_RETURN
   2252                 (WRITE_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, value ? (1U<<4) : 0));
   2253         }
   2254         break;
   2255 
   2256     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   2257         rv = phy_5482_control_linkdown_transmit_set(unit, port, value);
   2258         break;
   2259 
   2260     case SOC_PHY_CONTROL_POWER:
   2261         rv = _phy_5482_power_mode_set(unit,port,value);
   2262         break;
   2263 
   2264     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   2265         if (value <= PHY_5482_AUTO_PWRDWN_WAKEUP_MAX) {
   2266 
   2267             /* at least one unit */
   2268             if (value < PHY_5482_AUTO_PWRDWN_WAKEUP_UNIT) {
   2269                 value = PHY_5482_AUTO_PWRDWN_WAKEUP_UNIT;
   2270             }
   2271         } else { /* anything more then max, set to the max */
   2272             value = PHY_5482_AUTO_PWRDWN_WAKEUP_MAX;
   2273         }
   2274         SOC_IF_ERROR_RETURN
   2275             (MODIFY_PHY5482_AUTO_POWER_DOWNr(unit,pc,
   2276                       value/PHY_5482_AUTO_PWRDWN_WAKEUP_UNIT,
   2277                       PHY_5482_AUTO_PWRDWN_WAKEUP_MASK));
   2278         break;
   2279 
   2280     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   2281         /* sleep time configuration is either 2.7s or 5.4 s, default is 2.7s */
   2282         if (value < PHY_5482_AUTO_PWRDWN_SLEEP_MAX) {
   2283             data16 = 0; /* anything less than 5.4s, default to 2.7s */
   2284         } else {
   2285             data16 = PHY_5482_AUTO_PWRDWN_SLEEP_MASK;
   2286         }
   2287         SOC_IF_ERROR_RETURN
   2288             (MODIFY_PHY5482_AUTO_POWER_DOWNr(unit,pc,
   2289                       data16,
   2290                       PHY_5482_AUTO_PWRDWN_SLEEP_MASK));
   2291         break;
   2292 
   2293 
   2294     default:
   2295         rv = SOC_E_UNAVAIL;
   2296         break;
   2297     }
   2298     return rv;
   2299 }
   2300 
   2301 /*
   2302  * Function:
   2303  *      phy_5482_control_get
   2304  * Purpose:
   2305  *      Get current control settign of the PHY.
   2306  * Parameters:
   2307  *      unit  - StrataSwitch unit #.
   2308  *      port  - StrataSwitch port #.
   2309  *      type  - Control to update
   2310  *      value - (OUT)Current setting for the control
   2311  * Returns:
   2312  *      SOC_E_NONE
   2313  */
   2314 STATIC int
   2315 phy_5482_control_get(int unit, soc_port_t port,
   2316                      soc_phy_control_t type, uint32 *value)
   2317 {
   2318     int rv;
   2319     phy_ctrl_t *pc;
   2320     uint16 data;
   2321 
   2322     PHY_CONTROL_TYPE_CHECK(type);
   2323 
   2324     pc = EXT_PHY_SW_STATE(unit, port);
   2325     rv = SOC_E_NONE;
   2326 
   2327     switch(type) {
   2328     case SOC_PHY_CONTROL_CLOCK_ENABLE:
   2329         if (pc->phy_rev == 0xB) {
   2330             SOC_IF_ERROR_RETURN
   2331                 (READ_PHY5482_EXP_SGMII_REC_CTRLr(unit, pc, &data));
   2332             *value = (data & (1U << 4)) ? TRUE : FALSE;
   2333         }
   2334         break;
   2335 
   2336     case SOC_PHY_CONTROL_LINKDOWN_TRANSMIT:
   2337         rv = phy_5482_control_linkdown_transmit_get(unit, port, value);
   2338         break;
   2339 
   2340     case SOC_PHY_CONTROL_POWER:
   2341         *value = pc->power_mode;
   2342         break;
   2343 
   2344     case SOC_PHY_CONTROL_POWER_AUTO_SLEEP_TIME:
   2345         SOC_IF_ERROR_RETURN
   2346             (READ_PHY5482_AUTO_POWER_DOWNr(unit,pc, &data));
   2347 
   2348         if (data & PHY_5482_AUTO_PWRDWN_SLEEP_MASK) {
   2349             *value = PHY_5482_AUTO_PWRDWN_SLEEP_MAX;
   2350         } else {
   2351             *value = 2700;
   2352         }
   2353         break;
   2354 
   2355     case SOC_PHY_CONTROL_POWER_AUTO_WAKE_TIME:
   2356         SOC_IF_ERROR_RETURN
   2357             (READ_PHY5482_AUTO_POWER_DOWNr(unit,pc, &data));
   2358 
   2359         data &= PHY_5482_AUTO_PWRDWN_WAKEUP_MASK;
   2360         *value = data * PHY_5482_AUTO_PWRDWN_WAKEUP_UNIT;
   2361         break;
   2362         
   2363     default:
   2364         rv = SOC_E_UNAVAIL;
   2365         break;
   2366     }
   2367     return rv;
   2368 }
   2369 
   2370 /*
   2371  * Function:
   2372  *      phy_5482_cable_diag
   2373  * Purpose:
   2374  *      Run 546x cable diagnostics
   2375  * Parameters:
   2376  *      unit - device number
   2377  *      port - port number
   2378  *      status - (OUT) cable diagnotic status structure
   2379  * Returns:     
   2380  *      SOC_E_XXX
   2381  */
   2382 STATIC int
   2383 phy_5482_cable_diag(int unit, soc_port_t port,
   2384                     soc_port_cable_diag_t *status)
   2385 {
   2386     int                 rv, rv2, i;
   2387 
   2388     extern int phy_5464_cable_diag_sw(int, soc_port_t , 
   2389                                       soc_port_cable_diag_t *);
   2390 
   2391     if (status == NULL) {
   2392         return SOC_E_PARAM;
   2393     }
   2394 
   2395     status->state = SOC_PORT_CABLE_STATE_OK;
   2396     status->npairs = 4;
   2397     status->fuzz_len = 0;
   2398     for (i = 0; i < 4; i++) {
   2399         status->pair_state[i] = SOC_PORT_CABLE_STATE_OK;
   2400     }
   2401 
   2402     MIIM_LOCK(unit);    /* this locks out linkscan, essentially */
   2403     rv = phy_5464_cable_diag_sw(unit,port, status);
   2404     MIIM_UNLOCK(unit);
   2405     rv2 = 0;
   2406     if (rv <= 0) {      /* don't reset if > 0 -- link was up */
   2407         rv2 = _phy_5482_reset_setup(unit, port);
   2408     }
   2409     if (rv >= 0 && rv2 < 0) {
   2410         return rv2;
   2411     }
   2412     return rv;
   2413 }
   2414 
   2415 #ifdef BROADCOM_DEBUG
   2416 
   2417 /*
   2418  * Function:
   2419  *      phy_5482_shadow_dump
   2420  * Purpose:
   2421  *      Debug routine to dump all shadow registers.
   2422  * Parameters:
   2423  *      unit - StrataSwitch unit #.
   2424  *      port - StrataSwitch port #.
   2425  */
   2426 
   2427 void
   2428 phy_5482_shadow_dump(int unit, soc_port_t port)
   2429 {
   2430     phy_ctrl_t *pc;
   2431     uint16      tmp;
   2432     int         i;
   2433 
   2434     pc       = EXT_PHY_SW_STATE(unit, port);
   2435 
   2436     /* Register 0x18 Shadows */
   2437     for (i = 0; i <= 7; i++) {
   2438         WRITE_PHY_REG(unit, pc, 0x18, (i << 12) | 0x7);
   2439         READ_PHY_REG(unit, pc, 0x18, &tmp);
   2440         if ((tmp & ~7) == 0x0000) {
   2441             continue;
   2442         }
   2443         LOG_CLI((BSL_META_U(unit,
   2444                             "0x18[0x%x]=0x%04x\n"), i, tmp));
   2445     }
   2446 
   2447     /* Register 0x1c Shadows */
   2448     for (i = 0; i <= 0x1f; i++) {
   2449         WRITE_PHY_REG(unit, pc, 0x1c, i << 10);
   2450         READ_PHY_REG(unit, pc, 0x1c, &tmp);
   2451         if ((tmp & ~0x7c00) == 0x0000) {
   2452             continue;
   2453         }
   2454         LOG_CLI((BSL_META_U(unit,
   2455                             "0x1c[0x%x]=0x%04x\n"), i, tmp));
   2456     }
   2457 
   2458     /* Register 0x17/0x15 Shadows */
   2459     for (i = 0; i <= 0x13; i++) {
   2460         WRITE_PHY_REG(unit, pc, 0x17, 0xf00 | i);
   2461         READ_PHY_REG(unit, pc, 0x15, &tmp);
   2462         if (tmp  == 0x0000) {
   2463             continue;
   2464         }
   2465         LOG_CLI((BSL_META_U(unit,
   2466                             "0x17[0x%x]=0x%04x\n"), i, tmp));
   2467     }
   2468 }
   2469 
   2470 #endif /* BROADCOM_DEBUG */
   2471 
   2472 /*
   2473  * Variable:    phy_5482drv_ge
   2474  * Purpose:     PHY driver for 5482
   2475  */
   2476 
   2477 phy_driver_t phy_5482drv_ge = {
   2478     "5482/801x Gigabit PHY Driver",
   2479     phy_5482_init,
   2480     phy_fe_ge_reset,
   2481     phy_5482_link_get,
   2482     phy_5482_enable_set,
   2483     phy_5482_enable_get,
   2484     phy_5482_duplex_set,
   2485     phy_5482_duplex_get,
   2486     phy_5482_speed_set,
   2487     phy_5482_speed_get,
   2488     phy_5482_master_set,
   2489     phy_5482_master_get,
   2490     phy_5482_autoneg_set,
   2491     phy_5482_autoneg_get,
   2492     phy_5482_adv_local_set,
   2493     phy_5482_adv_local_get,
   2494     phy_5482_adv_remote_get,
   2495     phy_5482_lb_set,
   2496     phy_5482_lb_get,
   2497     phy_5482_interface_set,
   2498     phy_5482_interface_get,
   2499     phy_5482_ability_get,
   2500     NULL,                        /* Phy link up event */
   2501     NULL,                        /* Phy link down event */
   2502     phy_5482_mdix_set,
   2503     phy_5482_mdix_get,
   2504     phy_5482_mdix_status_get,
   2505     phy_5482_medium_config_set,
   2506     phy_5482_medium_config_get,
   2507     phy_5482_medium_status,
   2508     phy_5482_cable_diag,
   2509     NULL,                       /* phy_link_change */
   2510     phy_5482_control_set,       /* phy_control_set */ 
   2511     phy_5482_control_get,       /* phy_control_get */
   2512     phy_ge_reg_read,
   2513     phy_ge_reg_write,
   2514     phy_ge_reg_modify,
   2515     NULL                        /* Phy event notify */ 
   2516 };
   2517 
   2518 #else /* INCLUDE_PHY_5482_ESW */
   2519 int _soc_phy_5482_not_empty;
   2520 #endif /* INCLUDE_PHY_5482 */
   2521